@kungfu-tech/buildchain 2.10.4 → 2.10.5

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.
Files changed (37) hide show
  1. package/README.md +16 -1
  2. package/bin/buildchain.mjs +299 -16
  3. package/dist/site/buildchain-contract.json +7 -7
  4. package/dist/site/buildchain-site.json +42 -37
  5. package/dist/site/capability-registry.json +2 -2
  6. package/dist/site/cli-registry.json +164 -8
  7. package/dist/site/kfd-claims.json +190 -19
  8. package/dist/site/manual-registry.json +10 -10
  9. package/dist/site/node-api-registry.json +24 -11
  10. package/dist/site/page-registry.json +27 -22
  11. package/dist/site/public-surface-audit.json +334 -126
  12. package/dist/site/release-provenance.json +2 -1
  13. package/dist/site/site-manifest.json +14 -14
  14. package/dist/site/workflow-registry.json +4 -1
  15. package/docs/MAP.md +2 -2
  16. package/docs/cli.md +48 -14
  17. package/docs/install.md +1 -1
  18. package/docs/kfd-support.md +80 -21
  19. package/docs/lifecycle-protocol.md +7 -2
  20. package/docs/publish-transaction.md +1 -1
  21. package/docs/readme-badges.md +2 -2
  22. package/docs/release-passport.md +1 -1
  23. package/docs/reusable-build-surface.md +7 -7
  24. package/docs/web-surface-deployments.md +33 -4
  25. package/package.json +3 -2
  26. package/packages/core/buildchain-config.js +10 -5
  27. package/packages/core/buildchain-layout.js +157 -0
  28. package/packages/core/index.js +34 -0
  29. package/packages/core/kfd.js +273 -0
  30. package/packages/core/kfd3-surface-register.js +25 -17
  31. package/packages/core/public-surface-audit.js +14 -7
  32. package/scripts/buildchain-contract-lock.mjs +6 -2
  33. package/scripts/check-inventory.mjs +5 -4
  34. package/scripts/generate-site-bundle.mjs +20 -3
  35. package/scripts/init-repo.mjs +2 -1
  36. package/scripts/web-surface-production-release-pr.mjs +209 -36
  37. package/scripts/web-surface-release-pr-review.mjs +2 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kungfu-tech/buildchain",
3
- "version": "2.10.4",
3
+ "version": "2.10.5",
4
4
  "private": false,
5
5
  "description": "Buildchain Release Passport, release governance, CLI toolkit, and site facts.",
6
6
  "repository": "https://github.com/kungfu-systems/buildchain",
@@ -20,7 +20,8 @@
20
20
  "./diagnostics": "./packages/core/diagnostics.js",
21
21
  "./homebrew": "./packages/core/homebrew.js",
22
22
  "./issue-reporting": "./packages/core/issue-reporting.js",
23
- "./kfd-3-surfaces": "./packages/core/kfd3-surface-register.js",
23
+ "./kfd": "./packages/core/kfd.js",
24
+ "./buildchain-layout": "./packages/core/buildchain-layout.js",
24
25
  "./release-line-bootstrap": "./packages/core/release-line-bootstrap.js",
25
26
  "./readme-badges": "./packages/core/readme-badges.js",
26
27
  "./public-surface-audit": "./packages/core/public-surface-audit.js",
@@ -3,8 +3,12 @@ import fs from "node:fs";
3
3
  import os from "node:os";
4
4
  import path from "node:path";
5
5
  import { parse, stringify } from "smol-toml";
6
+ import {
7
+ BUILDCHAIN_CONFIG_PATH,
8
+ resolveBuildchainConfigPath,
9
+ } from "./buildchain-layout.js";
6
10
 
7
- const CONFIG_FILE = "buildchain.toml";
11
+ const CONFIG_FILE = BUILDCHAIN_CONFIG_PATH;
8
12
  const RESERVED_LIFECYCLE_KEYS = new Set(["env", "shell"]);
9
13
  const SUPPORTED_VERSION_FILE_TYPES = new Set(["json", "toml", "regex"]);
10
14
  const SUPPORTED_VERSION_STRATEGIES = new Set(["semver", "anchored"]);
@@ -97,7 +101,8 @@ function setByDottedKey(target, key, value) {
97
101
  }
98
102
 
99
103
  export function loadBuildchainConfig(cwd = process.cwd()) {
100
- const filePath = path.join(cwd, CONFIG_FILE);
104
+ const configPath = resolveBuildchainConfigPath(cwd);
105
+ const filePath = path.join(cwd, configPath);
101
106
  if (!fs.existsSync(filePath)) {
102
107
  return undefined;
103
108
  }
@@ -106,13 +111,13 @@ export function loadBuildchainConfig(cwd = process.cwd()) {
106
111
  try {
107
112
  config = parse(source);
108
113
  } catch (error) {
109
- throw new Error(`${CONFIG_FILE} parse failed: ${error.message}`);
114
+ throw new Error(`${configPath} parse failed: ${error.message}`);
110
115
  }
111
116
  if (config.schema !== 1) {
112
- throw new Error(`${CONFIG_FILE} schema must be 1`);
117
+ throw new Error(`${configPath} schema must be 1`);
113
118
  }
114
119
  return {
115
- path: CONFIG_FILE,
120
+ path: configPath,
116
121
  filePath,
117
122
  config: normalizeBuildchainConfig(config),
118
123
  };
@@ -0,0 +1,157 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+
4
+ export const BUILDCHAIN_DIR = ".buildchain";
5
+ export const BUILDCHAIN_CONFIG_PATH = ".buildchain/buildchain.toml";
6
+ export const LEGACY_BUILDCHAIN_CONFIG_PATH = "buildchain.toml";
7
+ export const BUILDCHAIN_CONTRACT_LOCK_PATH = ".buildchain/contract-lock.json";
8
+ export const LEGACY_BUILDCHAIN_CONTRACT_LOCK_PATH = "buildchain.contract-lock.json";
9
+ export const BUILDCHAIN_KFD3_SURFACE_REGISTRY_PATH = ".buildchain/kfd/kfd-3-surfaces.json";
10
+ export const LEGACY_BUILDCHAIN_KFD3_SURFACE_REGISTRY_PATH = "buildchain.kfd3.json";
11
+ export const BUILDCHAIN_RELEASE_PASSPORT_PATH = ".buildchain/release-passport/buildchain.release.json";
12
+ export const LEGACY_BUILDCHAIN_RELEASE_PASSPORT_PATH = "buildchain.release.json";
13
+
14
+ export const BUILDCHAIN_GENERATED_DIRS = Object.freeze([
15
+ ".buildchain/artifacts",
16
+ ".buildchain/diagnostics",
17
+ ".buildchain/logs",
18
+ ".buildchain/tmp",
19
+ ".buildchain/runtime",
20
+ ".buildchain/release-state",
21
+ ".buildchain/release-evidence",
22
+ ".buildchain/downloaded-manifests",
23
+ ".buildchain/downloaded-diagnostics",
24
+ ".buildchain/downloaded-relay-manifests",
25
+ ".buildchain/relayed-artifacts",
26
+ ]);
27
+
28
+ export function toPosixPath(value) {
29
+ return String(value || "").split(path.sep).join("/");
30
+ }
31
+
32
+ export function repoPath(cwd, relativePath) {
33
+ return path.join(cwd, relativePath);
34
+ }
35
+
36
+ export function firstExistingRepoPath(cwd, candidates = []) {
37
+ for (const candidate of candidates) {
38
+ if (fs.existsSync(repoPath(cwd, candidate))) {
39
+ return candidate;
40
+ }
41
+ }
42
+ return candidates[0] || "";
43
+ }
44
+
45
+ export function resolveBuildchainConfigPath(cwd = process.cwd()) {
46
+ return firstExistingRepoPath(cwd, [
47
+ BUILDCHAIN_CONFIG_PATH,
48
+ LEGACY_BUILDCHAIN_CONFIG_PATH,
49
+ ]);
50
+ }
51
+
52
+ export function resolveBuildchainContractLockPath(cwd = process.cwd()) {
53
+ return firstExistingRepoPath(cwd, [
54
+ BUILDCHAIN_CONTRACT_LOCK_PATH,
55
+ LEGACY_BUILDCHAIN_CONTRACT_LOCK_PATH,
56
+ ]);
57
+ }
58
+
59
+ export function resolveKfd3SurfaceRegistryPath(cwd = process.cwd()) {
60
+ return firstExistingRepoPath(cwd, [
61
+ BUILDCHAIN_KFD3_SURFACE_REGISTRY_PATH,
62
+ LEGACY_BUILDCHAIN_KFD3_SURFACE_REGISTRY_PATH,
63
+ ]);
64
+ }
65
+
66
+ export function resolveReleasePassportPath(cwd = process.cwd()) {
67
+ return firstExistingRepoPath(cwd, [
68
+ BUILDCHAIN_RELEASE_PASSPORT_PATH,
69
+ LEGACY_BUILDCHAIN_RELEASE_PASSPORT_PATH,
70
+ ]);
71
+ }
72
+
73
+ export function discoverBuildchainRepoFiles(cwd = process.cwd()) {
74
+ const files = [
75
+ {
76
+ kind: "config",
77
+ canonical: BUILDCHAIN_CONFIG_PATH,
78
+ legacy: LEGACY_BUILDCHAIN_CONFIG_PATH,
79
+ tracked: true,
80
+ },
81
+ {
82
+ kind: "contract-lock",
83
+ canonical: BUILDCHAIN_CONTRACT_LOCK_PATH,
84
+ legacy: LEGACY_BUILDCHAIN_CONTRACT_LOCK_PATH,
85
+ tracked: true,
86
+ },
87
+ {
88
+ kind: "kfd-3-surface-registry",
89
+ canonical: BUILDCHAIN_KFD3_SURFACE_REGISTRY_PATH,
90
+ legacy: LEGACY_BUILDCHAIN_KFD3_SURFACE_REGISTRY_PATH,
91
+ tracked: true,
92
+ },
93
+ {
94
+ kind: "release-passport",
95
+ canonical: BUILDCHAIN_RELEASE_PASSPORT_PATH,
96
+ legacy: LEGACY_BUILDCHAIN_RELEASE_PASSPORT_PATH,
97
+ tracked: false,
98
+ },
99
+ ];
100
+ return files.map((entry) => {
101
+ const canonicalExists = fs.existsSync(repoPath(cwd, entry.canonical));
102
+ const legacyExists = fs.existsSync(repoPath(cwd, entry.legacy));
103
+ return {
104
+ ...entry,
105
+ canonicalExists,
106
+ legacyExists,
107
+ activePath: canonicalExists ? entry.canonical : legacyExists ? entry.legacy : entry.canonical,
108
+ migrationNeeded: !canonicalExists && legacyExists,
109
+ };
110
+ });
111
+ }
112
+
113
+ export function planBuildchainLayoutMigration({ cwd = process.cwd() } = {}) {
114
+ const entries = discoverBuildchainRepoFiles(cwd);
115
+ const moves = entries
116
+ .filter((entry) => entry.migrationNeeded)
117
+ .map((entry) => ({
118
+ kind: entry.kind,
119
+ from: entry.legacy,
120
+ to: entry.canonical,
121
+ tracked: entry.tracked,
122
+ }));
123
+ return {
124
+ schemaVersion: 1,
125
+ contract: "kungfu-buildchain-repository-layout-migration",
126
+ cwd: path.resolve(cwd),
127
+ canonicalRoot: BUILDCHAIN_DIR,
128
+ status: moves.length > 0 ? "migration-needed" : "current",
129
+ files: entries,
130
+ generatedDirs: BUILDCHAIN_GENERATED_DIRS,
131
+ moves,
132
+ };
133
+ }
134
+
135
+ export function migrateBuildchainLayout({ cwd = process.cwd(), write = false, force = false } = {}) {
136
+ const plan = planBuildchainLayoutMigration({ cwd });
137
+ const applied = [];
138
+ if (write) {
139
+ for (const move of plan.moves) {
140
+ const from = repoPath(cwd, move.from);
141
+ const to = repoPath(cwd, move.to);
142
+ if (fs.existsSync(to) && !force) {
143
+ throw new Error(`${move.to} already exists; pass --force to overwrite`);
144
+ }
145
+ fs.mkdirSync(path.dirname(to), { recursive: true });
146
+ fs.renameSync(from, to);
147
+ applied.push(move);
148
+ }
149
+ }
150
+ return {
151
+ ...plan,
152
+ write,
153
+ force,
154
+ status: write && applied.length === plan.moves.length ? "applied" : plan.status,
155
+ applied,
156
+ };
157
+ }
@@ -257,6 +257,40 @@ export {
257
257
  updateHomebrewTap,
258
258
  } from "./homebrew.js";
259
259
 
260
+ export {
261
+ BUILDCHAIN_CONFIG_PATH,
262
+ BUILDCHAIN_CONTRACT_LOCK_PATH,
263
+ BUILDCHAIN_DIR,
264
+ BUILDCHAIN_GENERATED_DIRS,
265
+ BUILDCHAIN_KFD3_SURFACE_REGISTRY_PATH,
266
+ BUILDCHAIN_RELEASE_PASSPORT_PATH,
267
+ LEGACY_BUILDCHAIN_CONFIG_PATH,
268
+ LEGACY_BUILDCHAIN_CONTRACT_LOCK_PATH,
269
+ LEGACY_BUILDCHAIN_KFD3_SURFACE_REGISTRY_PATH,
270
+ LEGACY_BUILDCHAIN_RELEASE_PASSPORT_PATH,
271
+ discoverBuildchainRepoFiles,
272
+ migrateBuildchainLayout,
273
+ planBuildchainLayoutMigration,
274
+ resolveBuildchainConfigPath,
275
+ resolveBuildchainContractLockPath,
276
+ resolveKfd3SurfaceRegistryPath,
277
+ resolveReleasePassportPath,
278
+ } from "./buildchain-layout.js";
279
+ export {
280
+ buildchainKfdClaims,
281
+ collectKfdStatus,
282
+ discoverKfdStandards,
283
+ layout,
284
+ kfd1,
285
+ kfd2,
286
+ kfd3,
287
+ kfd4,
288
+ listKfdSchemas,
289
+ normalizeKfdStandardId,
290
+ readKfdSchema,
291
+ schemas,
292
+ } from "./kfd.js";
293
+
260
294
  export {
261
295
  KFD3_CAPABILITY_QUERY_CONTRACT,
262
296
  KFD3_DEFAULT_REGISTRY_PATH,
@@ -0,0 +1,273 @@
1
+ import fs from "node:fs";
2
+ import { createRequire } from "node:module";
3
+ import path from "node:path";
4
+
5
+ import {
6
+ createBuildchainKfd1Witness,
7
+ createBuildchainKfd2Claims,
8
+ createBuildchainKfd3ArtifactWitness,
9
+ createBuildchainKfd3PrebuildWitness,
10
+ createBuildchainKfdClaimRegistry,
11
+ createBuildchainKfdSurfaceRegistry,
12
+ createBuildchainPublicClaimDefinitions,
13
+ } from "./buildchain-kfd-claims.js";
14
+ import {
15
+ migrateBuildchainLayout,
16
+ planBuildchainLayoutMigration,
17
+ resolveBuildchainConfigPath,
18
+ resolveBuildchainContractLockPath,
19
+ resolveKfd3SurfaceRegistryPath,
20
+ resolveReleasePassportPath,
21
+ } from "./buildchain-layout.js";
22
+ import {
23
+ createKfd1ReleaseGateEvidence,
24
+ createKfd3CollaborationInterfaceReleaseGateEvidence,
25
+ normalizeKfd1ContractWorldWitness,
26
+ normalizeKfd3CollaborationInterfaceArtifactWitness,
27
+ normalizeKfd3CollaborationInterfacePrebuildWitness,
28
+ resolveKfd1Metadata,
29
+ resolveKfd2Metadata,
30
+ resolveKfd3Metadata,
31
+ validateKfd1ReleaseGateEvidence,
32
+ validateKfd2TrustTaxonomyEntry,
33
+ validateKfd3CollaborationInterfaceReleaseGateEvidence,
34
+ } from "./kfd-gate.js";
35
+ import {
36
+ auditKfd3Surfaces,
37
+ createKfd3SurfaceWitness,
38
+ detectKfd3Surfaces,
39
+ queryKfd3Capabilities,
40
+ readKfd3SurfaceRegistry,
41
+ registerKfd3Surfaces,
42
+ writeKfd3SurfaceRegistry,
43
+ } from "./kfd3-surface-register.js";
44
+
45
+ const require = createRequire(import.meta.url);
46
+
47
+ function readJsonPackageExport(exportPath) {
48
+ return JSON.parse(fs.readFileSync(require.resolve(exportPath), "utf8"));
49
+ }
50
+
51
+ function readJsonFile(filePath) {
52
+ return JSON.parse(fs.readFileSync(filePath, "utf8"));
53
+ }
54
+
55
+ function readJsonInput(value, { cwd = process.cwd(), label = "json" } = {}) {
56
+ const input = String(value || "").trim();
57
+ if (!input) {
58
+ throw new Error(`${label} is required`);
59
+ }
60
+ const filePath = path.isAbsolute(input) ? input : path.join(cwd, input);
61
+ if (fs.existsSync(filePath)) {
62
+ return readJsonFile(filePath);
63
+ }
64
+ return JSON.parse(input);
65
+ }
66
+
67
+ function readJsonInputs(values = [], { cwd = process.cwd(), label = "json" } = {}) {
68
+ return values.map((value, index) => readJsonInput(value, { cwd, label: `${label}[${index}]` }));
69
+ }
70
+
71
+ export function normalizeKfdStandardId(value) {
72
+ const raw = String(value || "").trim().toLowerCase();
73
+ const match = raw.match(/^(?:kfd[-\s]?)?([1-9][0-9]*)$/);
74
+ if (!match) {
75
+ throw new Error(`unsupported KFD standard: ${value}`);
76
+ }
77
+ return `kfd-${match[1]}`;
78
+ }
79
+
80
+ export function discoverKfdStandards() {
81
+ const packageJson = readJsonPackageExport("@kungfu-tech/kfd/package.json");
82
+ const standards = readJsonPackageExport("@kungfu-tech/kfd/standards.json");
83
+ return {
84
+ schemaVersion: 1,
85
+ contract: "kungfu-buildchain-kfd-standard-discovery",
86
+ package: {
87
+ name: packageJson.name,
88
+ version: packageJson.version,
89
+ repository: packageJson.repository?.url || "",
90
+ },
91
+ metadataSchema: standards.metadataSchema || {},
92
+ source: standards.source || {},
93
+ standards: Object.entries(standards.standards || {})
94
+ .map(([key, value]) => ({
95
+ key: value?.key || key,
96
+ id: value?.id || value?.label || key,
97
+ label: value?.label || value?.id || key,
98
+ title: value?.title || "",
99
+ status: value?.status || "",
100
+ revision: value?.revision || 0,
101
+ schemaIds: { ...(value?.schemaIds || {}) },
102
+ schemaPaths: { ...(value?.schemaPaths || {}) },
103
+ }))
104
+ .sort((a, b) => a.key.localeCompare(b.key)),
105
+ };
106
+ }
107
+
108
+ export function listKfdSchemas({ standard = "" } = {}) {
109
+ const discovery = discoverKfdStandards();
110
+ const selectedStandard = standard ? normalizeKfdStandardId(standard) : "";
111
+ const schemas = [];
112
+ for (const entry of discovery.standards) {
113
+ if (selectedStandard && normalizeKfdStandardId(entry.key) !== selectedStandard) continue;
114
+ const names = [...new Set([
115
+ ...Object.keys(entry.schemaIds || {}),
116
+ ...Object.keys(entry.schemaPaths || {}),
117
+ ])].sort();
118
+ for (const name of names) {
119
+ schemas.push({
120
+ standard: entry.key,
121
+ name,
122
+ schemaId: entry.schemaIds?.[name] || "",
123
+ schemaPath: entry.schemaPaths?.[name] || "",
124
+ });
125
+ }
126
+ }
127
+ return {
128
+ schemaVersion: 1,
129
+ contract: "kungfu-buildchain-kfd-schema-list",
130
+ package: discovery.package,
131
+ standard: selectedStandard || "",
132
+ schemas,
133
+ };
134
+ }
135
+
136
+ export function readKfdSchema({ standard, schema = "" } = {}) {
137
+ const selectedStandard = normalizeKfdStandardId(standard);
138
+ const schemaList = listKfdSchemas({ standard: selectedStandard }).schemas;
139
+ const selectedSchema = schema
140
+ ? schemaList.find((entry) => entry.name === schema || entry.schemaId === schema || entry.schemaPath === schema)
141
+ : schemaList[0];
142
+ if (!selectedSchema?.schemaPath) {
143
+ throw new Error(`KFD schema not found for ${selectedStandard}${schema ? `:${schema}` : ""}`);
144
+ }
145
+ return {
146
+ schemaVersion: 1,
147
+ contract: "kungfu-buildchain-kfd-schema",
148
+ standard: selectedStandard,
149
+ name: selectedSchema.name,
150
+ schemaId: selectedSchema.schemaId,
151
+ schemaPath: selectedSchema.schemaPath,
152
+ schema: readJsonPackageExport(`@kungfu-tech/kfd/${selectedSchema.schemaPath}`),
153
+ };
154
+ }
155
+
156
+ export const schemas = Object.freeze({
157
+ discover: discoverKfdStandards,
158
+ list: listKfdSchemas,
159
+ read: readKfdSchema,
160
+ });
161
+
162
+ export const kfd1 = Object.freeze({
163
+ resolveMetadata: resolveKfd1Metadata,
164
+ normalizeContractWorldWitness: normalizeKfd1ContractWorldWitness,
165
+ createReleaseGateEvidence: createKfd1ReleaseGateEvidence,
166
+ validateReleaseGateEvidence: validateKfd1ReleaseGateEvidence,
167
+ createBuildchainWitness: createBuildchainKfd1Witness,
168
+ createGate: ({ cwd = process.cwd(), witnessJsons = [], artifactRoot = "", artifacts = [] } = {}) => createKfd1ReleaseGateEvidence({
169
+ cwd,
170
+ artifactRoot,
171
+ artifacts,
172
+ witnesses: readJsonInputs(witnessJsons, { cwd, label: "kfd-1 witness" }),
173
+ }),
174
+ validateGate: (section) => validateKfd1ReleaseGateEvidence(section),
175
+ });
176
+
177
+ export const kfd2 = Object.freeze({
178
+ resolveMetadata: resolveKfd2Metadata,
179
+ validateTrustTaxonomyEntry: validateKfd2TrustTaxonomyEntry,
180
+ createBuildchainClaims: createBuildchainKfd2Claims,
181
+ createBuildchainPublicClaimDefinitions,
182
+ validateTaxonomyEntries: ({ entries = [], kind = "residualRisk" } = {}) => entries.map((entry, index) => validateKfd2TrustTaxonomyEntry(entry, {
183
+ kind,
184
+ label: `${kind}[${index}]`,
185
+ })),
186
+ });
187
+
188
+ export const kfd3 = Object.freeze({
189
+ resolveMetadata: resolveKfd3Metadata,
190
+ normalizePrebuildWitness: normalizeKfd3CollaborationInterfacePrebuildWitness,
191
+ normalizeArtifactWitness: normalizeKfd3CollaborationInterfaceArtifactWitness,
192
+ createReleaseGateEvidence: createKfd3CollaborationInterfaceReleaseGateEvidence,
193
+ validateReleaseGateEvidence: validateKfd3CollaborationInterfaceReleaseGateEvidence,
194
+ detectSurfaces: detectKfd3Surfaces,
195
+ registerSurfaces: registerKfd3Surfaces,
196
+ auditSurfaces: auditKfd3Surfaces,
197
+ createSurfaceWitness: createKfd3SurfaceWitness,
198
+ queryCapabilities: queryKfd3Capabilities,
199
+ readSurfaceRegistry: readKfd3SurfaceRegistry,
200
+ writeSurfaceRegistry: writeKfd3SurfaceRegistry,
201
+ createBuildchainPrebuildWitness: createBuildchainKfd3PrebuildWitness,
202
+ createBuildchainArtifactWitness: createBuildchainKfd3ArtifactWitness,
203
+ createBuildchainSurfaceRegistry: createBuildchainKfdSurfaceRegistry,
204
+ });
205
+
206
+ export const kfd4 = Object.freeze({
207
+ schemas: {
208
+ list: (options = {}) => listKfdSchemas({ ...options, standard: "kfd-4" }),
209
+ read: (options = {}) => readKfdSchema({ ...options, standard: "kfd-4" }),
210
+ },
211
+ status: "schema-only",
212
+ });
213
+
214
+ export const buildchainKfdClaims = Object.freeze({
215
+ createClaimRegistry: createBuildchainKfdClaimRegistry,
216
+ createSurfaceRegistry: createBuildchainKfdSurfaceRegistry,
217
+ createPublicClaimDefinitions: createBuildchainPublicClaimDefinitions,
218
+ });
219
+
220
+ export function collectKfdStatus({ cwd = process.cwd() } = {}) {
221
+ const resolvedCwd = path.resolve(cwd);
222
+ const schemas = listKfdSchemas();
223
+ const layout = planBuildchainLayoutMigration({ cwd: resolvedCwd });
224
+ const paths = {
225
+ config: resolveBuildchainConfigPath(resolvedCwd),
226
+ contractLock: resolveBuildchainContractLockPath(resolvedCwd),
227
+ kfd3SurfaceRegistry: resolveKfd3SurfaceRegistryPath(resolvedCwd),
228
+ releasePassport: resolveReleasePassportPath(resolvedCwd),
229
+ };
230
+ const pathStatus = Object.fromEntries(Object.entries(paths).map(([key, relPath]) => [
231
+ key,
232
+ {
233
+ path: relPath,
234
+ exists: fs.existsSync(path.join(resolvedCwd, relPath)),
235
+ },
236
+ ]));
237
+ return {
238
+ schemaVersion: 1,
239
+ contract: "kungfu-buildchain-kfd-status",
240
+ cwd: resolvedCwd,
241
+ layout: {
242
+ status: layout.status,
243
+ canonicalRoot: layout.canonicalRoot,
244
+ migrationNeeded: layout.moves.length > 0,
245
+ moves: layout.moves,
246
+ },
247
+ standards: schemas.schemas.reduce((acc, entry) => {
248
+ acc[entry.standard] ||= [];
249
+ acc[entry.standard].push({
250
+ name: entry.name,
251
+ schemaId: entry.schemaId,
252
+ schemaPath: entry.schemaPath,
253
+ });
254
+ return acc;
255
+ }, {}),
256
+ support: {
257
+ "kfd-1": ["schema", "witness", "gate", "verify"],
258
+ "kfd-2": ["schema", "taxonomy", "claims"],
259
+ "kfd-3": ["schema", "detect", "register", "audit", "witness", "query"],
260
+ "kfd-4": ["schema"],
261
+ },
262
+ paths: pathStatus,
263
+ };
264
+ }
265
+
266
+ export const layout = Object.freeze({
267
+ plan: planBuildchainLayoutMigration,
268
+ migrate: migrateBuildchainLayout,
269
+ resolveConfigPath: resolveBuildchainConfigPath,
270
+ resolveContractLockPath: resolveBuildchainContractLockPath,
271
+ resolveKfd3SurfaceRegistryPath,
272
+ resolveReleasePassportPath,
273
+ });
@@ -1,12 +1,13 @@
1
1
  import crypto from "node:crypto";
2
2
  import fs from "node:fs";
3
3
  import path from "node:path";
4
+ import { resolveKfd3SurfaceRegistryPath } from "./buildchain-layout.js";
4
5
 
5
6
  export const KFD3_SURFACE_REGISTRY_CONTRACT = "kungfu-buildchain-kfd-3-surface-registry";
6
7
  export const KFD3_SURFACE_DETECTION_CONTRACT = "kungfu-buildchain-kfd-3-surface-detection";
7
8
  export const KFD3_SURFACE_AUDIT_CONTRACT = "kungfu-buildchain-kfd-3-surface-audit";
8
9
  export const KFD3_CAPABILITY_QUERY_CONTRACT = "kungfu-buildchain-kfd-3-capability-query";
9
- export const KFD3_DEFAULT_REGISTRY_PATH = "buildchain.kfd3.json";
10
+ export const KFD3_DEFAULT_REGISTRY_PATH = ".buildchain/kfd/kfd-3-surfaces.json";
10
11
 
11
12
  const KIND_ALIASES = Object.freeze({
12
13
  "node-api": "node-api",
@@ -343,15 +344,20 @@ export function detectKfd3Surfaces({ cwd = process.cwd(), kinds = [], artifactPa
343
344
  };
344
345
  }
345
346
 
346
- export function readKfd3SurfaceRegistry({ cwd = process.cwd(), registryPath = KFD3_DEFAULT_REGISTRY_PATH } = {}) {
347
- const filePath = path.resolve(cwd, registryPath);
347
+ function resolveRegistryPath(cwd, registryPath) {
348
+ return registryPath || resolveKfd3SurfaceRegistryPath(cwd);
349
+ }
350
+
351
+ export function readKfd3SurfaceRegistry({ cwd = process.cwd(), registryPath = "" } = {}) {
352
+ const effectiveRegistryPath = resolveRegistryPath(cwd, registryPath);
353
+ const filePath = path.resolve(cwd, effectiveRegistryPath);
348
354
  const registry = readJsonFile(filePath, null);
349
355
  if (!registry) {
350
356
  return {
351
357
  schemaVersion: 1,
352
358
  contract: KFD3_SURFACE_REGISTRY_CONTRACT,
353
359
  product: {},
354
- registryPath,
360
+ registryPath: effectiveRegistryPath,
355
361
  surfaces: [],
356
362
  };
357
363
  }
@@ -359,24 +365,25 @@ export function readKfd3SurfaceRegistry({ cwd = process.cwd(), registryPath = KF
359
365
  schemaVersion: registry.schemaVersion || 1,
360
366
  contract: registry.contract || KFD3_SURFACE_REGISTRY_CONTRACT,
361
367
  product: registry.product || {},
362
- registryPath,
368
+ registryPath: registry.registryPath || effectiveRegistryPath,
363
369
  surfaces: Array.isArray(registry.surfaces) ? registry.surfaces : [],
364
370
  policy: registry.policy || {},
365
371
  };
366
372
  }
367
373
 
368
- export function writeKfd3SurfaceRegistry({ cwd = process.cwd(), registryPath = KFD3_DEFAULT_REGISTRY_PATH, registry }) {
374
+ export function writeKfd3SurfaceRegistry({ cwd = process.cwd(), registryPath = "", registry }) {
375
+ const effectiveRegistryPath = resolveRegistryPath(cwd, registryPath);
369
376
  const next = {
370
377
  schemaVersion: 1,
371
378
  contract: KFD3_SURFACE_REGISTRY_CONTRACT,
372
379
  product: registry.product || {},
373
- registryPath,
380
+ registryPath: effectiveRegistryPath,
374
381
  surfaces: uniqueSurfaces(registry.surfaces || []).map((entry) => ({
375
382
  ...entry,
376
383
  state: entry.state || "declared",
377
384
  declaration: entry.declaration || {
378
385
  owner: "product",
379
- source: "buildchain kfd-3 register",
386
+ source: "buildchain kfd 3 register",
380
387
  },
381
388
  })),
382
389
  policy: registry.policy || {
@@ -384,13 +391,13 @@ export function writeKfd3SurfaceRegistry({ cwd = process.cwd(), registryPath = K
384
391
  declaredButMissing: "fail",
385
392
  },
386
393
  };
387
- writeJsonFile(path.resolve(cwd, registryPath), next);
394
+ writeJsonFile(path.resolve(cwd, effectiveRegistryPath), next);
388
395
  return next;
389
396
  }
390
397
 
391
398
  export function registerKfd3Surfaces({
392
399
  cwd = process.cwd(),
393
- registryPath = KFD3_DEFAULT_REGISTRY_PATH,
400
+ registryPath = "",
394
401
  kinds = [],
395
402
  artifactPath = "",
396
403
  product = {},
@@ -435,7 +442,7 @@ export function registerKfd3Surfaces({
435
442
 
436
443
  export function auditKfd3Surfaces({
437
444
  cwd = process.cwd(),
438
- registryPath = KFD3_DEFAULT_REGISTRY_PATH,
445
+ registryPath = "",
439
446
  kinds = [],
440
447
  artifactPath = "",
441
448
  } = {}) {
@@ -490,7 +497,7 @@ export function auditKfd3Surfaces({
490
497
 
491
498
  export function createKfd3SurfaceWitness({
492
499
  cwd = process.cwd(),
493
- registryPath = KFD3_DEFAULT_REGISTRY_PATH,
500
+ registryPath = "",
494
501
  kind = "prebuild",
495
502
  sourceSha = "",
496
503
  artifactPath = "",
@@ -613,7 +620,7 @@ function capabilitiesFromRegistry({ registry, audit, passport = null }) {
613
620
  export async function queryKfd3Capabilities({
614
621
  cwd = process.cwd(),
615
622
  product = "",
616
- registryPath = KFD3_DEFAULT_REGISTRY_PATH,
623
+ registryPath = "",
617
624
  passportLocation = "",
618
625
  artifactPath = "",
619
626
  } = {}) {
@@ -649,15 +656,16 @@ export async function queryKfd3Capabilities({
649
656
  };
650
657
  }
651
658
 
652
- const registry = readKfd3SurfaceRegistry({ cwd, registryPath });
653
- const hasRegistry = fs.existsSync(path.resolve(cwd, registryPath));
654
- const audit = hasRegistry ? auditKfd3Surfaces({ cwd, registryPath, artifactPath }) : null;
659
+ const effectiveRegistryPath = resolveRegistryPath(cwd, registryPath);
660
+ const registry = readKfd3SurfaceRegistry({ cwd, registryPath: effectiveRegistryPath });
661
+ const hasRegistry = fs.existsSync(path.resolve(cwd, effectiveRegistryPath));
662
+ const audit = hasRegistry ? auditKfd3Surfaces({ cwd, registryPath: effectiveRegistryPath, artifactPath }) : null;
655
663
  if (hasRegistry) {
656
664
  return {
657
665
  schemaVersion: 1,
658
666
  contract: KFD3_CAPABILITY_QUERY_CONTRACT,
659
667
  product: product || registry.product?.name || registry.product?.id || "local-product",
660
- source: { type: "surface-registry", path: registryPath },
668
+ source: { type: "surface-registry", path: effectiveRegistryPath },
661
669
  status: audit.status,
662
670
  summary: audit.summary,
663
671
  capabilities: capabilitiesFromRegistry({ registry, audit }),