@kungfu-tech/buildchain 2.8.2-alpha.1 → 2.8.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/actions/promote-buildchain-ref/README.md +8 -0
- package/dist/site/agent-index.json +4 -1
- package/dist/site/artifact-schemas.json +3 -0
- package/dist/site/buildchain-contract.json +63 -11
- package/dist/site/buildchain-site.json +46 -16
- package/dist/site/kfd-claims.json +786 -0
- package/dist/site/manual-registry.json +132 -0
- package/dist/site/node-api-registry.json +93 -0
- package/dist/site/release-model.json +11 -0
- package/dist/site/release-provenance.json +4 -0
- package/dist/site/site-manifest.json +35 -16
- package/docs/MAP.md +21 -0
- package/docs/cli.md +25 -0
- package/docs/release-candidate.md +7 -7
- package/docs/release-governance.md +15 -7
- package/docs/release-passport.md +36 -0
- package/docs/site-bundle-contract.md +19 -1
- package/package.json +5 -1
- package/packages/core/buildchain-contract.js +37 -0
- package/packages/core/buildchain-kfd-claims.js +488 -0
- package/packages/core/index.js +13 -0
- package/scripts/check-inventory.mjs +76 -7
- package/scripts/ensure-github-release.mjs +9 -1
- package/scripts/generate-buildchain-kfd-witnesses.mjs +116 -0
- package/scripts/generate-site-bundle.mjs +105 -21
|
@@ -30,6 +30,7 @@ const requiredPaths = [
|
|
|
30
30
|
"scripts/create-release-bundle.mjs",
|
|
31
31
|
"scripts/ensure-github-release.mjs",
|
|
32
32
|
"scripts/generate-site-bundle.mjs",
|
|
33
|
+
"scripts/generate-buildchain-kfd-witnesses.mjs",
|
|
33
34
|
"scripts/generate-release-candidate-passport.mjs",
|
|
34
35
|
"scripts/artifact-relay-s3.mjs",
|
|
35
36
|
"scripts/npm-publish-dry-run.mjs",
|
|
@@ -105,6 +106,18 @@ if (rootPackage.exports?.["./release-passport"] !== "./packages/core/release-pas
|
|
|
105
106
|
if (rootPackage.exports?.["./release-propagation"] !== "./packages/core/release-propagation.js") {
|
|
106
107
|
throw new Error("root package must export @kungfu-tech/buildchain/release-propagation");
|
|
107
108
|
}
|
|
109
|
+
if (rootPackage.exports?.["./buildchain-kfd-claims"] !== "./packages/core/buildchain-kfd-claims.js") {
|
|
110
|
+
throw new Error("root package must export @kungfu-tech/buildchain/buildchain-kfd-claims");
|
|
111
|
+
}
|
|
112
|
+
if (rootPackage.exports?.["./site/manual-registry.json"] !== "./dist/site/manual-registry.json") {
|
|
113
|
+
throw new Error("root package must export @kungfu-tech/buildchain/site/manual-registry.json");
|
|
114
|
+
}
|
|
115
|
+
if (rootPackage.exports?.["./site/node-api-registry.json"] !== "./dist/site/node-api-registry.json") {
|
|
116
|
+
throw new Error("root package must export @kungfu-tech/buildchain/site/node-api-registry.json");
|
|
117
|
+
}
|
|
118
|
+
if (rootPackage.exports?.["./site/kfd-claims.json"] !== "./dist/site/kfd-claims.json") {
|
|
119
|
+
throw new Error("root package must export @kungfu-tech/buildchain/site/kfd-claims.json");
|
|
120
|
+
}
|
|
108
121
|
if (rootPackage.publishConfig?.access !== "public") {
|
|
109
122
|
throw new Error("root package publishConfig.access must be public");
|
|
110
123
|
}
|
|
@@ -128,6 +141,7 @@ const cliSource = fs.readFileSync(path.join(root, "bin/buildchain.mjs"), "utf8")
|
|
|
128
141
|
const coreIndexSource = fs.readFileSync(path.join(root, "packages/core/index.js"), "utf8");
|
|
129
142
|
const versioningDoc = fs.readFileSync(path.join(root, "docs/versioning.md"), "utf8");
|
|
130
143
|
const cliDoc = fs.readFileSync(path.join(root, "docs/cli.md"), "utf8");
|
|
144
|
+
const docsMap = fs.readFileSync(path.join(root, "docs/MAP.md"), "utf8");
|
|
131
145
|
const installDoc = fs.readFileSync(path.join(root, "docs/install.md"), "utf8");
|
|
132
146
|
if (!cliSource.startsWith("#!/usr/bin/env node")) {
|
|
133
147
|
throw new Error("bin/buildchain.mjs must be executable with a node shebang");
|
|
@@ -153,6 +167,17 @@ if (!coreIndexSource.includes("KFD2_RELEASE_TRUST_PASSPORT_CONTRACT")) {
|
|
|
153
167
|
if (!coreIndexSource.includes("KFD2_TRUST_PROOF_CONTRACT")) {
|
|
154
168
|
throw new Error("packages/core/index.js must export KFD-2 trust proof contract");
|
|
155
169
|
}
|
|
170
|
+
for (const requiredSnippet of [
|
|
171
|
+
"createBuildchainKfdClaimRegistry",
|
|
172
|
+
"createBuildchainKfd1Witness",
|
|
173
|
+
"createBuildchainKfd2Claims",
|
|
174
|
+
"createBuildchainKfd3PrebuildWitness",
|
|
175
|
+
"BUILDCHAIN_AGENT_MANUALS",
|
|
176
|
+
]) {
|
|
177
|
+
if (!coreIndexSource.includes(requiredSnippet)) {
|
|
178
|
+
throw new Error(`packages/core/index.js must export Buildchain self KFD claim API: ${requiredSnippet}`);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
156
181
|
for (const requiredSnippet of [
|
|
157
182
|
"createKfd1ReleaseGateEvidence",
|
|
158
183
|
"resolveKfd1Metadata",
|
|
@@ -207,6 +232,20 @@ for (const requiredSnippet of [
|
|
|
207
232
|
throw new Error(`release passport doc missing KFD-1 gate snippet: ${requiredSnippet}`);
|
|
208
233
|
}
|
|
209
234
|
}
|
|
235
|
+
for (const requiredSnippet of [
|
|
236
|
+
"Capability Coverage",
|
|
237
|
+
"KFD-1 / KFD-2 / KFD-3",
|
|
238
|
+
"floating `@v2`",
|
|
239
|
+
"npm publish transactions",
|
|
240
|
+
"GitHub Release",
|
|
241
|
+
"release propagation",
|
|
242
|
+
"manual-registry.json",
|
|
243
|
+
"node-api-registry.json",
|
|
244
|
+
]) {
|
|
245
|
+
if (!docsMap.includes(requiredSnippet)) {
|
|
246
|
+
throw new Error(`documentation map missing capability coverage snippet: ${requiredSnippet}`);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
210
249
|
const reusableBuildSurfaceDoc = fs.readFileSync(path.join(root, "docs/reusable-build-surface.md"), "utf8");
|
|
211
250
|
for (const requiredSnippet of [
|
|
212
251
|
"Floating Ref Contract Lock",
|
|
@@ -294,6 +333,7 @@ for (const requiredSnippet of [
|
|
|
294
333
|
"github.event.workflow_run.event == 'push'",
|
|
295
334
|
"target-sha: ${{ github.event.workflow_run.head_sha || inputs.sha || github.sha }}",
|
|
296
335
|
"github-release: true",
|
|
336
|
+
"release-passport-buildchain-self-kfd: true",
|
|
297
337
|
"publish-required-artifacts-json: \"[]\"",
|
|
298
338
|
"release-passport-impact-json: >-",
|
|
299
339
|
"Buildchain v2.8 promotes KFD self-verification",
|
|
@@ -311,17 +351,21 @@ for (const requiredSnippet of [
|
|
|
311
351
|
const releaseCandidatePromoteWorkflow = fs.readFileSync(path.join(root, ".github/workflows/release-candidate-promote.yml"), "utf8");
|
|
312
352
|
for (const requiredSnippet of [
|
|
313
353
|
"release-passport-kfd-1-witness-jsons:",
|
|
314
|
-
"release-passport-kfd-1-witness-jsons: ${{ inputs.release-passport-kfd-1-witness-jsons }}",
|
|
354
|
+
"release-passport-kfd-1-witness-jsons: ${{ inputs.release-passport-kfd-1-witness-jsons || steps.buildchain-self-kfd.outputs.kfd-1-witness-jsons }}",
|
|
315
355
|
"release-passport-kfd-2-claim-jsons:",
|
|
316
|
-
"release-passport-kfd-2-claim-jsons: ${{ inputs.release-passport-kfd-2-claim-jsons }}",
|
|
356
|
+
"release-passport-kfd-2-claim-jsons: ${{ inputs.release-passport-kfd-2-claim-jsons || steps.buildchain-self-kfd.outputs.kfd-2-claim-jsons }}",
|
|
317
357
|
"release-passport-kfd-3-prebuild-witness-jsons:",
|
|
318
|
-
"release-passport-kfd-3-prebuild-witness-jsons: ${{ inputs.release-passport-kfd-3-prebuild-witness-jsons }}",
|
|
358
|
+
"release-passport-kfd-3-prebuild-witness-jsons: ${{ inputs.release-passport-kfd-3-prebuild-witness-jsons || steps.buildchain-self-kfd.outputs.kfd-3-prebuild-witness-jsons }}",
|
|
319
359
|
"release-passport-kfd-3-artifact-witness-jsons:",
|
|
360
|
+
"release-passport-kfd-3-artifact-witness-jsons: ${{ inputs.release-passport-kfd-3-artifact-witness-jsons || steps.buildchain-self-kfd.outputs.kfd-3-artifact-witness-jsons }}",
|
|
320
361
|
"release-passport-kfd-3-artifact-verify-command:",
|
|
362
|
+
"release-passport-buildchain-self-kfd:",
|
|
363
|
+
"Generate Buildchain self KFD release claims",
|
|
364
|
+
"generate-buildchain-kfd-witnesses.mjs",
|
|
321
365
|
"github-release:",
|
|
322
|
-
"
|
|
323
|
-
"
|
|
324
|
-
"
|
|
366
|
+
"github-release: ${{ inputs.github-release }}",
|
|
367
|
+
"github-release-title: ${{ inputs.github-release-title }}",
|
|
368
|
+
"github-release-notes: ${{ inputs.github-release-notes }}",
|
|
325
369
|
"require-publish-source-lock: \"true\"",
|
|
326
370
|
"publish-source-ref: ${{ steps.publish-gate.outputs.ref }}",
|
|
327
371
|
"publish-source-sha: ${{ steps.publish-gate.outputs.sha }}",
|
|
@@ -377,6 +421,31 @@ for (const retiredWorkflow of [
|
|
|
377
421
|
}
|
|
378
422
|
}
|
|
379
423
|
}
|
|
424
|
+
const promoteBuildchainRefAction = fs.readFileSync(path.join(root, "actions/promote-buildchain-ref/action.yml"), "utf8");
|
|
425
|
+
const promoteBuildchainRefIndex = fs.readFileSync(path.join(root, "actions/promote-buildchain-ref/index.js"), "utf8");
|
|
426
|
+
for (const requiredSnippet of [
|
|
427
|
+
"github-release:",
|
|
428
|
+
"github-release-title:",
|
|
429
|
+
"github-release-notes:",
|
|
430
|
+
"github-release-url:",
|
|
431
|
+
"github-release-action:",
|
|
432
|
+
]) {
|
|
433
|
+
if (!promoteBuildchainRefAction.includes(requiredSnippet)) {
|
|
434
|
+
throw new Error(`promote-buildchain-ref action missing GitHub Release surface: ${requiredSnippet}`);
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
for (const requiredSnippet of [
|
|
438
|
+
"ensureGitHubRelease",
|
|
439
|
+
"publishGitHubReleaseEvidence",
|
|
440
|
+
"collectGitHubReleaseEvidenceAssets",
|
|
441
|
+
"uploadReleaseAsset",
|
|
442
|
+
"result.publishTransaction?.state === \"complete\"",
|
|
443
|
+
"result.publishTransaction?.finalizationNeeded !== true",
|
|
444
|
+
]) {
|
|
445
|
+
if (!promoteBuildchainRefIndex.includes(requiredSnippet)) {
|
|
446
|
+
throw new Error(`promote-buildchain-ref index missing semver GitHub Release implementation: ${requiredSnippet}`);
|
|
447
|
+
}
|
|
448
|
+
}
|
|
380
449
|
for (const forbiddenSnippet of [
|
|
381
450
|
"run: node scripts/release-candidate-resolver.mjs",
|
|
382
451
|
"uses: ./actions/promote-buildchain-ref",
|
|
@@ -493,7 +562,7 @@ for (const artifact of [
|
|
|
493
562
|
}
|
|
494
563
|
}
|
|
495
564
|
|
|
496
|
-
for (const siteFile of ["buildchain-site.json", "site-manifest.json", "cli-registry.json", "release-model.json", "buildchain-contract.json"]) {
|
|
565
|
+
for (const siteFile of ["buildchain-site.json", "site-manifest.json", "cli-registry.json", "manual-registry.json", "node-api-registry.json", "release-model.json", "buildchain-contract.json"]) {
|
|
497
566
|
if (!fs.existsSync(path.join(root, "dist", "site", siteFile))) {
|
|
498
567
|
throw new Error(`site bundle missing ${siteFile}`);
|
|
499
568
|
}
|
|
@@ -168,7 +168,15 @@ async function main() {
|
|
|
168
168
|
console.log(`github-release-make-latest=${result.metadata.makeLatest}`);
|
|
169
169
|
}
|
|
170
170
|
|
|
171
|
-
|
|
171
|
+
function isCliEntrypoint() {
|
|
172
|
+
const entry = process.argv[1] || "";
|
|
173
|
+
return (
|
|
174
|
+
entry.replace(/\\/g, "/").endsWith("/ensure-github-release.mjs") &&
|
|
175
|
+
import.meta.url === pathToFileURL(entry).href
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (isCliEntrypoint()) {
|
|
172
180
|
main().catch((error) => {
|
|
173
181
|
console.error(error.message);
|
|
174
182
|
process.exit(1);
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { execFileSync } from "node:child_process";
|
|
5
|
+
import { pathToFileURL } from "node:url";
|
|
6
|
+
import {
|
|
7
|
+
createBuildchainKfd1Witness,
|
|
8
|
+
createBuildchainKfd2Claims,
|
|
9
|
+
createBuildchainKfd3ArtifactWitness,
|
|
10
|
+
createBuildchainKfd3PrebuildWitness,
|
|
11
|
+
} from "../packages/core/buildchain-kfd-claims.js";
|
|
12
|
+
import { writeGitHubOutputs } from "./build-contract-core.mjs";
|
|
13
|
+
|
|
14
|
+
function parseArgs(argv = process.argv.slice(2)) {
|
|
15
|
+
const args = {
|
|
16
|
+
cwd: process.cwd(),
|
|
17
|
+
outputDir: ".buildchain/kfd",
|
|
18
|
+
sourceSha: process.env.BUILDCHAIN_SOURCE_SHA || "",
|
|
19
|
+
};
|
|
20
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
21
|
+
const arg = argv[index];
|
|
22
|
+
if (arg === "--cwd") {
|
|
23
|
+
args.cwd = argv[++index] || args.cwd;
|
|
24
|
+
} else if (arg === "--output-dir") {
|
|
25
|
+
args.outputDir = argv[++index] || args.outputDir;
|
|
26
|
+
} else if (arg === "--source-sha") {
|
|
27
|
+
args.sourceSha = argv[++index] || args.sourceSha;
|
|
28
|
+
} else if (arg === "--help") {
|
|
29
|
+
args.help = true;
|
|
30
|
+
} else {
|
|
31
|
+
throw new Error(`unknown argument: ${arg}`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return args;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function gitSha(cwd) {
|
|
38
|
+
try {
|
|
39
|
+
return execFileSync("git", ["rev-parse", "HEAD"], { cwd, encoding: "utf8" }).trim();
|
|
40
|
+
} catch {
|
|
41
|
+
return "";
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function writeJson(filePath, value) {
|
|
46
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
47
|
+
fs.writeFileSync(filePath, `${JSON.stringify(value, null, 2)}\n`);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function toRepoRelative(cwd, filePath) {
|
|
51
|
+
return path.relative(cwd, filePath).replace(/\\/g, "/");
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function generateBuildchainKfdWitnesses({
|
|
55
|
+
cwd = process.cwd(),
|
|
56
|
+
outputDir = ".buildchain/kfd",
|
|
57
|
+
sourceSha = "",
|
|
58
|
+
emitOutputs = true,
|
|
59
|
+
} = {}) {
|
|
60
|
+
const root = path.resolve(cwd);
|
|
61
|
+
const outDir = path.resolve(root, outputDir);
|
|
62
|
+
const resolvedSourceSha = sourceSha || gitSha(root);
|
|
63
|
+
const paths = {
|
|
64
|
+
kfd1Witness: path.join(outDir, "buildchain-kfd-1-witness.json"),
|
|
65
|
+
kfd3PrebuildWitness: path.join(outDir, "buildchain-kfd-3-prebuild-witness.json"),
|
|
66
|
+
kfd3ArtifactWitness: path.join(outDir, "buildchain-kfd-3-artifact-witness.json"),
|
|
67
|
+
kfd2ClaimsDir: path.join(outDir, "kfd-2-claims"),
|
|
68
|
+
};
|
|
69
|
+
writeJson(paths.kfd1Witness, createBuildchainKfd1Witness({ root, sourceSha: resolvedSourceSha }));
|
|
70
|
+
writeJson(paths.kfd3PrebuildWitness, createBuildchainKfd3PrebuildWitness({ root, sourceSha: resolvedSourceSha }));
|
|
71
|
+
writeJson(paths.kfd3ArtifactWitness, createBuildchainKfd3ArtifactWitness({ root, sourceSha: resolvedSourceSha }));
|
|
72
|
+
const witnessFiles = {
|
|
73
|
+
"kfd-1-witness": toRepoRelative(root, paths.kfd1Witness),
|
|
74
|
+
"kfd-3-prebuild-witness": toRepoRelative(root, paths.kfd3PrebuildWitness),
|
|
75
|
+
"kfd-3-artifact-witness": toRepoRelative(root, paths.kfd3ArtifactWitness),
|
|
76
|
+
};
|
|
77
|
+
const kfd2ClaimPaths = createBuildchainKfd2Claims({ root, witnessFiles }).map((claim) => {
|
|
78
|
+
const slug = String(claim.id || "claim")
|
|
79
|
+
.replace(/^claim:/, "")
|
|
80
|
+
.replace(/[^0-9A-Za-z._-]+/g, "-")
|
|
81
|
+
.replace(/^-+|-+$/g, "") || "claim";
|
|
82
|
+
const claimPath = path.join(paths.kfd2ClaimsDir, `${slug}.json`);
|
|
83
|
+
writeJson(claimPath, claim);
|
|
84
|
+
return claimPath;
|
|
85
|
+
});
|
|
86
|
+
const outputs = {
|
|
87
|
+
"kfd-1-witness-jsons": toRepoRelative(root, paths.kfd1Witness),
|
|
88
|
+
"kfd-2-claim-jsons": kfd2ClaimPaths.map((claimPath) => toRepoRelative(root, claimPath)).join(","),
|
|
89
|
+
"kfd-3-prebuild-witness-jsons": toRepoRelative(root, paths.kfd3PrebuildWitness),
|
|
90
|
+
"kfd-3-artifact-witness-jsons": toRepoRelative(root, paths.kfd3ArtifactWitness),
|
|
91
|
+
"source-sha": resolvedSourceSha,
|
|
92
|
+
"output-dir": toRepoRelative(root, outDir),
|
|
93
|
+
};
|
|
94
|
+
if (emitOutputs) {
|
|
95
|
+
writeGitHubOutputs(outputs);
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
schemaVersion: 1,
|
|
99
|
+
contract: "kungfu-buildchain-self-kfd-witness-generation",
|
|
100
|
+
outputs,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
|
|
105
|
+
try {
|
|
106
|
+
const args = parseArgs();
|
|
107
|
+
if (args.help) {
|
|
108
|
+
process.stdout.write("Usage: generate-buildchain-kfd-witnesses [--cwd <repo>] [--output-dir <dir>] [--source-sha <sha>]\n");
|
|
109
|
+
process.exit(0);
|
|
110
|
+
}
|
|
111
|
+
process.stdout.write(`${JSON.stringify(generateBuildchainKfdWitnesses(args), null, 2)}\n`);
|
|
112
|
+
} catch (error) {
|
|
113
|
+
console.error(`buildchain self KFD witnesses: ${error.message}`);
|
|
114
|
+
process.exitCode = 1;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import fs from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
|
+
import crypto from "node:crypto";
|
|
4
5
|
import { pathToFileURL } from "node:url";
|
|
5
6
|
import { createBuildchainContractWorld } from "../packages/core/buildchain-contract.js";
|
|
7
|
+
import {
|
|
8
|
+
BUILDCHAIN_AGENT_MANUALS,
|
|
9
|
+
createBuildchainKfdClaimRegistry,
|
|
10
|
+
} from "../packages/core/buildchain-kfd-claims.js";
|
|
6
11
|
|
|
7
12
|
const SITE_BUNDLE_CONTRACT = "kungfu-buildchain-site-bundle";
|
|
8
13
|
const root = path.resolve(import.meta.dirname, "..");
|
|
@@ -21,6 +26,13 @@ function stableJson(value) {
|
|
|
21
26
|
return `${JSON.stringify(value, null, 2)}\n`;
|
|
22
27
|
}
|
|
23
28
|
|
|
29
|
+
function sha256File(rel) {
|
|
30
|
+
const filePath = path.join(root, rel);
|
|
31
|
+
return fs.existsSync(filePath) && fs.statSync(filePath).isFile()
|
|
32
|
+
? `sha256:${crypto.createHash("sha256").update(fs.readFileSync(filePath)).digest("hex")}`
|
|
33
|
+
: "";
|
|
34
|
+
}
|
|
35
|
+
|
|
24
36
|
function existingJson(filePath) {
|
|
25
37
|
return fs.existsSync(filePath) ? fs.readFileSync(filePath, "utf8") : "";
|
|
26
38
|
}
|
|
@@ -32,30 +44,14 @@ function docEntry(id, title, pathName, plane) {
|
|
|
32
44
|
path: pathName,
|
|
33
45
|
plane,
|
|
34
46
|
exists: fs.existsSync(path.join(root, pathName)),
|
|
47
|
+
digest: sha256File(pathName),
|
|
35
48
|
};
|
|
36
49
|
}
|
|
37
50
|
|
|
38
51
|
function buildSiteBundle() {
|
|
39
52
|
const packageJson = readJson("package.json");
|
|
40
53
|
const inventory = readJson("tests/buildchain-inventory.json");
|
|
41
|
-
const docs =
|
|
42
|
-
docEntry("install", "Install and verify Buildchain", "docs/install.md", "use"),
|
|
43
|
-
docEntry("release-passport", "Release Passport protocol", "docs/release-passport.md", "verify"),
|
|
44
|
-
docEntry("release-propagation", "Release propagation", "docs/release-propagation.md", "use"),
|
|
45
|
-
docEntry("binary-distribution", "Binary distribution contract", "docs/binary-distribution.md", "verify"),
|
|
46
|
-
docEntry("toolkit-observability", "Toolkit observability", "docs/toolkit-observability.md", "use"),
|
|
47
|
-
docEntry("site-bundle-contract", "Site bundle contract", "docs/site-bundle-contract.md", "use"),
|
|
48
|
-
docEntry("product-mechanism", "Product mechanism", "docs/product-mechanism.md", "why"),
|
|
49
|
-
docEntry("cli", "CLI and npm package", "docs/cli.md", "use"),
|
|
50
|
-
docEntry("lifecycle-protocol", "Lifecycle protocol", "docs/lifecycle-protocol.md", "use"),
|
|
51
|
-
docEntry("reusable-build-surface", "Reusable build surface", "docs/reusable-build-surface.md", "use"),
|
|
52
|
-
docEntry("publish-transaction", "Publish transaction", "docs/publish-transaction.md", "verify"),
|
|
53
|
-
docEntry("release-governance", "Release governance", "docs/release-governance.md", "why"),
|
|
54
|
-
docEntry("release-flow", "Release flow", "docs/release-flow.md", "verify"),
|
|
55
|
-
docEntry("versioning", "Versioning", "docs/versioning.md", "why"),
|
|
56
|
-
docEntry("web-surface-deployments", "Web surface deployments", "docs/web-surface-deployments.md", "use"),
|
|
57
|
-
docEntry("infra-contract", "Infra Contract", "docs/infra-contract.md", "use"),
|
|
58
|
-
];
|
|
54
|
+
const docs = BUILDCHAIN_AGENT_MANUALS.map((manual) => docEntry(manual.id, manual.title, manual.path, manual.plane));
|
|
59
55
|
|
|
60
56
|
const cliRegistry = {
|
|
61
57
|
schemaVersion: 1,
|
|
@@ -80,6 +76,52 @@ function buildSiteBundle() {
|
|
|
80
76
|
],
|
|
81
77
|
};
|
|
82
78
|
|
|
79
|
+
const manualRegistry = {
|
|
80
|
+
schemaVersion: 1,
|
|
81
|
+
contract: "kungfu-buildchain-agent-manual-registry",
|
|
82
|
+
package: packageJson.name,
|
|
83
|
+
source: "npm package docs/",
|
|
84
|
+
manuals: docs.map((entry) => ({
|
|
85
|
+
id: entry.id,
|
|
86
|
+
title: entry.title,
|
|
87
|
+
path: entry.path,
|
|
88
|
+
plane: entry.plane,
|
|
89
|
+
digest: entry.digest,
|
|
90
|
+
})),
|
|
91
|
+
requiredAgentManuals: [
|
|
92
|
+
"docs/MAP.md",
|
|
93
|
+
"docs/install.md",
|
|
94
|
+
"docs/cli.md",
|
|
95
|
+
"docs/reusable-build-surface.md",
|
|
96
|
+
"docs/release-candidate.md",
|
|
97
|
+
"docs/release-governance.md",
|
|
98
|
+
"docs/release-passport.md",
|
|
99
|
+
"docs/publish-transaction.md",
|
|
100
|
+
"docs/site-bundle-contract.md",
|
|
101
|
+
],
|
|
102
|
+
guidance: "Agent consumers should use this registry to find packaged Buildchain manuals before inferring behavior from workflow snippets or release notes.",
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
const nodeApiRegistry = {
|
|
106
|
+
schemaVersion: 1,
|
|
107
|
+
contract: "kungfu-buildchain-node-api-registry",
|
|
108
|
+
package: packageJson.name,
|
|
109
|
+
moduleSystem: packageJson.type || "module",
|
|
110
|
+
exports: Object.entries(packageJson.exports || {})
|
|
111
|
+
.filter(([specifier]) => !specifier.startsWith("./site/") && specifier !== "./package.json")
|
|
112
|
+
.map(([specifier, target]) => ({
|
|
113
|
+
specifier: specifier === "." ? packageJson.name : `${packageJson.name}/${specifier.replace(/^\.\//, "")}`,
|
|
114
|
+
export: specifier,
|
|
115
|
+
target,
|
|
116
|
+
digest: typeof target === "string" ? sha256File(target.replace(/^\.\//, "")) : "",
|
|
117
|
+
})),
|
|
118
|
+
docs: [
|
|
119
|
+
{ id: "cli-and-node-package", path: "docs/cli.md", digest: sha256File("docs/cli.md") },
|
|
120
|
+
{ id: "site-bundle-contract", path: "docs/site-bundle-contract.md", digest: sha256File("docs/site-bundle-contract.md") },
|
|
121
|
+
],
|
|
122
|
+
guidance: "These are the public Node import surfaces shipped by the npm package. Agents should prefer these exports over internal file paths.",
|
|
123
|
+
};
|
|
124
|
+
|
|
83
125
|
const workflowRegistry = {
|
|
84
126
|
schemaVersion: 1,
|
|
85
127
|
contract: "kungfu-buildchain-workflow-registry",
|
|
@@ -124,6 +166,17 @@ function buildSiteBundle() {
|
|
|
124
166
|
alphaDistTag: "alpha",
|
|
125
167
|
stableDistTag: "latest",
|
|
126
168
|
},
|
|
169
|
+
githubRelease: {
|
|
170
|
+
exactTagRelease: true,
|
|
171
|
+
prereleaseTags: "semver prerelease tags set prerelease=true and make_latest=false",
|
|
172
|
+
stableTags: "stable semver tags set make_latest=true",
|
|
173
|
+
evidenceAssets: [
|
|
174
|
+
"publish evidence JSON",
|
|
175
|
+
"buildchain.release.json",
|
|
176
|
+
"release passport assets",
|
|
177
|
+
],
|
|
178
|
+
owner: "promote-buildchain-ref",
|
|
179
|
+
},
|
|
127
180
|
};
|
|
128
181
|
|
|
129
182
|
const artifactSchemas = {
|
|
@@ -144,10 +197,13 @@ function buildSiteBundle() {
|
|
|
144
197
|
"buildchain-site.json",
|
|
145
198
|
"site-manifest.json",
|
|
146
199
|
"cli-registry.json",
|
|
200
|
+
"manual-registry.json",
|
|
201
|
+
"node-api-registry.json",
|
|
147
202
|
"workflow-registry.json",
|
|
148
203
|
"release-model.json",
|
|
149
204
|
"artifact-schemas.json",
|
|
150
205
|
"buildchain-contract.json",
|
|
206
|
+
"kfd-claims.json",
|
|
151
207
|
"product-mechanism.json",
|
|
152
208
|
"release-provenance.json",
|
|
153
209
|
"agent-index.json",
|
|
@@ -211,11 +267,14 @@ function buildSiteBundle() {
|
|
|
211
267
|
docs,
|
|
212
268
|
facts: [
|
|
213
269
|
"cli-registry.json",
|
|
270
|
+
"manual-registry.json",
|
|
271
|
+
"node-api-registry.json",
|
|
214
272
|
"workflow-registry.json",
|
|
215
273
|
"release-model.json",
|
|
216
274
|
"artifact-schemas.json",
|
|
217
275
|
"product-mechanism.json",
|
|
218
276
|
"release-provenance.json",
|
|
277
|
+
"kfd-claims.json",
|
|
219
278
|
"agent-index.json",
|
|
220
279
|
],
|
|
221
280
|
};
|
|
@@ -228,9 +287,12 @@ function buildSiteBundle() {
|
|
|
228
287
|
"product-mechanism.json",
|
|
229
288
|
"release-model.json",
|
|
230
289
|
"cli-registry.json",
|
|
290
|
+
"manual-registry.json",
|
|
291
|
+
"node-api-registry.json",
|
|
231
292
|
"workflow-registry.json",
|
|
232
293
|
"artifact-schemas.json",
|
|
233
294
|
"buildchain-contract.json",
|
|
295
|
+
"kfd-claims.json",
|
|
234
296
|
],
|
|
235
297
|
instruction: "Use this bundle as the package-owned fact source for Buildchain pages. Do not infer current release mechanics from prose alone.",
|
|
236
298
|
};
|
|
@@ -252,10 +314,13 @@ function buildSiteBundle() {
|
|
|
252
314
|
"buildchain-site.json": siteBundle,
|
|
253
315
|
"site-manifest.json": siteManifest,
|
|
254
316
|
"cli-registry.json": cliRegistry,
|
|
317
|
+
"manual-registry.json": manualRegistry,
|
|
318
|
+
"node-api-registry.json": nodeApiRegistry,
|
|
255
319
|
"workflow-registry.json": workflowRegistry,
|
|
256
320
|
"release-model.json": releaseModel,
|
|
257
321
|
"artifact-schemas.json": artifactSchemas,
|
|
258
322
|
"buildchain-contract.json": createBuildchainContractWorld({ root }),
|
|
323
|
+
"kfd-claims.json": createBuildchainKfdClaimRegistry({ root }),
|
|
259
324
|
"product-mechanism.json": productMechanism,
|
|
260
325
|
"release-provenance.json": releaseProvenance,
|
|
261
326
|
"agent-index.json": agentIndex,
|
|
@@ -263,7 +328,7 @@ function buildSiteBundle() {
|
|
|
263
328
|
}
|
|
264
329
|
|
|
265
330
|
export function writeSiteBundle({ check = false } = {}) {
|
|
266
|
-
|
|
331
|
+
let files = buildSiteBundle();
|
|
267
332
|
const mismatches = [];
|
|
268
333
|
for (const [name, value] of Object.entries(files)) {
|
|
269
334
|
const filePath = path.join(outputDir, name);
|
|
@@ -272,13 +337,32 @@ export function writeSiteBundle({ check = false } = {}) {
|
|
|
272
337
|
if (existingJson(filePath) !== next) {
|
|
273
338
|
mismatches.push(path.relative(root, filePath));
|
|
274
339
|
}
|
|
275
|
-
} else {
|
|
276
|
-
writeJson(filePath, value);
|
|
277
340
|
}
|
|
278
341
|
}
|
|
279
342
|
if (mismatches.length > 0) {
|
|
280
343
|
throw new Error(`site bundle is stale: ${mismatches.join(", ")}`);
|
|
281
344
|
}
|
|
345
|
+
if (!check) {
|
|
346
|
+
for (let iteration = 0; iteration < 5; iteration += 1) {
|
|
347
|
+
for (const [name, value] of Object.entries(files)) {
|
|
348
|
+
writeJson(path.join(outputDir, name), value);
|
|
349
|
+
}
|
|
350
|
+
const nextFiles = buildSiteBundle();
|
|
351
|
+
const stable = Object.entries(nextFiles).every(([name, value]) => (
|
|
352
|
+
existingJson(path.join(outputDir, name)) === stableJson(value)
|
|
353
|
+
));
|
|
354
|
+
files = nextFiles;
|
|
355
|
+
if (stable) {
|
|
356
|
+
break;
|
|
357
|
+
}
|
|
358
|
+
if (iteration === 4) {
|
|
359
|
+
throw new Error("site bundle did not converge after 5 generations");
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
for (const [name, value] of Object.entries(files)) {
|
|
363
|
+
writeJson(path.join(outputDir, name), value);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
282
366
|
return {
|
|
283
367
|
schemaVersion: 1,
|
|
284
368
|
contract: "kungfu-buildchain-site-bundle-generation",
|