@kungfu-tech/buildchain 2.8.7-alpha.1 → 2.8.7
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/README.md +29 -1
- package/dist/site/agent-index.json +1 -0
- package/dist/site/artifact-schemas.json +1 -0
- package/dist/site/buildchain-contract.json +4 -4
- package/dist/site/buildchain-site.json +1619 -10
- package/dist/site/kfd-claims.json +326 -50
- package/dist/site/manual-registry.json +49 -10
- package/dist/site/node-api-registry.json +2 -2
- package/dist/site/page-registry.json +1437 -0
- package/dist/site/release-provenance.json +1 -0
- package/dist/site/site-manifest.json +56 -10
- package/dist/site/workflow-registry.json +5 -0
- package/docs/runtime-train-validation.md +123 -0
- package/docs/site-bundle-contract.md +30 -0
- package/docs/web-surface-deployments.md +22 -9
- package/package.json +4 -23
- package/packages/core/buildchain-kfd-claims.js +37 -6
- package/scripts/check-inventory.mjs +114 -5
- package/scripts/generate-site-bundle.mjs +311 -1
- package/scripts/web-surface-production-release-pr.mjs +315 -0
|
@@ -38,6 +38,7 @@ const requiredPaths = [
|
|
|
38
38
|
"scripts/release-candidate-resolver.mjs",
|
|
39
39
|
"scripts/buildchain-patrol.mjs",
|
|
40
40
|
"scripts/workflow-friction-report.mjs",
|
|
41
|
+
"scripts/web-surface-production-release-pr.mjs",
|
|
41
42
|
"docs/migration-inventory.md",
|
|
42
43
|
"docs/lifecycle-protocol.md",
|
|
43
44
|
"docs/ownership.md",
|
|
@@ -79,6 +80,22 @@ if (rootPackage.name !== "@kungfu-tech/buildchain") {
|
|
|
79
80
|
if (rootPackage.private !== false) {
|
|
80
81
|
throw new Error("root package must be publishable with private=false");
|
|
81
82
|
}
|
|
83
|
+
const packageDependencySections = ["dependencies", "optionalDependencies", "peerDependencies"];
|
|
84
|
+
const exoticDependencyPattern =
|
|
85
|
+
/^(?:git(?:\+ssh|\+https|\+http|\+file)?:|github:|gitlab:|bitbucket:|https?:|file:|link:|workspace:)/i;
|
|
86
|
+
for (const sectionName of packageDependencySections) {
|
|
87
|
+
const section = rootPackage[sectionName] || {};
|
|
88
|
+
for (const [dependencyName, specifier] of Object.entries(section)) {
|
|
89
|
+
if (typeof specifier !== "string") {
|
|
90
|
+
throw new Error(`package ${sectionName}.${dependencyName} must use a string version specifier`);
|
|
91
|
+
}
|
|
92
|
+
if (exoticDependencyPattern.test(specifier.trim())) {
|
|
93
|
+
throw new Error(
|
|
94
|
+
`package ${sectionName}.${dependencyName} must use an auditable npm registry version, not exotic specifier: ${specifier}`,
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
82
99
|
if (rootPackage.bin?.buildchain !== "./bin/buildchain.mjs") {
|
|
83
100
|
throw new Error("root package must expose the buildchain CLI");
|
|
84
101
|
}
|
|
@@ -109,6 +126,15 @@ if (rootPackage.exports?.["./release-propagation"] !== "./packages/core/release-
|
|
|
109
126
|
if (rootPackage.exports?.["./buildchain-kfd-claims"] !== "./packages/core/buildchain-kfd-claims.js") {
|
|
110
127
|
throw new Error("root package must export @kungfu-tech/buildchain/buildchain-kfd-claims");
|
|
111
128
|
}
|
|
129
|
+
if (rootPackage.exports?.["./site/buildchain-site.json"] !== "./dist/site/buildchain-site.json") {
|
|
130
|
+
throw new Error("root package must export @kungfu-tech/buildchain/site/buildchain-site.json");
|
|
131
|
+
}
|
|
132
|
+
if (rootPackage.exports?.["./site/site-manifest.json"] !== "./dist/site/site-manifest.json") {
|
|
133
|
+
throw new Error("root package must export @kungfu-tech/buildchain/site/site-manifest.json");
|
|
134
|
+
}
|
|
135
|
+
if (rootPackage.exports?.["./site/page-registry.json"] !== "./dist/site/page-registry.json") {
|
|
136
|
+
throw new Error("root package must export @kungfu-tech/buildchain/site/page-registry.json");
|
|
137
|
+
}
|
|
112
138
|
if (rootPackage.exports?.["./site/manual-registry.json"] !== "./dist/site/manual-registry.json") {
|
|
113
139
|
throw new Error("root package must export @kungfu-tech/buildchain/site/manual-registry.json");
|
|
114
140
|
}
|
|
@@ -124,25 +150,25 @@ if (rootPackage.publishConfig?.access !== "public") {
|
|
|
124
150
|
if (rootPackage.publishConfig?.registry !== "https://registry.npmjs.org/") {
|
|
125
151
|
throw new Error("root package publishConfig.registry must be npmjs");
|
|
126
152
|
}
|
|
127
|
-
for (const expectedFile of ["bin/", "scripts/*.mjs", "packages/core/", "docs
|
|
153
|
+
for (const expectedFile of ["bin/", "scripts/*.mjs", "packages/core/", "docs/*.md"]) {
|
|
128
154
|
if (!rootPackage.files?.includes(expectedFile)) {
|
|
129
155
|
throw new Error(`root package files must include ${expectedFile}`);
|
|
130
156
|
}
|
|
131
157
|
}
|
|
132
|
-
for (const expectedFile of ["dist/site/", "
|
|
158
|
+
for (const expectedFile of ["dist/site/", "actions/*/README.md", "fixtures/*/README.md"]) {
|
|
133
159
|
if (!rootPackage.files?.includes(expectedFile)) {
|
|
134
160
|
throw new Error(`root package files must include ${expectedFile}`);
|
|
135
161
|
}
|
|
136
162
|
}
|
|
137
|
-
if (!rootPackage.files?.includes("docs/release-propagation.md")) {
|
|
138
|
-
throw new Error("root package files must include docs/release-propagation.md");
|
|
139
|
-
}
|
|
140
163
|
const cliSource = fs.readFileSync(path.join(root, "bin/buildchain.mjs"), "utf8");
|
|
141
164
|
const coreIndexSource = fs.readFileSync(path.join(root, "packages/core/index.js"), "utf8");
|
|
142
165
|
const versioningDoc = fs.readFileSync(path.join(root, "docs/versioning.md"), "utf8");
|
|
143
166
|
const cliDoc = fs.readFileSync(path.join(root, "docs/cli.md"), "utf8");
|
|
144
167
|
const docsMap = fs.readFileSync(path.join(root, "docs/MAP.md"), "utf8");
|
|
145
168
|
const installDoc = fs.readFileSync(path.join(root, "docs/install.md"), "utf8");
|
|
169
|
+
const siteBundle = JSON.parse(fs.readFileSync(path.join(root, "dist/site/buildchain-site.json"), "utf8"));
|
|
170
|
+
const siteManifest = JSON.parse(fs.readFileSync(path.join(root, "dist/site/site-manifest.json"), "utf8"));
|
|
171
|
+
const pageRegistry = JSON.parse(fs.readFileSync(path.join(root, "dist/site/page-registry.json"), "utf8"));
|
|
146
172
|
if (!cliSource.startsWith("#!/usr/bin/env node")) {
|
|
147
173
|
throw new Error("bin/buildchain.mjs must be executable with a node shebang");
|
|
148
174
|
}
|
|
@@ -167,6 +193,89 @@ if (!coreIndexSource.includes("KFD2_RELEASE_TRUST_PASSPORT_CONTRACT")) {
|
|
|
167
193
|
if (!coreIndexSource.includes("KFD2_TRUST_PROOF_CONTRACT")) {
|
|
168
194
|
throw new Error("packages/core/index.js must export KFD-2 trust proof contract");
|
|
169
195
|
}
|
|
196
|
+
if (siteBundle.contract !== "kungfu-buildchain-site-bundle") {
|
|
197
|
+
throw new Error("buildchain-site.json must expose the Buildchain site bundle contract");
|
|
198
|
+
}
|
|
199
|
+
if (siteBundle.source?.homepageTextSource !== "README.md") {
|
|
200
|
+
throw new Error("buildchain-site.json source.homepageTextSource must be README.md");
|
|
201
|
+
}
|
|
202
|
+
if (siteManifest.source?.homepageTextSource !== "README.md") {
|
|
203
|
+
throw new Error("site-manifest.json source.homepageTextSource must be README.md");
|
|
204
|
+
}
|
|
205
|
+
if (siteBundle.homepage?.title !== "Buildchain") {
|
|
206
|
+
throw new Error("buildchain-site.json homepage.title must match README H1");
|
|
207
|
+
}
|
|
208
|
+
if (!Array.isArray(siteBundle.homepage?.sections) || siteBundle.homepage.sections.length < 5) {
|
|
209
|
+
throw new Error("buildchain-site.json homepage.sections must expose README-derived sections");
|
|
210
|
+
}
|
|
211
|
+
for (const requiredSection of ["install-and-verify", "use-buildchain", "release-model", "toolkit-observability", "site-fact-source"]) {
|
|
212
|
+
if (!siteBundle.homepage.sections.some((entry) => entry.id === requiredSection && entry.sourcePath === "README.md" && entry.markdown)) {
|
|
213
|
+
throw new Error(`buildchain-site.json homepage.sections must include README projection ${requiredSection}`);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
if (siteBundle.homepage.sections.some((entry) => entry.id === "homepage-content-contract")) {
|
|
217
|
+
throw new Error("buildchain-site.json homepage.sections must not render the renderer contract as homepage content");
|
|
218
|
+
}
|
|
219
|
+
if (
|
|
220
|
+
siteBundle.homepage?.rendererContract?.id !== "homepage-content-contract" ||
|
|
221
|
+
siteBundle.homepage?.rendererContract?.renderAsHomepageContent !== false ||
|
|
222
|
+
!siteBundle.homepage?.rendererContract?.markdown
|
|
223
|
+
) {
|
|
224
|
+
throw new Error("buildchain-site.json homepage.rendererContract must expose README renderer contract outside homepage.sections");
|
|
225
|
+
}
|
|
226
|
+
if (!siteBundle.homepage?.displayPlan?.firstScreen?.include?.includes("install-and-verify")) {
|
|
227
|
+
throw new Error("buildchain-site.json homepage.displayPlan firstScreen must include install-and-verify");
|
|
228
|
+
}
|
|
229
|
+
if (!Array.isArray(siteBundle.renderingBoundary?.ownedByBuildchain) || !siteBundle.renderingBoundary.ownedByBuildchain.includes("homepage section projection from README.md")) {
|
|
230
|
+
throw new Error("buildchain-site.json renderingBoundary.ownedByBuildchain must include README projection ownership");
|
|
231
|
+
}
|
|
232
|
+
if (!Array.isArray(siteBundle.renderingBoundary?.ownedBySite) || !siteBundle.renderingBoundary.ownedBySite.includes("markdown-to-HTML renderer")) {
|
|
233
|
+
throw new Error("buildchain-site.json renderingBoundary.ownedBySite must include markdown-to-HTML renderer");
|
|
234
|
+
}
|
|
235
|
+
if (pageRegistry.contract !== "kungfu-buildchain-site-page-registry") {
|
|
236
|
+
throw new Error("page-registry.json must expose the site page registry contract");
|
|
237
|
+
}
|
|
238
|
+
if (siteBundle.pageRegistry?.path !== "page-registry.json" || siteBundle.pageRegistry?.pageCount !== pageRegistry.pageCount) {
|
|
239
|
+
throw new Error("buildchain-site.json must link to page-registry.json with matching page count");
|
|
240
|
+
}
|
|
241
|
+
if (!siteManifest.facts?.includes("page-registry.json") || !siteBundle.entrypoints?.includes("page-registry.json")) {
|
|
242
|
+
throw new Error("site bundle entrypoints must include page-registry.json");
|
|
243
|
+
}
|
|
244
|
+
function immediateReadmes(dir) {
|
|
245
|
+
const absoluteDir = path.join(root, dir);
|
|
246
|
+
if (!fs.existsSync(absoluteDir)) return [];
|
|
247
|
+
return fs.readdirSync(absoluteDir, { withFileTypes: true })
|
|
248
|
+
.filter((entry) => entry.isDirectory())
|
|
249
|
+
.map((entry) => `${dir}/${entry.name}/README.md`)
|
|
250
|
+
.filter((relPath) => fs.existsSync(path.join(root, relPath)))
|
|
251
|
+
.sort();
|
|
252
|
+
}
|
|
253
|
+
const expectedPageSources = [
|
|
254
|
+
"README.md",
|
|
255
|
+
...fs.readdirSync(path.join(root, "docs")).filter((name) => name.endsWith(".md")).sort().map((name) => `docs/${name}`),
|
|
256
|
+
...immediateReadmes("actions"),
|
|
257
|
+
"packages/core/README.md",
|
|
258
|
+
...immediateReadmes("fixtures"),
|
|
259
|
+
].sort();
|
|
260
|
+
const registryPageSources = [...new Set((pageRegistry.pages || []).map((page) => page.sourcePath))].sort();
|
|
261
|
+
const bundlePageSources = [...new Set((siteBundle.pages || []).map((page) => page.sourcePath))].sort();
|
|
262
|
+
if (JSON.stringify(registryPageSources) !== JSON.stringify(expectedPageSources)) {
|
|
263
|
+
throw new Error(`page-registry.json must include every public markdown page: expected ${expectedPageSources.length}, got ${registryPageSources.length}`);
|
|
264
|
+
}
|
|
265
|
+
if (JSON.stringify(bundlePageSources) !== JSON.stringify(expectedPageSources)) {
|
|
266
|
+
throw new Error(`buildchain-site.json pages must include every public markdown page: expected ${expectedPageSources.length}, got ${bundlePageSources.length}`);
|
|
267
|
+
}
|
|
268
|
+
for (const page of pageRegistry.pages || []) {
|
|
269
|
+
if (!page.id || !page.route || !page.title || !page.category || !page.sourcePath || !page.digest || !page.markdown) {
|
|
270
|
+
throw new Error(`page-registry.json page is incomplete: ${page.sourcePath || page.id || "<unknown>"}`);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
if (!pageRegistry.pages?.some((page) => page.sourcePath === "actions/promote-buildchain-ref/README.md")) {
|
|
274
|
+
throw new Error("page-registry.json must include action manuals");
|
|
275
|
+
}
|
|
276
|
+
if (!pageRegistry.pages?.some((page) => page.sourcePath === "packages/core/README.md" && page.category === "api")) {
|
|
277
|
+
throw new Error("page-registry.json must include Node API overview");
|
|
278
|
+
}
|
|
170
279
|
for (const requiredSnippet of [
|
|
171
280
|
"createBuildchainKfdClaimRegistry",
|
|
172
281
|
"createBuildchainKfd1Witness",
|
|
@@ -10,11 +10,16 @@ import {
|
|
|
10
10
|
} from "../packages/core/buildchain-kfd-claims.js";
|
|
11
11
|
|
|
12
12
|
const SITE_BUNDLE_CONTRACT = "kungfu-buildchain-site-bundle";
|
|
13
|
+
const README_PATH = "README.md";
|
|
13
14
|
const root = path.resolve(import.meta.dirname, "..");
|
|
14
15
|
const outputDir = path.join(root, "dist", "site");
|
|
15
16
|
|
|
17
|
+
function readText(rel) {
|
|
18
|
+
return fs.readFileSync(path.join(root, rel), "utf8");
|
|
19
|
+
}
|
|
20
|
+
|
|
16
21
|
function readJson(rel) {
|
|
17
|
-
return JSON.parse(
|
|
22
|
+
return JSON.parse(readText(rel));
|
|
18
23
|
}
|
|
19
24
|
|
|
20
25
|
function writeJson(filePath, value) {
|
|
@@ -37,6 +42,72 @@ function existingJson(filePath) {
|
|
|
37
42
|
return fs.existsSync(filePath) ? fs.readFileSync(filePath, "utf8") : "";
|
|
38
43
|
}
|
|
39
44
|
|
|
45
|
+
function normalizeMarkdown(value) {
|
|
46
|
+
return String(value || "").replace(/\r\n/g, "\n").trim();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function paragraphBlocks(markdown) {
|
|
50
|
+
return normalizeMarkdown(markdown)
|
|
51
|
+
.split(/\n{2,}/)
|
|
52
|
+
.map((block) => block.replace(/\n/g, " ").trim())
|
|
53
|
+
.filter(Boolean);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function parseReadme(markdown) {
|
|
57
|
+
const content = normalizeMarkdown(markdown);
|
|
58
|
+
const titleMatch = content.match(/^#\s+(.+)$/m);
|
|
59
|
+
if (!titleMatch) {
|
|
60
|
+
throw new Error(`${README_PATH} must start with an H1 title`);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const headingPattern = /^##\s+(.+)$/gm;
|
|
64
|
+
const headings = [];
|
|
65
|
+
let match;
|
|
66
|
+
while ((match = headingPattern.exec(content))) {
|
|
67
|
+
headings.push({
|
|
68
|
+
title: match[1].trim(),
|
|
69
|
+
index: match.index,
|
|
70
|
+
bodyStart: headingPattern.lastIndex,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const sections = {};
|
|
75
|
+
for (let index = 0; index < headings.length; index += 1) {
|
|
76
|
+
const current = headings[index];
|
|
77
|
+
const next = headings[index + 1];
|
|
78
|
+
sections[current.title] = content.slice(current.bodyStart, next ? next.index : content.length).trim();
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const intro = content.slice(titleMatch[0].length, headings[0]?.index ?? content.length).trim();
|
|
82
|
+
return {
|
|
83
|
+
title: titleMatch[1].trim(),
|
|
84
|
+
intro,
|
|
85
|
+
sections,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function readmeSection(readme, heading) {
|
|
90
|
+
const body = readme.sections[heading];
|
|
91
|
+
if (!body) {
|
|
92
|
+
throw new Error(`${README_PATH} missing required section: ${heading}`);
|
|
93
|
+
}
|
|
94
|
+
return body;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function homepageSection({ readme, id, heading, title = heading, role, priority, presentation, firstScreen = false }) {
|
|
98
|
+
return {
|
|
99
|
+
id,
|
|
100
|
+
sourcePath: README_PATH,
|
|
101
|
+
sourceHeading: heading,
|
|
102
|
+
title,
|
|
103
|
+
renderRole: role,
|
|
104
|
+
homepagePriority: priority,
|
|
105
|
+
defaultPresentation: presentation,
|
|
106
|
+
includeInFirstScreen: firstScreen,
|
|
107
|
+
markdown: normalizeMarkdown(readmeSection(readme, heading)),
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
40
111
|
function docEntry(id, title, pathName, plane) {
|
|
41
112
|
return {
|
|
42
113
|
id,
|
|
@@ -48,10 +119,102 @@ function docEntry(id, title, pathName, plane) {
|
|
|
48
119
|
};
|
|
49
120
|
}
|
|
50
121
|
|
|
122
|
+
function slugify(value) {
|
|
123
|
+
return String(value || "")
|
|
124
|
+
.toLowerCase()
|
|
125
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
126
|
+
.replace(/^-+|-+$/g, "") || "page";
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function markdownTitle(markdown, fallback) {
|
|
130
|
+
const match = normalizeMarkdown(markdown).match(/^#\s+(.+)$/m);
|
|
131
|
+
return match ? match[1].trim() : fallback;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function markdownHeadings(markdown) {
|
|
135
|
+
const headings = [];
|
|
136
|
+
const pattern = /^(#{1,4})\s+(.+)$/gm;
|
|
137
|
+
let match;
|
|
138
|
+
while ((match = pattern.exec(normalizeMarkdown(markdown)))) {
|
|
139
|
+
headings.push({
|
|
140
|
+
level: match[1].length,
|
|
141
|
+
title: match[2].trim(),
|
|
142
|
+
anchor: slugify(match[2]),
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
return headings;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function listMarkdownFiles(dir) {
|
|
149
|
+
const absoluteDir = path.join(root, dir);
|
|
150
|
+
if (!fs.existsSync(absoluteDir)) return [];
|
|
151
|
+
return fs.readdirSync(absoluteDir)
|
|
152
|
+
.filter((name) => name.endsWith(".md"))
|
|
153
|
+
.sort()
|
|
154
|
+
.map((name) => `${dir}/${name}`);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function immediateReadmes(dir) {
|
|
158
|
+
const absoluteDir = path.join(root, dir);
|
|
159
|
+
if (!fs.existsSync(absoluteDir)) return [];
|
|
160
|
+
return fs.readdirSync(absoluteDir, { withFileTypes: true })
|
|
161
|
+
.filter((entry) => entry.isDirectory())
|
|
162
|
+
.map((entry) => `${dir}/${entry.name}/README.md`)
|
|
163
|
+
.filter((relPath) => fs.existsSync(path.join(root, relPath)))
|
|
164
|
+
.sort();
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function sitePage(relPath, category, routePrefix, extra = {}) {
|
|
168
|
+
const markdown = normalizeMarkdown(readText(relPath));
|
|
169
|
+
const baseName = path.basename(relPath, path.extname(relPath));
|
|
170
|
+
const parentName = path.basename(path.dirname(relPath));
|
|
171
|
+
const slug = extra.slug || (baseName.toLowerCase() === "readme" ? slugify(parentName) : slugify(baseName));
|
|
172
|
+
const route = extra.route || `${routePrefix}/${slug}`;
|
|
173
|
+
const title = markdownTitle(markdown, extra.title || slug);
|
|
174
|
+
return {
|
|
175
|
+
id: extra.id || `${category}:${slug}`,
|
|
176
|
+
title,
|
|
177
|
+
route,
|
|
178
|
+
category,
|
|
179
|
+
sourcePath: relPath,
|
|
180
|
+
digest: sha256File(relPath),
|
|
181
|
+
headings: markdownHeadings(markdown),
|
|
182
|
+
markdown,
|
|
183
|
+
...extra,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function buildSitePages() {
|
|
188
|
+
const docsPages = listMarkdownFiles("docs").map((relPath) => sitePage(relPath, "manual", "/docs"));
|
|
189
|
+
const actionPages = immediateReadmes("actions").map((relPath) => sitePage(relPath, "action", "/actions"));
|
|
190
|
+
const fixturePages = immediateReadmes("fixtures").map((relPath) => sitePage(relPath, "fixture", "/fixtures"));
|
|
191
|
+
const apiPages = [
|
|
192
|
+
sitePage("packages/core/README.md", "api", "/api", {
|
|
193
|
+
id: "api:node-package",
|
|
194
|
+
slug: "node-package",
|
|
195
|
+
route: "/api/node-package",
|
|
196
|
+
}),
|
|
197
|
+
];
|
|
198
|
+
return [
|
|
199
|
+
sitePage(README_PATH, "overview", "/", {
|
|
200
|
+
id: "overview:home",
|
|
201
|
+
slug: "home",
|
|
202
|
+
route: "/",
|
|
203
|
+
title: "Buildchain",
|
|
204
|
+
}),
|
|
205
|
+
...docsPages,
|
|
206
|
+
...actionPages,
|
|
207
|
+
...apiPages,
|
|
208
|
+
...fixturePages,
|
|
209
|
+
].sort((a, b) => a.route.localeCompare(b.route));
|
|
210
|
+
}
|
|
211
|
+
|
|
51
212
|
function buildSiteBundle() {
|
|
52
213
|
const packageJson = readJson("package.json");
|
|
53
214
|
const inventory = readJson("tests/buildchain-inventory.json");
|
|
215
|
+
const readme = parseReadme(readText(README_PATH));
|
|
54
216
|
const docs = BUILDCHAIN_AGENT_MANUALS.map((manual) => docEntry(manual.id, manual.title, manual.path, manual.plane));
|
|
217
|
+
const pages = buildSitePages();
|
|
55
218
|
|
|
56
219
|
const cliRegistry = {
|
|
57
220
|
schemaVersion: 1,
|
|
@@ -98,10 +261,29 @@ function buildSiteBundle() {
|
|
|
98
261
|
"docs/release-passport.md",
|
|
99
262
|
"docs/publish-transaction.md",
|
|
100
263
|
"docs/site-bundle-contract.md",
|
|
264
|
+
"docs/runtime-train-validation.md",
|
|
265
|
+
"docs/consumer-issue-reporting.md",
|
|
266
|
+
"docs/ownership.md",
|
|
267
|
+
"docs/migration-inventory.md",
|
|
101
268
|
],
|
|
102
269
|
guidance: "Agent consumers should use this registry to find packaged Buildchain manuals before inferring behavior from workflow snippets or release notes.",
|
|
103
270
|
};
|
|
104
271
|
|
|
272
|
+
const pageRegistry = {
|
|
273
|
+
schemaVersion: 1,
|
|
274
|
+
contract: "kungfu-buildchain-site-page-registry",
|
|
275
|
+
package: packageJson.name,
|
|
276
|
+
sourceOfTruth: "npm package @kungfu-tech/buildchain/dist/site/page-registry.json",
|
|
277
|
+
rendererBoundary: {
|
|
278
|
+
contentOwner: "Buildchain",
|
|
279
|
+
rendererOwner: "site repository",
|
|
280
|
+
rule: "Site repositories render these markdown pages and metadata; they do not maintain separate Buildchain product copy.",
|
|
281
|
+
},
|
|
282
|
+
pageCount: pages.length,
|
|
283
|
+
categories: [...new Set(pages.map((page) => page.category))].sort(),
|
|
284
|
+
pages,
|
|
285
|
+
};
|
|
286
|
+
|
|
105
287
|
const nodeApiRegistry = {
|
|
106
288
|
schemaVersion: 1,
|
|
107
289
|
contract: "kungfu-buildchain-node-api-registry",
|
|
@@ -137,6 +319,7 @@ function buildSiteBundle() {
|
|
|
137
319
|
{ id: "validate-config", path: "actions/validate-config", status: "active" },
|
|
138
320
|
{ id: "run-lifecycle", path: "actions/run-lifecycle", status: "active" },
|
|
139
321
|
{ id: "promote-buildchain-ref", path: "actions/promote-buildchain-ref", status: "active" },
|
|
322
|
+
{ id: "report-buildchain-issue", path: "actions/report-buildchain-issue", status: "active" },
|
|
140
323
|
],
|
|
141
324
|
};
|
|
142
325
|
|
|
@@ -196,6 +379,7 @@ function buildSiteBundle() {
|
|
|
196
379
|
site: [
|
|
197
380
|
"buildchain-site.json",
|
|
198
381
|
"site-manifest.json",
|
|
382
|
+
"page-registry.json",
|
|
199
383
|
"cli-registry.json",
|
|
200
384
|
"manual-registry.json",
|
|
201
385
|
"node-api-registry.json",
|
|
@@ -264,8 +448,14 @@ function buildSiteBundle() {
|
|
|
264
448
|
versionSource: "package.json#version",
|
|
265
449
|
},
|
|
266
450
|
entrypoint: "buildchain-site.json",
|
|
451
|
+
source: {
|
|
452
|
+
homepageTextSource: README_PATH,
|
|
453
|
+
docsMap: "docs/MAP.md",
|
|
454
|
+
siteFactsDir: "dist/site",
|
|
455
|
+
},
|
|
267
456
|
docs,
|
|
268
457
|
facts: [
|
|
458
|
+
"page-registry.json",
|
|
269
459
|
"cli-registry.json",
|
|
270
460
|
"manual-registry.json",
|
|
271
461
|
"node-api-registry.json",
|
|
@@ -284,6 +474,7 @@ function buildSiteBundle() {
|
|
|
284
474
|
contract: "kungfu-buildchain-site-agent-index",
|
|
285
475
|
readOrder: [
|
|
286
476
|
"site-manifest.json",
|
|
477
|
+
"page-registry.json",
|
|
287
478
|
"product-mechanism.json",
|
|
288
479
|
"release-model.json",
|
|
289
480
|
"cli-registry.json",
|
|
@@ -297,22 +488,141 @@ function buildSiteBundle() {
|
|
|
297
488
|
instruction: "Use this bundle as the package-owned fact source for Buildchain pages. Do not infer current release mechanics from prose alone.",
|
|
298
489
|
};
|
|
299
490
|
|
|
491
|
+
const homepageSections = [
|
|
492
|
+
homepageSection({
|
|
493
|
+
readme,
|
|
494
|
+
id: "install-and-verify",
|
|
495
|
+
heading: "Install and Verify",
|
|
496
|
+
role: "primary",
|
|
497
|
+
priority: 10,
|
|
498
|
+
presentation: "release-passport-install",
|
|
499
|
+
firstScreen: true,
|
|
500
|
+
}),
|
|
501
|
+
homepageSection({
|
|
502
|
+
readme,
|
|
503
|
+
id: "use-buildchain",
|
|
504
|
+
heading: "Use Buildchain",
|
|
505
|
+
role: "primary",
|
|
506
|
+
priority: 20,
|
|
507
|
+
presentation: "workflow-surface-list",
|
|
508
|
+
firstScreen: true,
|
|
509
|
+
}),
|
|
510
|
+
homepageSection({
|
|
511
|
+
readme,
|
|
512
|
+
id: "release-model",
|
|
513
|
+
heading: "Release Model",
|
|
514
|
+
role: "primary",
|
|
515
|
+
priority: 30,
|
|
516
|
+
presentation: "release-model-table",
|
|
517
|
+
}),
|
|
518
|
+
homepageSection({
|
|
519
|
+
readme,
|
|
520
|
+
id: "toolkit-observability",
|
|
521
|
+
heading: "Toolkit Observability",
|
|
522
|
+
role: "support",
|
|
523
|
+
priority: 40,
|
|
524
|
+
presentation: "toolkit-example",
|
|
525
|
+
}),
|
|
526
|
+
homepageSection({
|
|
527
|
+
readme,
|
|
528
|
+
id: "site-fact-source",
|
|
529
|
+
heading: "Site Fact Source",
|
|
530
|
+
role: "support",
|
|
531
|
+
priority: 50,
|
|
532
|
+
presentation: "site-fact-source",
|
|
533
|
+
}),
|
|
534
|
+
];
|
|
535
|
+
|
|
536
|
+
const rendererContract = {
|
|
537
|
+
...homepageSection({
|
|
538
|
+
readme,
|
|
539
|
+
id: "homepage-content-contract",
|
|
540
|
+
heading: "Homepage Content Contract",
|
|
541
|
+
role: "renderer-contract",
|
|
542
|
+
priority: 90,
|
|
543
|
+
presentation: "developer-note",
|
|
544
|
+
}),
|
|
545
|
+
renderAsHomepageContent: false,
|
|
546
|
+
note: "This is a machine/renderer contract for site implementers. It should not be rendered as ordinary homepage content.",
|
|
547
|
+
};
|
|
548
|
+
|
|
300
549
|
const siteBundle = {
|
|
301
550
|
schemaVersion: 1,
|
|
302
551
|
contract: SITE_BUNDLE_CONTRACT,
|
|
303
552
|
product: siteManifest.product,
|
|
304
553
|
package: siteManifest.package,
|
|
554
|
+
source: {
|
|
555
|
+
package: packageJson.name,
|
|
556
|
+
homepageTextSource: README_PATH,
|
|
557
|
+
docsMap: "docs/MAP.md",
|
|
558
|
+
manualRegistry: "manual-registry.json",
|
|
559
|
+
siteFactsDir: "dist/site",
|
|
560
|
+
},
|
|
561
|
+
routes: {
|
|
562
|
+
home: "/",
|
|
563
|
+
docsPattern: "/docs/{id}",
|
|
564
|
+
llms: "/llms.txt",
|
|
565
|
+
manifest: "/manifest.json",
|
|
566
|
+
},
|
|
305
567
|
sourceOfTruth: "npm package @kungfu-tech/buildchain/dist/site",
|
|
306
568
|
humanFirst: true,
|
|
307
569
|
agentFirst: true,
|
|
308
570
|
entrypoints: siteManifest.facts.concat(["site-manifest.json"]),
|
|
571
|
+
pages,
|
|
572
|
+
pageRegistry: {
|
|
573
|
+
path: "page-registry.json",
|
|
574
|
+
contract: pageRegistry.contract,
|
|
575
|
+
pageCount: pageRegistry.pageCount,
|
|
576
|
+
categories: pageRegistry.categories,
|
|
577
|
+
},
|
|
578
|
+
homepage: {
|
|
579
|
+
title: readme.title,
|
|
580
|
+
lead: paragraphBlocks(readme.intro)[0] || "",
|
|
581
|
+
mechanismSummary: paragraphBlocks(readme.intro).slice(1),
|
|
582
|
+
sections: homepageSections,
|
|
583
|
+
displayPlan: {
|
|
584
|
+
firstScreen: {
|
|
585
|
+
include: ["title", "lead", "install-and-verify", "use-buildchain"],
|
|
586
|
+
maxPrimarySections: 2,
|
|
587
|
+
note: "The first viewport should establish Buildchain identity, release-passport trust, and the primary reusable workflow entrypoint without rendering implementation notes.",
|
|
588
|
+
},
|
|
589
|
+
primary: ["install-and-verify", "use-buildchain", "release-model"],
|
|
590
|
+
support: ["toolkit-observability", "site-fact-source"],
|
|
591
|
+
rendererContract: ["homepage-content-contract"],
|
|
592
|
+
},
|
|
593
|
+
rendererContract,
|
|
594
|
+
},
|
|
309
595
|
docs,
|
|
310
596
|
releaseModel,
|
|
597
|
+
renderingBoundary: {
|
|
598
|
+
ownedByBuildchain: [
|
|
599
|
+
"homepage title and text",
|
|
600
|
+
"homepage section projection from README.md",
|
|
601
|
+
"complete markdown page registry for Buildchain public docs, action manuals, Node API overview, and fixtures",
|
|
602
|
+
"release model facts",
|
|
603
|
+
"workflow and action registries",
|
|
604
|
+
"CLI command registry",
|
|
605
|
+
"manual and Node API registries",
|
|
606
|
+
"KFD claim registry",
|
|
607
|
+
"release-passport evidence vocabulary",
|
|
608
|
+
],
|
|
609
|
+
ownedBySite: [
|
|
610
|
+
"HTML structure",
|
|
611
|
+
"CSS",
|
|
612
|
+
"responsive layout",
|
|
613
|
+
"navigation layout",
|
|
614
|
+
"visual assets",
|
|
615
|
+
"decorative images",
|
|
616
|
+
"markdown-to-HTML renderer",
|
|
617
|
+
"section presentation and progressive disclosure within Buildchain displayPlan constraints",
|
|
618
|
+
],
|
|
619
|
+
},
|
|
311
620
|
};
|
|
312
621
|
|
|
313
622
|
return {
|
|
314
623
|
"buildchain-site.json": siteBundle,
|
|
315
624
|
"site-manifest.json": siteManifest,
|
|
625
|
+
"page-registry.json": pageRegistry,
|
|
316
626
|
"cli-registry.json": cliRegistry,
|
|
317
627
|
"manual-registry.json": manualRegistry,
|
|
318
628
|
"node-api-registry.json": nodeApiRegistry,
|