@kungfu-tech/buildchain 0.0.0-bootstrap.0 → 2.0.13-alpha.10

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 (35) hide show
  1. package/README.md +262 -0
  2. package/bin/buildchain.mjs +222 -0
  3. package/docs/cli.md +124 -0
  4. package/docs/lifecycle-protocol.md +422 -0
  5. package/docs/publish-transaction.md +285 -0
  6. package/docs/reusable-build-surface.md +350 -0
  7. package/docs/web-surface-deployments.md +211 -0
  8. package/package.json +52 -1
  9. package/packages/core/README.md +15 -0
  10. package/packages/core/buildchain-config.js +721 -0
  11. package/packages/core/index.js +40 -0
  12. package/packages/core/package-manager.js +291 -0
  13. package/packages/core/publish-transaction.js +418 -0
  14. package/packages/core/release-line-dry-run.js +296 -0
  15. package/scripts/aggregate-build-summary.mjs +88 -0
  16. package/scripts/build-contract-core.mjs +731 -0
  17. package/scripts/check-inventory.mjs +325 -0
  18. package/scripts/init-repo.mjs +316 -0
  19. package/scripts/npm-publish-dry-run.mjs +176 -0
  20. package/scripts/npm-publish-transaction.mjs +268 -0
  21. package/scripts/publish-source-ref-resolver.mjs +113 -0
  22. package/scripts/release-line-dry-run.mjs +53 -0
  23. package/scripts/release-line-policy.mjs +141 -0
  24. package/scripts/release-transaction.mjs +212 -0
  25. package/scripts/resolve-build-contract.mjs +63 -0
  26. package/scripts/resolve-publish-gate.mjs +33 -0
  27. package/scripts/resolve-publish-source.mjs +99 -0
  28. package/scripts/run-lifecycle-core.mjs +162 -0
  29. package/scripts/run-lifecycle.mjs +40 -0
  30. package/scripts/strip-trailing-whitespace.mjs +14 -0
  31. package/scripts/tsup-action.config.mjs +19 -0
  32. package/scripts/verify-publish-source-lock.mjs +37 -0
  33. package/scripts/verify-release-pr.mjs +34 -0
  34. package/scripts/web-surface-core.mjs +382 -0
  35. package/scripts/web-surface.mjs +112 -0
package/README.md ADDED
@@ -0,0 +1,262 @@
1
+ # Kungfu Buildchain
2
+
3
+ Kungfu Buildchain is the v2 source of truth for Kungfu reusable GitHub
4
+ workflows, the minimal Buildchain-native GitHub Actions surface, and release-line
5
+ automation.
6
+
7
+ The repository does more than collect workflow files. Its main job is to make a
8
+ Kungfu release auditable and repeatable: a protected branch merge should produce
9
+ the right version commit, exact release tag, floating channel tag, and next
10
+ alpha line without a maintainer hand-moving refs or repairing package metadata
11
+ after the fact.
12
+
13
+ ## Why This Exists
14
+
15
+ Kungfu release automation has to solve a few problems at the same time:
16
+
17
+ - consumers need stable refs such as `v2`, `v2.0`, and `v2.0-alpha`;
18
+ - maintainers need exact immutable refs such as `v2.0.2` and
19
+ `v2.0.3-alpha.0` for audit and rollback;
20
+ - package manifests must record the same version that the release tag
21
+ advertises;
22
+ - alpha and release promotion must follow reviewed PRs, not local scripts or
23
+ manually edited tags;
24
+ - the release toolchain itself must be released by the same governance model
25
+ that it applies to product repositories.
26
+
27
+ The older ABV model solved this by treating a GitHub release PR as the release
28
+ intent. Buildchain v2 keeps that semantic contract, but implements it inside a
29
+ modern monorepo with Node 24 actions, pnpm, tsup bundles, committed `dist`
30
+ outputs, reusable workflow tests, package-manager adapters, and a TOML lifecycle
31
+ protocol for non-Node projects.
32
+
33
+ ## Mental Model
34
+
35
+ Buildchain release automation is branch-driven:
36
+
37
+ | Merge path | Meaning | Exact tag | Floating tags and branches |
38
+ | --- | --- | --- | --- |
39
+ | `dev/vX/vX.Y -> alpha/vX/vX.Y` | publish the next testable alpha for a minor line | `vX.Y.Z-alpha.N` | `vX.Y-alpha`, `alpha/vX/vX.Y`, `dev/vX/vX.Y` |
40
+ | `alpha/vX/vX.Y -> release/vX/vX.Y` | publish production for that minor line | `vX.Y.Z` | `vX.Y`, usually `vX`, `release/vX/vX.Y` |
41
+ | `release/vX/vX.Y -> publish-gate/major` | publish the next major from a reviewed production line | `v(X+1).0.0` | `v(X+1)`, `v(X+1).0`, `release/v(X+1)/v(X+1).0` |
42
+
43
+ After a production release, Buildchain prepares the next alpha source commit for
44
+ the same minor line and moves `dev/vX/vX.Y`, `alpha/vX/vX.Y`, and
45
+ `vX.Y-alpha` to that next prerelease state. This is why a release can leave the
46
+ production channel at `v2.0.2` while the test channel is already at
47
+ `v2.0.3-alpha.0`.
48
+
49
+ Kungfu treats minor lines as long-running product trains. `v2.0`, `v2.1`, and
50
+ future minor refs can each receive many patch releases such as `v2.0.1234`.
51
+ `v2` points at the selected stable major line, while `v2.0` points at the
52
+ latest production patch for that minor line.
53
+
54
+ `publish-gate/major` replaces the old ABV `main` channel. It is deliberately
55
+ not named `main` because it is not the active development trunk. Maintainers use
56
+ the same PR flow as other channel promotions: merging
57
+ `release/v2/v2.0 -> publish-gate/major` means "publish the next major line from
58
+ this production state." The promotion then creates the next major production
59
+ version, for example `v3.0.0`, and prepares `dev/v3/v3.0` plus
60
+ `alpha/v3/v3.0` at `v3.0.1-alpha.0`. The older `major-gate` branch name is only
61
+ a compatibility alias during migration.
62
+
63
+ Exact tags are always v-prefixed. Use `v2.0.0` and `v2.0.1-alpha.0`; bare tags
64
+ such as `1.0.0` are not maintained as Buildchain release entrypoints.
65
+
66
+ ## Repository Layout
67
+
68
+ ```text
69
+ .github/workflows/ Repository checks, reusable workflows, and release promotion
70
+ actions/ GitHub Actions implementations, grouped by action
71
+ fixtures/ Safe fixture repositories or fixture descriptors
72
+ packages/ Shared libraries, added only when justified
73
+ tests/ Inventory and contract data used by checks
74
+ docs/ Governance, migration, architecture, and rollback notes
75
+ scripts/ Local verification scripts
76
+ ```
77
+
78
+ ## Buildchain v2 Contract
79
+
80
+ Buildchain v2 ships these active surfaces:
81
+
82
+ - repository workflows under `.github/workflows`;
83
+ - the public npm package `@kungfu-tech/buildchain` and `buildchain` CLI for
84
+ initializing and validating new repositories;
85
+ - the active reusable build workflow `.github/workflows/.build.yml`;
86
+ - exactly three GitHub Actions under `actions/<name>`:
87
+ `validate-config`, `run-lifecycle`, and `promote-buildchain-ref`;
88
+ - action runtime on Node 24;
89
+ - workspace package management with pnpm;
90
+ - action bundling through tsup;
91
+ - committed `dist/index.js` bundles for direct GitHub Actions consumption;
92
+ - package-manager adapters for pnpm, npm, and yarn version-state updates;
93
+ - `buildchain.toml` lifecycle configuration for custom version files and
94
+ verification commands;
95
+ - `project.type = "web-surface"` configuration for site and app repositories
96
+ that need preview/staging/production deployment manifests and dry-run deploy
97
+ plans without package-release version semantics;
98
+ - opt-in anchored/manual version strategy for packages whose version is pinned
99
+ to an explicit upstream release instead of derived from the Buildchain tag;
100
+ - `actions/validate-config` migration preflight for TOML version-state and
101
+ lifecycle declarations without running heavyweight builds;
102
+ - `.github/workflows/.build.yml` as the reusable build surface for
103
+ tri-platform runner presets, custom runner matrices, caller-provided lifecycle
104
+ commands, trusted event gating, artifact name templates, expected artifact
105
+ checks, deterministic artifact manifests, publish-gate source locks, resolved
106
+ release manifests, and aggregate build summaries;
107
+ - `actions/run-lifecycle` for callers that need the same lifecycle/manifest
108
+ contract inside their own workflows;
109
+ - governance-closed self-promotion through `Buildchain Ref Promotion`.
110
+
111
+ Stable consumers should reference actions as:
112
+
113
+ ```yaml
114
+ uses: kungfu-systems/buildchain/actions/<name>@v2
115
+ ```
116
+
117
+ Documented reusable workflows should be referenced as:
118
+
119
+ ```yaml
120
+ uses: kungfu-systems/buildchain/.github/workflows/<workflow>.yml@v2
121
+ ```
122
+
123
+ Repositories can also bootstrap local integration through the CLI:
124
+
125
+ ```bash
126
+ npx @kungfu-tech/buildchain init --type package
127
+ npx @kungfu-tech/buildchain validate --require-version-state
128
+ npx @kungfu-tech/buildchain release --dry-run --target-ref alpha/v2/v2.0
129
+ npx @kungfu-tech/buildchain npm dry-run --json
130
+ ```
131
+
132
+ Standalone `workflows` and `action-*` repositories are historical rollback
133
+ anchors. Buildchain no longer ships migrated copies of legacy action
134
+ repositories.
135
+
136
+ Some hidden reusable workflow files from the old `workflows` repository still
137
+ exist in this repository so they can be linted, audited, and made fail-closed
138
+ while consumers migrate. They are not Buildchain-native release or publish
139
+ surfaces unless this README or a dedicated document explicitly names them.
140
+ Modern package, artifact, and publish integrations should use `.build.yml`,
141
+ `buildchain.toml`, lifecycle commands, and publish transaction evidence instead
142
+ of retired legacy action paths.
143
+
144
+ ## Release Governance
145
+
146
+ Buildchain promotes its own release refs through
147
+ `.github/workflows/buildchain-ref-promotion.yml` and
148
+ `actions/promote-buildchain-ref`.
149
+
150
+ The important constraints are:
151
+
152
+ - non-dry-run promotion is not available from manual dispatch;
153
+ - promotion must be backed by a protected same-repository PR channel path;
154
+ - protected channel details must be readable and must enforce protection for
155
+ administrators;
156
+ - alpha promotion must come from `dev/vX/vX.Y -> alpha/vX/vX.Y`;
157
+ - release promotion must come from `alpha/vX/vX.Y -> release/vX/vX.Y`;
158
+ - major promotion must come from `release/vX/vX.Y -> publish-gate/major`;
159
+ - release promotion must match an existing same-patch alpha tag tree;
160
+ - generated version-state commits must pass the configured verification command
161
+ before refs move;
162
+ - `BUILDCHAIN_PROMOTION_TOKEN` is the release authority used to move protected
163
+ refs when repository policy requires it.
164
+
165
+ Buildchain's top-level `Release - New Version` workflow is intentionally a
166
+ no-op for this repository. Buildchain itself is promoted only by
167
+ `Buildchain Ref Promotion` after `Verify` succeeds. The legacy hidden
168
+ `.release-new-version.yml` file is not the modern publish surface; it remains a
169
+ migration boundary for old consumers and must not be used for new Buildchain v2
170
+ integrations.
171
+
172
+ Buildchain's npm package is published by the same promotion transaction that
173
+ creates exact v-prefixed release tags. Alpha releases such as
174
+ `v2.0.13-alpha.0` publish to npm with dist-tag `alpha`; stable releases such as
175
+ `v2.0.13` publish with dist-tag `latest`. Floating refs like `v2`, `v2.0`, and
176
+ `v2.0-alpha` never publish npm packages. The old tag-push npm workflow is
177
+ dry-run only; real npm publish happens before public release refs move, using
178
+ the evidence contract in `lifecycle.publish`.
179
+
180
+ For release-line planning, use the CLI dry-run:
181
+
182
+ ```bash
183
+ buildchain release --dry-run --target-ref release/v2/v2.0 --sha <verified-sha>
184
+ ```
185
+
186
+ This prints the branch/tag/version-state/governance plan that a channel merge
187
+ would trigger. It is intentionally separate from `buildchain npm dry-run`, which
188
+ only checks package publish shape.
189
+
190
+ ## Read Next
191
+
192
+ - [Release governance](docs/release-governance.md) explains the design problem,
193
+ old ABV compatibility, hard constraints, and operational guarantees.
194
+ - [Release flow diagrams](docs/release-flow.md) gives the branch/tag state
195
+ machine and Mermaid diagrams.
196
+ - [Migration inventory](docs/migration-inventory.md) lists migrated and retired
197
+ action repositories.
198
+ - [Ownership rules](docs/ownership.md) defines source-of-truth and rollback
199
+ boundaries.
200
+ - [promote-buildchain-ref](actions/promote-buildchain-ref/README.md) documents
201
+ the internal promotion action.
202
+ - [Lifecycle protocol](docs/lifecycle-protocol.md) documents `buildchain.toml`
203
+ for custom version-state files and lifecycle commands.
204
+ - [Reusable build surface](docs/reusable-build-surface.md) documents the build
205
+ workflow, local runner matrix, artifact contract, and libnode-shaped fixture.
206
+ - [Web-surface deployments](docs/web-surface-deployments.md) documents the
207
+ preview/staging/production channel ontology, deployment manifest, adapter
208
+ contract, and dry-run cleanup/deploy plans.
209
+ - [Buildchain CLI and npm package](docs/cli.md) documents the npm package,
210
+ command-line entrypoint, repository bootstrap flow, and release-only publish
211
+ gate.
212
+
213
+ ## Local Verification
214
+
215
+ ```bash
216
+ corepack enable pnpm
217
+ pnpm install --frozen-lockfile
218
+ pnpm run check
219
+ ```
220
+
221
+ `pnpm run check` validates inventory data, lints all root workflows including
222
+ hidden reusable workflows, and rebuilds every action bundle.
223
+
224
+ ## Lifecycle Configuration
225
+
226
+ Projects can add `buildchain.toml` to declare release version state and
227
+ lifecycle commands. Buildchain v2 supports TOML only. The promotion action uses
228
+ configured version files to create source version commits, then runs
229
+ `lifecycle.verify` before moving release refs. Repositories that publish
230
+ external artifacts can also declare `lifecycle.publish`; with publish
231
+ transactions enabled, Buildchain requires machine-readable evidence before exact
232
+ release tags and floating channel refs move.
233
+
234
+ Web-surface projects can also declare `project.type = "web-surface"` with
235
+ preview, staging, and production channels. Those projects get deployment
236
+ manifests and dry-run deploy/cleanup plans, but they are not forced into package
237
+ version lines or anchored release semantics.
238
+
239
+ ## Safety Defaults
240
+
241
+ - Lab workflows are manual by default.
242
+ - Publishing is disabled unless explicitly enabled by a production release
243
+ workflow. Reusable builds expose `publish-channel`, `publish-allowed`, and
244
+ `publish-reason` so callers can gate publish jobs on a reviewed channel ref
245
+ instead of inferring publish eligibility from ad hoc branch checks.
246
+ - Publish gate branches are resolved to a source SHA before checkout. Builds,
247
+ verification, artifact manifests, and summaries use that locked SHA; publish
248
+ jobs must re-check the branch tip before external side effects.
249
+ - Publish transactions are keyed by repository, version, source SHA, and target
250
+ ref rather than run id. Reruns may resume missing artifacts, accept matching
251
+ existing artifacts, and fail closed on conflicting material until an explicit
252
+ repair override is used.
253
+ - Fork pull requests must not reach secrets or self-hosted runners.
254
+ - Candidate refs are expected to come from `kungfu-systems/*`.
255
+ - Self-hosted runner validation is available only through the manual
256
+ `Self-hosted Runner Smoke` workflow.
257
+
258
+ ## Read Next
259
+
260
+ - [Lifecycle protocol](docs/lifecycle-protocol.md)
261
+ - [Publish transaction](docs/publish-transaction.md)
262
+ - [Reusable build surface](docs/reusable-build-surface.md)
@@ -0,0 +1,222 @@
1
+ #!/usr/bin/env node
2
+ import { spawnSync } from "node:child_process";
3
+ import fs from "node:fs";
4
+ import path from "node:path";
5
+ import { fileURLToPath } from "node:url";
6
+ import { initBuildchainRepo } from "../scripts/init-repo.mjs";
7
+ import { npmPublishDryRun } from "../scripts/npm-publish-dry-run.mjs";
8
+ import { runLifecycle } from "../scripts/run-lifecycle-core.mjs";
9
+ import { validateBuildchainConfig } from "../packages/core/buildchain-config.js";
10
+ import {
11
+ explainReleaseLineDryRun,
12
+ formatReleaseLineDryRun,
13
+ } from "../packages/core/release-line-dry-run.js";
14
+
15
+ const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
16
+
17
+ function usage() {
18
+ return `Usage:
19
+ buildchain --help
20
+ buildchain version
21
+ buildchain init [--cwd <dir>] [--type package|native|web-surface|anchored-package] [--force]
22
+ [--package-manager pnpm|npm|yarn] [--runner-preset <preset>]
23
+ [--artifact-name <template>]
24
+ buildchain validate [--cwd <dir>] [--require-version-state]
25
+ [--require-lifecycle-stages <comma-list>]
26
+ buildchain lifecycle run <stage> [--cwd <dir>] [--required]
27
+ [--artifact-name <name>] [--artifact-path <path>]...
28
+ buildchain npm dry-run [--cwd <dir>] [--expected-tag <tag>] [--registry <url>]
29
+ [--dist-tag <tag>] [--skip-npm-publish-dry-run] [--json]
30
+ buildchain release --dry-run --target-ref <ref> [--sha <sha>] [--source-ref <ref>]
31
+ [--tags <comma-list>] [--json]
32
+ buildchain release dry-run --target-ref <ref> [--sha <sha>] [--source-ref <ref>]
33
+ [--tags <comma-list>] [--json]
34
+ buildchain release <inspect|recover|finalize|abort> ...
35
+ buildchain web-surface ...
36
+ buildchain publish-source <lock|manifest|verify-lock> ...
37
+ buildchain build-contract ...
38
+
39
+ Examples:
40
+ buildchain init --type package --package-manager pnpm
41
+ buildchain validate --require-version-state --require-lifecycle-stages build,verify
42
+ buildchain lifecycle run build --artifact-path dist --artifact-name "{repo}-{version}-{platform}"
43
+ buildchain npm dry-run --json
44
+ buildchain release --dry-run --target-ref alpha/v2/v2.0
45
+ `;
46
+ }
47
+
48
+ function readFlag(args, name, fallback = "") {
49
+ const index = args.indexOf(`--${name}`);
50
+ if (index === -1) {
51
+ return fallback;
52
+ }
53
+ return args[index + 1] || "";
54
+ }
55
+
56
+ function readBooleanFlag(args, name) {
57
+ return args.includes(`--${name}`);
58
+ }
59
+
60
+ function readRepeatedFlag(args, name) {
61
+ const values = [];
62
+ for (let index = 0; index < args.length; index += 1) {
63
+ if (args[index] === `--${name}` && args[index + 1]) {
64
+ values.push(args[index + 1]);
65
+ index += 1;
66
+ }
67
+ }
68
+ return values;
69
+ }
70
+
71
+ function runScript(scriptName, args) {
72
+ const scriptPath = path.join(root, "scripts", scriptName);
73
+ const result = spawnSync(process.execPath, [scriptPath, ...args], {
74
+ cwd: process.cwd(),
75
+ env: process.env,
76
+ stdio: "inherit",
77
+ });
78
+ if (result.error) {
79
+ throw result.error;
80
+ }
81
+ process.exitCode = result.status ?? 1;
82
+ }
83
+
84
+ function printJson(value) {
85
+ process.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
86
+ }
87
+
88
+ function packageVersion() {
89
+ const packageJson = JSON.parse(fs.readFileSync(path.join(root, "package.json"), "utf8"));
90
+ return packageJson.version;
91
+ }
92
+
93
+ async function main(argv = process.argv.slice(2)) {
94
+ const [command, ...args] = argv;
95
+ if (!command || command === "-h" || command === "--help" || command === "help") {
96
+ process.stdout.write(usage());
97
+ return;
98
+ }
99
+
100
+ if (command === "version" || command === "--version" || command === "-v") {
101
+ process.stdout.write(`${packageVersion()}\n`);
102
+ return;
103
+ }
104
+
105
+ if (command === "init") {
106
+ const result = initBuildchainRepo({
107
+ cwd: readFlag(args, "cwd", process.cwd()),
108
+ type: readFlag(args, "type", "package"),
109
+ force: readBooleanFlag(args, "force"),
110
+ packageManager: readFlag(args, "package-manager", ""),
111
+ runnerPreset: readFlag(args, "runner-preset", "github-hosted"),
112
+ artifactName: readFlag(args, "artifact-name", "{repo}-{version}-{platform}"),
113
+ });
114
+ printJson(result);
115
+ return;
116
+ }
117
+
118
+ if (command === "validate") {
119
+ const lifecycleStages = readFlag(args, "require-lifecycle-stages", "")
120
+ .split(",")
121
+ .map((entry) => entry.trim())
122
+ .filter(Boolean);
123
+ printJson(validateBuildchainConfig(readFlag(args, "cwd", process.cwd()), {
124
+ requireVersionState: readBooleanFlag(args, "require-version-state"),
125
+ requireLifecycleStages: lifecycleStages,
126
+ }));
127
+ return;
128
+ }
129
+
130
+ if (command === "lifecycle") {
131
+ const [subcommand, stageName = "", ...lifecycleArgs] = args;
132
+ if (subcommand !== "run" || !stageName) {
133
+ throw new Error("usage: buildchain lifecycle run <stage>");
134
+ }
135
+ const artifactPaths = readRepeatedFlag(lifecycleArgs, "artifact-path");
136
+ const manifest = runLifecycle({
137
+ cwd: readFlag(lifecycleArgs, "cwd", process.cwd()),
138
+ stageName,
139
+ required: readBooleanFlag(lifecycleArgs, "required"),
140
+ artifactName: readFlag(lifecycleArgs, "artifact-name", "buildchain-artifact"),
141
+ artifactPaths,
142
+ expectedArtifactsJson: readFlag(lifecycleArgs, "expected-artifacts-json", ""),
143
+ workspace: process.cwd(),
144
+ });
145
+ printJson(manifest);
146
+ return;
147
+ }
148
+
149
+ if (command === "npm") {
150
+ const [subcommand = "", ...npmArgs] = args;
151
+ if (subcommand !== "dry-run") {
152
+ throw new Error("usage: buildchain npm dry-run");
153
+ }
154
+ const result = npmPublishDryRun({
155
+ cwd: readFlag(npmArgs, "cwd", process.cwd()),
156
+ expectedTag: readFlag(npmArgs, "expected-tag", ""),
157
+ registry: readFlag(npmArgs, "registry", "https://registry.npmjs.org/"),
158
+ distTag: readFlag(npmArgs, "dist-tag", ""),
159
+ skipNpmPublishDryRun: readBooleanFlag(npmArgs, "skip-npm-publish-dry-run"),
160
+ });
161
+ if (readBooleanFlag(npmArgs, "json")) {
162
+ printJson(result);
163
+ } else {
164
+ process.stdout.write(`npm publish dry-run ok: ${result.package.name}@${result.package.version} -> ${result.distTag}\n`);
165
+ process.stdout.write(`pack entries: ${result.pack.entryCount}\n`);
166
+ }
167
+ return;
168
+ }
169
+
170
+ if (command === "release") {
171
+ const releaseArgs = args[0] === "dry-run" ? args.slice(1) : args;
172
+ if (args[0] === "dry-run" || readBooleanFlag(args, "dry-run")) {
173
+ const plan = explainReleaseLineDryRun({
174
+ cwd: readFlag(releaseArgs, "cwd", process.cwd()),
175
+ targetRef: readFlag(releaseArgs, "target-ref", ""),
176
+ sourceRef: readFlag(releaseArgs, "source-ref", ""),
177
+ sha: readFlag(releaseArgs, "sha", ""),
178
+ tags: readFlag(releaseArgs, "tags", ""),
179
+ publishTransaction: readBooleanFlag(releaseArgs, "publish-transaction"),
180
+ publishCommand: readFlag(releaseArgs, "publish-command", ""),
181
+ });
182
+ if (readBooleanFlag(releaseArgs, "json")) {
183
+ printJson(plan);
184
+ } else {
185
+ process.stdout.write(formatReleaseLineDryRun(plan));
186
+ }
187
+ return;
188
+ }
189
+ runScript("release-transaction.mjs", args);
190
+ return;
191
+ }
192
+
193
+ if (command === "web-surface") {
194
+ runScript("web-surface.mjs", args);
195
+ return;
196
+ }
197
+
198
+ if (command === "build-contract") {
199
+ runScript("resolve-build-contract.mjs", args);
200
+ return;
201
+ }
202
+
203
+ if (command === "publish-source") {
204
+ const [mode = "lock", ...publishArgs] = args;
205
+ if (mode === "lock" || mode === "manifest") {
206
+ runScript("resolve-publish-source.mjs", ["--mode", mode, ...publishArgs]);
207
+ return;
208
+ }
209
+ if (mode === "verify-lock") {
210
+ runScript("verify-publish-source-lock.mjs", publishArgs);
211
+ return;
212
+ }
213
+ throw new Error(`unsupported publish-source command: ${mode}`);
214
+ }
215
+
216
+ throw new Error(`unsupported buildchain command: ${command}`);
217
+ }
218
+
219
+ main().catch((error) => {
220
+ console.error(`buildchain: ${error.message}`);
221
+ process.exitCode = 1;
222
+ });
package/docs/cli.md ADDED
@@ -0,0 +1,124 @@
1
+ # Buildchain CLI and npm Package
2
+
3
+ Buildchain is published as the public npm package
4
+ `@kungfu-tech/buildchain`. The package contains the `buildchain` command,
5
+ the shared core libraries, and the local scripts needed to initialize and
6
+ validate repositories before they use the reusable GitHub workflow surface.
7
+
8
+ The npm package is not the release authority. Release authority still comes
9
+ from the protected Buildchain branch and tag state machine. npm publishing is a
10
+ side effect of an exact release tag that has already been produced by that
11
+ state machine.
12
+
13
+ ## Install and Run
14
+
15
+ Use the published package directly:
16
+
17
+ ```bash
18
+ npx @kungfu-tech/buildchain --help
19
+ npx @kungfu-tech/buildchain init --type package
20
+ npx @kungfu-tech/buildchain validate --require-version-state
21
+ ```
22
+
23
+ Or install it in a repository:
24
+
25
+ ```bash
26
+ pnpm add -D @kungfu-tech/buildchain
27
+ pnpm exec buildchain validate
28
+ ```
29
+
30
+ ## Commands
31
+
32
+ `buildchain init` writes a starter `buildchain.toml` and a reusable workflow
33
+ caller at `.github/workflows/build.yml`.
34
+
35
+ Supported presets:
36
+
37
+ - `--type package` for Node package repositories with pnpm, npm, or yarn.
38
+ - `--type native` for CMake-style native projects.
39
+ - `--type web-surface` for preview/staging/production site or app deployments.
40
+ - `--type anchored-package` for packages whose version is anchored to an
41
+ explicit upstream release manifest.
42
+
43
+ `buildchain validate` parses `buildchain.toml`, checks configured version-state
44
+ files, and can require named lifecycle stages:
45
+
46
+ ```bash
47
+ buildchain validate \
48
+ --require-version-state \
49
+ --require-lifecycle-stages install,build,verify
50
+ ```
51
+
52
+ `buildchain lifecycle run <stage>` executes a lifecycle stage and writes the
53
+ same deterministic artifact manifest contract used by the reusable workflow:
54
+
55
+ ```bash
56
+ buildchain lifecycle run build \
57
+ --artifact-path dist \
58
+ --artifact-name "{repo}-{version}-{platform}"
59
+ ```
60
+
61
+ `buildchain release`, `buildchain web-surface`, `buildchain publish-source`,
62
+ and `buildchain build-contract` route to the same scripts used by Buildchain's
63
+ GitHub Actions workflows. This keeps local inspection and CI behavior on the
64
+ same implementation path.
65
+
66
+ `buildchain release --dry-run` explains the release-line state machine before a
67
+ maintainer opens or merges a channel PR:
68
+
69
+ ```bash
70
+ buildchain release --dry-run --target-ref alpha/v2/v2.0
71
+ buildchain release --dry-run --target-ref release/v2/v2.0 --sha <verified-sha>
72
+ buildchain release dry-run --target-ref publish-gate/major --source-ref release/v2/v2.0
73
+ ```
74
+
75
+ This is a Buildchain-level dry-run, not an npm dry-run. It explains the legal
76
+ source branch, exact release or alpha tags, floating tags, channel branches,
77
+ version-state files, governance checks, and publish transaction behavior that
78
+ would apply if the corresponding PR merge were promoted. It does not move
79
+ branches, move tags, edit files, publish npm packages, or run lifecycle publish
80
+ commands. Pass `--json` for a machine-readable plan.
81
+
82
+ `buildchain npm dry-run` verifies the package shape before a release tag exists:
83
+
84
+ ```bash
85
+ buildchain npm dry-run --json
86
+ ```
87
+
88
+ The command validates `package.json`, infers the exact release tag
89
+ `v${package.json.version}`, chooses npm dist-tag `alpha` for prereleases and
90
+ `latest` for stable releases, runs `npm pack --dry-run --json`, and then runs
91
+ `npm publish --dry-run --access public --tag <alpha|latest>` unless
92
+ `--skip-npm-publish-dry-run` is passed. It never performs a real publish.
93
+
94
+ ## npm Publish Gate
95
+
96
+ Buildchain's own npm package is published from
97
+ `.github/workflows/buildchain-ref-promotion.yml`, inside the same publish
98
+ transaction that promotes release refs:
99
+
100
+ - `v2.0.13-alpha.0` publishes to npm with dist-tag `alpha`.
101
+ - `v2.0.13` publishes to npm with dist-tag `latest`.
102
+ - moving refs such as `v2`, `v2.0`, and `v2.0-alpha` do not match the publish
103
+ workflow and do not publish.
104
+
105
+ The promotion workflow uses npm Trusted Publishing through GitHub Actions OIDC.
106
+ It runs on a GitHub-hosted runner with `id-token: write`, generates the
107
+ version-state commit, runs `lifecycle.verify`, runs `lifecycle.publish`, writes
108
+ Buildchain publish evidence, validates that evidence, and only then moves exact
109
+ tags and floating refs.
110
+
111
+ ```bash
112
+ node scripts/npm-publish-transaction.mjs
113
+ ```
114
+
115
+ Before the first real release, configure npm Trusted Publishing for:
116
+
117
+ - package: `@kungfu-tech/buildchain`
118
+ - repository: `kungfu-systems/buildchain`
119
+ - workflow: `.github/workflows/buildchain-ref-promotion.yml`
120
+
121
+ No npm package is published by manual dispatch or ordinary branch builds.
122
+ Manual dispatch on `.github/workflows/npm-publish.yml` remains dry-run only, so
123
+ maintainers can verify package contents and npm publish shape before opening or
124
+ merging the release PR.