@kungfu-tech/buildchain 3.0.9-alpha.2 → 3.0.9-alpha.4

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 (50) hide show
  1. package/contracts/fixtures/next-development-transition-v1/anchored-manual-waiting.json +47 -0
  2. package/contracts/fixtures/next-development-transition-v1/semver-auto-planned.json +47 -0
  3. package/contracts/fixtures/next-development-transition-v1/version-model-cases.json +40 -0
  4. package/contracts/next-development-request-v1.schema.json +66 -0
  5. package/contracts/next-development-transition-v1.schema.json +292 -0
  6. package/dist/site/buildchain-contract.json +4 -4
  7. package/dist/site/buildchain-site.json +89 -18
  8. package/dist/site/capability-registry.json +4 -3
  9. package/dist/site/kfd-claims.json +65 -5
  10. package/dist/site/kfd-upstream-aggregate.json +1 -1
  11. package/dist/site/manual-registry.json +19 -3
  12. package/dist/site/node-api-registry.json +1017 -37
  13. package/dist/site/page-registry.json +74 -11
  14. package/dist/site/public-surface-audit.json +7 -3
  15. package/dist/site/publication-registry.json +4 -4
  16. package/dist/site/release-provenance.json +3 -0
  17. package/dist/site/site-manifest.json +15 -7
  18. package/dist/site/workflow-registry.json +4 -4
  19. package/docs/MAP.md +2 -1
  20. package/docs/aws-us-elastic-runner-burst-plane.md +25 -3
  21. package/docs/dev-alpha-candidate-patrol.md +8 -0
  22. package/docs/next-development-transition.md +119 -0
  23. package/docs/node-api-reference.md +126 -73
  24. package/docs/versioning.md +1 -1
  25. package/package.json +8 -3
  26. package/packages/core/buildchain-agent-manuals.js +1 -0
  27. package/packages/core/channel-candidate.js +8 -0
  28. package/packages/core/channel-promotion-baseline.js +52 -0
  29. package/packages/core/dev-alpha-candidate-selection.js +10 -2
  30. package/packages/core/next-development-candidate-reservation.js +186 -0
  31. package/packages/core/next-development-controller.js +726 -0
  32. package/packages/core/next-development-projection.js +288 -0
  33. package/packages/core/next-development-transition.js +738 -0
  34. package/packages/core/paper-agent-entry.js +7 -4
  35. package/packages/core/paper.js +14 -7
  36. package/packages/core/release-passport-contract.js +1 -1
  37. package/scripts/aws-macos-jit-controller-core.mjs +109 -4
  38. package/scripts/aws-macos-jit-controller.mjs +71 -2
  39. package/scripts/aws-macos-jit-instance-rehydrate.mjs +260 -0
  40. package/scripts/aws-macos-jit-source-rebind.mjs +71 -14
  41. package/scripts/check-inventory.mjs +11 -0
  42. package/scripts/dev-alpha-candidate-patrol.mjs +22 -1
  43. package/scripts/generate-next-development-guidance.mjs +49 -0
  44. package/scripts/generate-site-bundle.mjs +2 -0
  45. package/scripts/init-repo.mjs +119 -62
  46. package/scripts/next-development-self-dogfood-harness.mjs +409 -0
  47. package/scripts/next-development-self-dogfood.mjs +532 -0
  48. package/scripts/next-development-transition.mjs +47 -0
  49. package/scripts/site-capability-metadata.mjs +3 -0
  50. package/scripts/stable-candidate-qualification.mjs +7 -7
@@ -28,7 +28,29 @@ function priorOwnershipPlan(plan) {
28
28
  };
29
29
  }
30
30
 
31
- function campaignRunsWithNoWork(plan) {
31
+ function assertRunMatchesPolicy(plan, run, jobs, jobCount, artifactCount) {
32
+ if (plan.github.priorRunPolicy === "unused") {
33
+ if (jobCount !== 0 || artifactCount !== 0) {
34
+ throw new Error(
35
+ `macOS campaign run ${run.id} already has jobs or artifacts`,
36
+ );
37
+ }
38
+ return;
39
+ }
40
+ if (
41
+ run.status !== "completed" ||
42
+ run.conclusion !== "failure" ||
43
+ jobCount === 0 ||
44
+ artifactCount === 0 ||
45
+ (jobs.jobs || []).some((job) => job.status !== "completed")
46
+ ) {
47
+ throw new Error(
48
+ `macOS campaign run ${run.id} is not a terminal failed run with retained evidence`,
49
+ );
50
+ }
51
+ }
52
+
53
+ function campaignRunReceipts(plan) {
32
54
  const branch = sourceRefName(plan.source.ref);
33
55
  const response = ghJson(
34
56
  [
@@ -68,19 +90,35 @@ function campaignRunsWithNoWork(plan) {
68
90
  const artifactCount = Number(
69
91
  artifacts.total_count || (artifacts.artifacts || []).length || 0,
70
92
  );
71
- if (jobCount !== 0 || artifactCount !== 0) {
72
- throw new Error(
73
- `macOS campaign run ${run.id} already has jobs or artifacts`,
74
- );
75
- }
93
+ assertRunMatchesPolicy(plan, run, jobs, jobCount, artifactCount);
76
94
  receipts.push({
77
95
  runId: String(run.id),
78
96
  status: String(run.status || "unknown"),
79
97
  conclusion: String(run.conclusion || ""),
80
98
  jobCount,
81
99
  artifactCount,
100
+ artifacts: (artifacts.artifacts || []).map((artifact) => ({
101
+ id: String(artifact.id),
102
+ name: String(artifact.name || ""),
103
+ sizeInBytes: Number(artifact.size_in_bytes || 0),
104
+ digest: String(artifact.digest || ""),
105
+ expired: artifact.expired === true,
106
+ })),
82
107
  });
83
108
  }
109
+ if (plan.github.priorRunPolicy === "terminal-failure") {
110
+ const observed = receipts
111
+ .map((receipt) => receipt.runId)
112
+ .sort((left, right) => Number(left) - Number(right));
113
+ if (
114
+ JSON.stringify(observed) !==
115
+ JSON.stringify(plan.github.terminalFailureRunIds)
116
+ ) {
117
+ throw new Error(
118
+ "macOS campaign terminal failed run inventory does not match the confirmed run ids",
119
+ );
120
+ }
121
+ }
84
122
  return receipts;
85
123
  }
86
124
 
@@ -286,7 +324,7 @@ function assertZeroCampaignResidue(plan, profile) {
286
324
  if (matchingRunners.length !== 0) {
287
325
  throw new Error("macOS campaign already has a registered JIT runner");
288
326
  }
289
- const evidenceObjectCounts = {};
327
+ const evidenceObjects = {};
290
328
  for (const sourceSha of [plan.previousSource.sha, plan.source.sha]) {
291
329
  const evidence = awsJson(
292
330
  plan,
@@ -299,27 +337,43 @@ function assertZeroCampaignResidue(plan, profile) {
299
337
  "--prefix",
300
338
  `macos/${sourceSha}/`,
301
339
  "--max-keys",
302
- "1",
340
+ "1000",
303
341
  "--output",
304
342
  "json",
305
343
  ],
306
344
  `macOS campaign evidence inventory for ${sourceSha}`,
307
345
  );
346
+ if (evidence.IsTruncated === true) {
347
+ throw new Error(
348
+ `macOS campaign source ${sourceSha} evidence inventory is incomplete`,
349
+ );
350
+ }
351
+ const objects = (evidence.Contents || []).map((object) => ({
352
+ key: String(object.Key || ""),
353
+ size: Number(object.Size || 0),
354
+ etag: String(object.ETag || ""),
355
+ }));
308
356
  const count = Number(
309
357
  evidence.KeyCount || (evidence.Contents || []).length || 0,
310
358
  );
311
- if (count !== 0) {
359
+ const previousTerminalEvidence =
360
+ sourceSha === plan.previousSource.sha &&
361
+ plan.github.priorRunPolicy === "terminal-failure";
362
+ if (
363
+ (!previousTerminalEvidence && count !== 0) ||
364
+ (previousTerminalEvidence && count === 0)
365
+ ) {
312
366
  throw new Error(
313
- `macOS campaign source ${sourceSha} already has bootstrap evidence`,
367
+ `macOS campaign source ${sourceSha} bootstrap evidence does not match the rebind policy`,
314
368
  );
315
369
  }
316
- evidenceObjectCounts[sourceSha] = count;
370
+ evidenceObjects[sourceSha] = objects;
317
371
  }
318
372
  return {
319
- priorRuns: campaignRunsWithNoWork(plan),
373
+ priorRuns: campaignRunReceipts(plan),
320
374
  jitParameterCount: parameters.length,
321
375
  runnerCount: matchingRunners.length,
322
- evidenceObjectCounts,
376
+ evidenceObjects,
323
377
  };
324
378
  }
325
379
 
@@ -480,7 +534,10 @@ export function executeMacosJitSourceRebind(plan, { profile = "" } = {}) {
480
534
  schemaVersion: 1,
481
535
  contract: AWS_MACOS_JIT_CONTROLLER_CONTRACT,
482
536
  kind: "campaign-source-rebind-result",
483
- status: "rebound-zero-allocation",
537
+ status:
538
+ plan.github.priorRunPolicy === "terminal-failure"
539
+ ? "rebound-after-terminal-failure-zero-allocation"
540
+ : "rebound-zero-allocation",
484
541
  repository: plan.repository,
485
542
  campaign: plan.campaign,
486
543
  previousSource: plan.previousSource,
@@ -53,6 +53,10 @@ const requiredPaths = [
53
53
  "packages/core/homebrew.js",
54
54
  "packages/core/artifact-verification-envelope.js",
55
55
  "packages/core/anchored-version-material.js",
56
+ "packages/core/next-development-transition.js",
57
+ "packages/core/next-development-controller.js",
58
+ "packages/core/next-development-candidate-reservation.js",
59
+ "packages/core/next-development-projection.js",
56
60
  "packages/core/build-facts.js",
57
61
  "packages/core/publication-package.js",
58
62
  "packages/core/publication-reproducibility.js",
@@ -75,6 +79,8 @@ const requiredPaths = [
75
79
  "docs/auditable-demo.md",
76
80
  "contracts/auditable-demo-scenario-v1.schema.json",
77
81
  "contracts/release-candidate-recovery-v1.schema.json",
82
+ "contracts/next-development-request-v1.schema.json",
83
+ "contracts/next-development-transition-v1.schema.json",
78
84
  "contracts/auditable-demo-media-profiles-v1.json",
79
85
  "contracts/evidence/auditable-demo-web-delivery-v1.json",
80
86
  "contracts/evidence/auditable-demo-responsive-web-delivery-v1.json",
@@ -86,10 +92,15 @@ const requiredPaths = [
86
92
  "contracts/fixtures/auditable-demo-responsive-web-delivery-v1/public-projection.json",
87
93
  "contracts/fixtures/auditable-demo-responsive-web-delivery-v1/scene.json",
88
94
  "docs/release-propagation.md",
95
+ "docs/next-development-transition.md",
89
96
  "docs/site-bundle-contract.md",
90
97
  "docs/toolkit-observability.md",
91
98
  "docs/versioning.md",
92
99
  "scripts/release-line-dry-run.mjs",
100
+ "scripts/next-development-transition.mjs",
101
+ "scripts/next-development-self-dogfood.mjs",
102
+ "scripts/next-development-self-dogfood-harness.mjs",
103
+ "scripts/generate-next-development-guidance.mjs",
93
104
  "scripts/reconcile-release-governance.mjs",
94
105
  "scripts/buildchain-channel-router.mjs",
95
106
  "scripts/generate-channel-build-workflow.mjs",
@@ -20,6 +20,7 @@ import {
20
20
  candidateFromDecision,
21
21
  selectLatestQualifiedSource,
22
22
  } from "../packages/core/dev-alpha-candidate-selection.js";
23
+ import { readGitHubNextDevelopmentVersionReservation } from "../packages/core/next-development-candidate-reservation.js";
23
24
 
24
25
  export { reconcileActiveReleaseTrain, selectLatestQualifiedSource };
25
26
 
@@ -617,6 +618,7 @@ export async function runDevAlphaCandidatePatrol(
617
618
  comparison,
618
619
  workflowEvidence,
619
620
  skippedNewerCommitCount,
621
+ versionReservation,
620
622
  qualificationError,
621
623
  } = await resolvePatrolSourceInputs({
622
624
  client,
@@ -646,6 +648,7 @@ export async function runDevAlphaCandidatePatrol(
646
648
  observedSourceHeadSha,
647
649
  skippedNewerCommitCount,
648
650
  ...(targetBaseline ? { targetBaseline } : {}),
651
+ ...(versionReservation ? { versionReservation } : {}),
649
652
  },
650
653
  workflowEvidence,
651
654
  requiredWorkflowPaths,
@@ -992,6 +995,20 @@ export function createGitHubChannelCandidateClient({
992
995
  targetBranch,
993
996
  parseCandidate: managedCandidateFromPullRequest,
994
997
  }),
998
+ async readNextDevelopmentVersionReservation({
999
+ reservationSha,
1000
+ candidateSha,
1001
+ targetVersion,
1002
+ }) {
1003
+ return readGitHubNextDevelopmentVersionReservation({
1004
+ api,
1005
+ owner,
1006
+ repo,
1007
+ reservationSha,
1008
+ candidateSha,
1009
+ targetVersion,
1010
+ });
1011
+ },
995
1012
  async listCompletedWorkflowRuns(workflowPathValue, sourceBranch) {
996
1013
  const runs = [];
997
1014
  for (let page = 1; page <= 10; page += 1) {
@@ -1015,7 +1032,11 @@ export function createGitHubChannelCandidateClient({
1015
1032
  for (const commit of rows) {
1016
1033
  const commitSha = text(commit.sha);
1017
1034
  if (commitSha === targetSha) return commits;
1018
- commits.push(commitSha);
1035
+ commits.push({
1036
+ sha: commitSha,
1037
+ message: text(commit.commit?.message),
1038
+ parents: (commit.parents || []).map((parent) => text(parent.sha)),
1039
+ });
1019
1040
  }
1020
1041
  if (rows.length < 100) return commits;
1021
1042
  }
@@ -0,0 +1,49 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from "node:fs";
4
+ import path from "node:path";
5
+ import { pathToFileURL } from "node:url";
6
+
7
+ import { nextDevelopmentManual } from "../packages/core/next-development-projection.js";
8
+
9
+ export const NEXT_DEVELOPMENT_MANUAL_PATH =
10
+ "docs/next-development-transition.md";
11
+
12
+ export function generateNextDevelopmentGuidance({
13
+ cwd = process.cwd(),
14
+ check = false,
15
+ } = {}) {
16
+ const target = path.resolve(cwd, NEXT_DEVELOPMENT_MANUAL_PATH);
17
+ const expected = nextDevelopmentManual();
18
+ const current = fs.existsSync(target) ? fs.readFileSync(target, "utf8") : "";
19
+ if (check) {
20
+ if (current !== expected) {
21
+ throw new Error(
22
+ `${NEXT_DEVELOPMENT_MANUAL_PATH} drifted from its contract source`,
23
+ );
24
+ }
25
+ return { ok: true, changed: false, path: NEXT_DEVELOPMENT_MANUAL_PATH };
26
+ }
27
+ fs.mkdirSync(path.dirname(target), { recursive: true });
28
+ if (current !== expected) fs.writeFileSync(target, expected);
29
+ return {
30
+ ok: true,
31
+ changed: current !== expected,
32
+ path: NEXT_DEVELOPMENT_MANUAL_PATH,
33
+ };
34
+ }
35
+
36
+ if (
37
+ process.argv[1] &&
38
+ import.meta.url === pathToFileURL(process.argv[1]).href
39
+ ) {
40
+ try {
41
+ const result = generateNextDevelopmentGuidance({
42
+ check: process.argv.includes("--check"),
43
+ });
44
+ process.stdout.write(`${JSON.stringify(result)}\n`);
45
+ } catch (error) {
46
+ process.stderr.write(`next-development guidance: ${error.message}\n`);
47
+ process.exitCode = 1;
48
+ }
49
+ }
@@ -368,6 +368,7 @@ const manualMetaById = new Map(Object.entries({
368
368
  "release-activation-transaction": { capabilityGroup: "release-passport-trust", audience: ["release-operator", "agent"], maturity: "preview", order: 125 },
369
369
  "release-candidate": { capabilityGroup: "reusable-build", audience: ["release-operator", "consumer"], maturity: "stable", order: 130 },
370
370
  "release-train": { capabilityGroup: "governance-versioning", audience: ["release-operator", "consumer", "agent"], maturity: "preview", order: 132 },
371
+ "next-development-transition": { capabilityGroup: "governance-versioning", audience: ["release-operator", "consumer", "agent"], maturity: "preview", order: 133 },
371
372
  "stable-candidate-patrol": { capabilityGroup: "governance-versioning", audience: ["release-operator", "consumer"], maturity: "preview", order: 135 },
372
373
  "dev-qualification-patrol": { capabilityGroup: "governance-versioning", audience: ["release-operator", "consumer", "agent"], maturity: "preview", order: 136 },
373
374
  "dev-alpha-candidate-patrol": { capabilityGroup: "governance-versioning", audience: ["release-operator", "consumer", "agent"], maturity: "preview", order: 137 },
@@ -733,6 +734,7 @@ function buildSiteBundle() {
733
734
  "docs/reusable-build-surface.md",
734
735
  "docs/release-candidate.md",
735
736
  "docs/release-train.md",
737
+ "docs/next-development-transition.md",
736
738
  "docs/stable-candidate-patrol.md",
737
739
  "docs/dev-qualification-patrol.md",
738
740
  "docs/dev-alpha-candidate-patrol.md",
@@ -3,21 +3,35 @@ import fs from "node:fs";
3
3
  import path from "node:path";
4
4
  import { pathToFileURL } from "node:url";
5
5
  import { BUILDCHAIN_CONFIG_PATH } from "../packages/core/buildchain-layout.js";
6
- import { detectPackageManager, assertPackageManager } from "../packages/core/package-manager.js";
6
+ import {
7
+ detectPackageManager,
8
+ assertPackageManager,
9
+ } from "../packages/core/package-manager.js";
7
10
  import {
8
11
  PUBLICATION_REHEARSAL_WORKFLOW_PATH,
9
12
  appendPublicationRehearsalToml,
10
13
  mergePublicationRehearsalAgentInstructions,
11
14
  publicationRehearsalWorkflow,
12
15
  } from "../packages/core/publication-rehearsal-projection.js";
13
-
14
- const BUILDCHAIN_WORKFLOW_REF = "kungfu-systems/buildchain/.github/workflows/.build.yml@v3";
15
- const DEFAULT_PUBLICATION_LATEX_IMAGE = "ghcr.io/kungfu-systems/build-images/latex-pdf-builder";
16
- const DEFAULT_PUBLICATION_LATEX_DIGEST = "sha256:c20f3809e96836c1c78e97c76939d12f1de3fed0ea9b7c40c43332ec2ea480f8";
17
- const DEFAULT_PUBLICATION_LATEX_COMMAND = "latexmk -pdf -outdir=_build paper/main.tex";
16
+ import {
17
+ appendNextDevelopmentToml,
18
+ mergeNextDevelopmentAgentInstructions,
19
+ nextDevelopmentWorkflowHeader,
20
+ } from "../packages/core/next-development-projection.js";
21
+
22
+ const BUILDCHAIN_WORKFLOW_REF =
23
+ "kungfu-systems/buildchain/.github/workflows/.build.yml@v3";
24
+ const DEFAULT_PUBLICATION_LATEX_IMAGE =
25
+ "ghcr.io/kungfu-systems/build-images/latex-pdf-builder";
26
+ const DEFAULT_PUBLICATION_LATEX_DIGEST =
27
+ "sha256:c20f3809e96836c1c78e97c76939d12f1de3fed0ea9b7c40c43332ec2ea480f8";
28
+ const DEFAULT_PUBLICATION_LATEX_COMMAND =
29
+ "latexmk -pdf -outdir=_build paper/main.tex";
18
30
 
19
31
  function posixPath(value) {
20
- return String(value || "").split(path.sep).join("/");
32
+ return String(value || "")
33
+ .split(path.sep)
34
+ .join("/");
21
35
  }
22
36
 
23
37
  function repoName(cwd) {
@@ -282,34 +296,42 @@ command = "make check"
282
296
  }
283
297
 
284
298
  function infraContractDesiredJson(cwd) {
285
- return `${JSON.stringify({
286
- service: repoName(cwd),
287
- environment: "staging",
288
- resources: [
289
- {
290
- kind: "static-site",
291
- name: repoName(cwd),
292
- desiredState: {
293
- hostname: "staging.example.com",
294
- accessControl: "managed-network",
295
- owner: "platform",
299
+ return `${JSON.stringify(
300
+ {
301
+ service: repoName(cwd),
302
+ environment: "staging",
303
+ resources: [
304
+ {
305
+ kind: "static-site",
306
+ name: repoName(cwd),
307
+ desiredState: {
308
+ hostname: "staging.example.com",
309
+ accessControl: "managed-network",
310
+ owner: "platform",
311
+ },
296
312
  },
297
- },
298
- ],
299
- }, null, 2)}\n`;
313
+ ],
314
+ },
315
+ null,
316
+ 2,
317
+ )}\n`;
300
318
  }
301
319
 
302
320
  function infraContractOutputsJson(cwd) {
303
- return `${JSON.stringify({
304
- service: repoName(cwd),
305
- environment: "staging",
306
- observedMode: "manual-observed",
307
- outputs: {
308
- hostname: "staging.example.com",
309
- distributionId: "observed-distribution-id",
310
- bucket: "observed-bucket-name",
321
+ return `${JSON.stringify(
322
+ {
323
+ service: repoName(cwd),
324
+ environment: "staging",
325
+ observedMode: "manual-observed",
326
+ outputs: {
327
+ hostname: "staging.example.com",
328
+ distributionId: "observed-distribution-id",
329
+ bucket: "observed-bucket-name",
330
+ },
311
331
  },
312
- }, null, 2)}\n`;
332
+ null,
333
+ 2,
334
+ )}\n`;
313
335
  }
314
336
 
315
337
  function workflowArtifactPaths(type) {
@@ -333,7 +355,7 @@ function workflowArtifactPaths(type) {
333
355
  }
334
356
 
335
357
  function publicationWorkflowYaml() {
336
- return `name: Build
358
+ return `${nextDevelopmentWorkflowHeader()}name: Build
337
359
 
338
360
  on:
339
361
  workflow_dispatch:
@@ -365,7 +387,7 @@ jobs:
365
387
  }
366
388
 
367
389
  function workflowYaml({ type, runnerPreset, artifactName }) {
368
- return `name: Build
390
+ return `${nextDevelopmentWorkflowHeader()}name: Build
369
391
 
370
392
  on:
371
393
  workflow_dispatch:
@@ -400,7 +422,9 @@ jobs:
400
422
 
401
423
  function writeIfAllowed(filePath, content, { force }) {
402
424
  if (fs.existsSync(filePath) && !force) {
403
- throw new Error(`${posixPath(filePath)} already exists; pass --force to overwrite`);
425
+ throw new Error(
426
+ `${posixPath(filePath)} already exists; pass --force to overwrite`,
427
+ );
404
428
  }
405
429
  fs.mkdirSync(path.dirname(filePath), { recursive: true });
406
430
  fs.writeFileSync(filePath, content);
@@ -408,7 +432,9 @@ function writeIfAllowed(filePath, content, { force }) {
408
432
  }
409
433
 
410
434
  function writeManagedAgentEntry(filePath, current) {
411
- const content = mergePublicationRehearsalAgentInstructions(current);
435
+ const content = mergeNextDevelopmentAgentInstructions(
436
+ mergePublicationRehearsalAgentInstructions(current),
437
+ );
412
438
  fs.mkdirSync(path.dirname(filePath), { recursive: true });
413
439
  fs.writeFileSync(filePath, content);
414
440
  return filePath;
@@ -424,27 +450,33 @@ export function initBuildchainRepo({
424
450
  } = {}) {
425
451
  const resolvedCwd = path.resolve(cwd);
426
452
  const manager = detectOrDefaultPackageManager(resolvedCwd, packageManager);
427
- const toml = appendPublicationRehearsalToml((() => {
428
- if (type === "package") {
429
- return packageToml(resolvedCwd, manager);
430
- }
431
- if (type === "native") {
432
- return nativeToml(resolvedCwd);
433
- }
434
- if (type === "web-surface") {
435
- return webSurfaceToml(resolvedCwd);
436
- }
437
- if (type === "infra-contract") {
438
- return infraContractToml(resolvedCwd);
439
- }
440
- if (type === "publication-artifact") {
441
- return publicationArtifactToml(resolvedCwd);
442
- }
443
- if (type === "anchored-package") {
444
- return anchoredPackageToml(resolvedCwd, manager);
445
- }
446
- throw new Error("init --type must be one of package, native, web-surface, infra-contract, publication-artifact, or anchored-package");
447
- })());
453
+ const toml = appendNextDevelopmentToml(
454
+ appendPublicationRehearsalToml(
455
+ (() => {
456
+ if (type === "package") {
457
+ return packageToml(resolvedCwd, manager);
458
+ }
459
+ if (type === "native") {
460
+ return nativeToml(resolvedCwd);
461
+ }
462
+ if (type === "web-surface") {
463
+ return webSurfaceToml(resolvedCwd);
464
+ }
465
+ if (type === "infra-contract") {
466
+ return infraContractToml(resolvedCwd);
467
+ }
468
+ if (type === "publication-artifact") {
469
+ return publicationArtifactToml(resolvedCwd);
470
+ }
471
+ if (type === "anchored-package") {
472
+ return anchoredPackageToml(resolvedCwd, manager);
473
+ }
474
+ throw new Error(
475
+ "init --type must be one of package, native, web-surface, infra-contract, publication-artifact, or anchored-package",
476
+ );
477
+ })(),
478
+ ),
479
+ );
448
480
 
449
481
  const agentsPath = path.join(resolvedCwd, "AGENTS.md");
450
482
  const currentAgents = fs.existsSync(agentsPath)
@@ -452,7 +484,9 @@ export function initBuildchainRepo({
452
484
  : "";
453
485
 
454
486
  const written = [
455
- writeIfAllowed(path.join(resolvedCwd, BUILDCHAIN_CONFIG_PATH), toml, { force }),
487
+ writeIfAllowed(path.join(resolvedCwd, BUILDCHAIN_CONFIG_PATH), toml, {
488
+ force,
489
+ }),
456
490
  writeIfAllowed(
457
491
  path.join(resolvedCwd, ".github", "workflows", "build.yml"),
458
492
  type === "publication-artifact"
@@ -472,14 +506,31 @@ export function initBuildchainRepo({
472
506
  writeManagedAgentEntry(agentsPath, currentAgents),
473
507
  ];
474
508
 
475
- if (type === "anchored-package" && !fs.existsSync(path.join(resolvedCwd, "release.json"))) {
476
- written.push(writeIfAllowed(path.join(resolvedCwd, "release.json"), "{\n \"upstream\": \"\",\n \"version\": \"0.0.0\"\n}\n", { force }));
509
+ if (
510
+ type === "anchored-package" &&
511
+ !fs.existsSync(path.join(resolvedCwd, "release.json"))
512
+ ) {
513
+ written.push(
514
+ writeIfAllowed(
515
+ path.join(resolvedCwd, "release.json"),
516
+ '{\n "upstream": "",\n "version": "0.0.0"\n}\n',
517
+ { force },
518
+ ),
519
+ );
477
520
  }
478
521
 
479
522
  if (type === "infra-contract") {
480
523
  written.push(
481
- writeIfAllowed(path.join(resolvedCwd, "infra", "desired.json"), infraContractDesiredJson(resolvedCwd), { force }),
482
- writeIfAllowed(path.join(resolvedCwd, "infra", "outputs.json"), infraContractOutputsJson(resolvedCwd), { force }),
524
+ writeIfAllowed(
525
+ path.join(resolvedCwd, "infra", "desired.json"),
526
+ infraContractDesiredJson(resolvedCwd),
527
+ { force },
528
+ ),
529
+ writeIfAllowed(
530
+ path.join(resolvedCwd, "infra", "outputs.json"),
531
+ infraContractOutputsJson(resolvedCwd),
532
+ { force },
533
+ ),
483
534
  );
484
535
  }
485
536
 
@@ -489,7 +540,9 @@ export function initBuildchainRepo({
489
540
  cwd: resolvedCwd,
490
541
  packageManager: manager,
491
542
  workflowRef: BUILDCHAIN_WORKFLOW_REF,
492
- written: written.map((filePath) => posixPath(path.relative(resolvedCwd, filePath))),
543
+ written: written.map((filePath) =>
544
+ posixPath(path.relative(resolvedCwd, filePath)),
545
+ ),
493
546
  };
494
547
  }
495
548
 
@@ -501,7 +554,11 @@ function readArg(name, fallback = "") {
501
554
  return process.argv[index + 1] || "";
502
555
  }
503
556
 
504
- if (!process.env.BUILDCHAIN_EMBEDDED_ENTRYPOINT && process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
557
+ if (
558
+ !process.env.BUILDCHAIN_EMBEDDED_ENTRYPOINT &&
559
+ process.argv[1] &&
560
+ import.meta.url === pathToFileURL(process.argv[1]).href
561
+ ) {
505
562
  try {
506
563
  const result = initBuildchainRepo({
507
564
  cwd: readArg("cwd", process.cwd()),