@kungfu-tech/buildchain 3.0.9-alpha.9 → 4.0.0-alpha.0

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 (262) hide show
  1. package/AGENTS.md +39 -0
  2. package/README.md +17 -13
  3. package/actions/promote-buildchain-ref/README.md +0 -10
  4. package/actions/release-tail/README.md +6 -10
  5. package/architecture/internal-capabilities.json +502 -0
  6. package/architecture/maintainability-baseline.json +59 -0
  7. package/architecture/maintainability-policy.json +1384 -0
  8. package/architecture/release-tail-contract-inventory.json +587 -0
  9. package/architecture/v3-core-mechanism-inventory.json +1043 -0
  10. package/architecture/v3-core-mechanism-inventory.md +67 -0
  11. package/architecture/v4-adopter-delivery-parity.json +47 -0
  12. package/architecture/v4-architecture-constitution.md +210 -0
  13. package/architecture/v4-bootstrap-authority.json +56 -0
  14. package/architecture/v4-canonical-contract-fixtures.json +105 -0
  15. package/architecture/v4-capability-state-machine-manifest.json +480 -0
  16. package/architecture/v4-capability-state-machine-manifest.schema.json +202 -0
  17. package/architecture/v4-delivery-warrant-shadow-bootstrap-plan.json +830 -0
  18. package/architecture/v4-delivery-warrant-shadow-bootstrap-plan.md +223 -0
  19. package/architecture/v4-delivery-warrant-shadow-bootstrap-plan.schema.json +318 -0
  20. package/architecture/v4-delivery-warrant-shadow-fixtures.json +227 -0
  21. package/architecture/v4-delivery-warrant-shadow-fixtures.schema.json +67 -0
  22. package/architecture/v4-exception-ledger.json +5 -0
  23. package/architecture/v4-exception-ledger.schema.json +56 -0
  24. package/architecture/v4-partial-mutation-recovery-qualification.json +65 -0
  25. package/architecture/v4-platform-stage-checkpoints.json +97 -0
  26. package/architecture/v4-provider-operation-journal-contract.json +113 -0
  27. package/architecture/v4-release-activation-shadow-domain.json +61 -0
  28. package/architecture/v4-release-train-parity.json +68 -0
  29. package/architecture/v4-rust-libnode-bridge-evaluation.json +107 -0
  30. package/architecture/v4-rust-libnode-bridge-spike.md +85 -0
  31. package/architecture/v4-stable-publication-fence.json +66 -0
  32. package/architecture/v4-stage-capsule-contract.json +90 -0
  33. package/architecture/v4-stage-capsule-qualification.json +99 -0
  34. package/architecture/v4-stage-capsule-resume-planner.json +52 -0
  35. package/architecture/v4-stage-capsule-store-contract.json +72 -0
  36. package/bin/buildchain.mjs +15 -10
  37. package/contracts/auditable-demo-scenario-v1.schema.json +1 -1
  38. package/contracts/buildchain-v2-residuals-v1.json +2 -2
  39. package/contracts/fixtures/v4-delivery-warrant-trace-v1/golden.json +158 -0
  40. package/contracts/fixtures/v4-delivery-warrant-trace-v1/property.json +380 -0
  41. package/contracts/fixtures/v4-delivery-warrant-trace-v1/replay.json +163 -0
  42. package/contracts/fixtures/v4-partial-mutation-recovery-v1/shared.json +155 -0
  43. package/contracts/fixtures/v4-provider-operation-journal-v1/shared.json +457 -0
  44. package/contracts/fixtures/v4-provider-readback-idempotency-v1/shared.json +682 -0
  45. package/contracts/fixtures/v4-release-activation-shadow-v1/shared.json +53 -0
  46. package/contracts/fixtures/v4-stable-publication-fence-v1/shared.json +56 -0
  47. package/contracts/fixtures/v4-stage-capsule-resume-v1/late-platform-failure.json +176 -0
  48. package/contracts/fixtures/v4-stage-capsule-store-v1/shared.json +132 -0
  49. package/contracts/fixtures/v4-stage-capsule-v1/shared.json +111 -0
  50. package/contracts/v4-canonical-contracts-v1.schema.json +182 -0
  51. package/contracts/v4-delivery-warrant-semantic-diff-report-v1.schema.json +284 -0
  52. package/contracts/v4-delivery-warrant-trace-v1.schema.json +215 -0
  53. package/contracts/v4-host-contract-v1.schema.json +135 -0
  54. package/contracts/v4-partial-mutation-recovery-v1.schema.json +168 -0
  55. package/contracts/v4-provider-operation-journal-v1.schema.json +381 -0
  56. package/contracts/v4-release-activation-shadow-v1.schema.json +186 -0
  57. package/contracts/v4-stable-publication-fence-v1.schema.json +125 -0
  58. package/contracts/v4-stage-capsule-resume-v1.schema.json +225 -0
  59. package/contracts/v4-stage-capsule-store-v1.schema.json +154 -0
  60. package/contracts/v4-stage-capsule-v1.schema.json +178 -0
  61. package/crates/buildchain-v4-bridge/Cargo.lock +213 -0
  62. package/crates/buildchain-v4-bridge/Cargo.toml +12 -0
  63. package/crates/buildchain-v4-bridge/src/main.rs +495 -0
  64. package/dist/site/agent-index.json +0 -4
  65. package/dist/site/artifact-schemas.json +0 -8
  66. package/dist/site/buildchain-contract.json +103 -397
  67. package/dist/site/buildchain-site.json +302 -386
  68. package/dist/site/capability-registry.json +9 -11
  69. package/dist/site/cli-registry.json +8 -53
  70. package/dist/site/controller-registry.json +48 -8
  71. package/dist/site/kfd-claims.json +129 -167
  72. package/dist/site/kfd-upstream-aggregate.json +9 -9
  73. package/dist/site/manual-registry.json +18 -49
  74. package/dist/site/node-api-registry.json +4345 -7345
  75. package/dist/site/page-registry.json +278 -346
  76. package/dist/site/public-surface-audit.json +85 -404
  77. package/dist/site/publication-authority-registry.json +11 -1
  78. package/dist/site/publication-registry.json +4 -4
  79. package/dist/site/release-provenance.json +3 -9
  80. package/dist/site/schemas/kfd-support-projection-v1.schema.json +106 -0
  81. package/dist/site/site-manifest.json +22 -38
  82. package/dist/site/workflow-registry.json +78 -35
  83. package/docs/MAP.md +8 -5
  84. package/docs/auditable-demo.md +2 -2
  85. package/docs/aws-us-elastic-runner-burst-plane.md +7 -59
  86. package/docs/cli-reference.md +15 -213
  87. package/docs/cli.md +14 -14
  88. package/docs/dev-alpha-candidate-patrol.md +3 -11
  89. package/docs/dev-delivery-warrant.md +29 -194
  90. package/docs/engineering-housekeeper.md +12 -4
  91. package/docs/getting-started.md +1 -1
  92. package/docs/install.md +5 -5
  93. package/docs/kfd-support.md +2 -7
  94. package/docs/lifecycle-protocol.md +2 -4
  95. package/docs/node-api-reference.md +414 -554
  96. package/docs/release-flow.md +31 -31
  97. package/docs/release-governance.md +16 -28
  98. package/docs/release-passport.md +2 -15
  99. package/docs/release-tail-contract.md +13 -6
  100. package/docs/release-tail-provider-plane.md +13 -19
  101. package/docs/release-train.md +4 -4
  102. package/docs/reusable-build-surface.md +14 -27
  103. package/docs/site-bundle-contract.md +1 -5
  104. package/docs/stable-candidate-patrol.md +7 -7
  105. package/docs/v4-canonical-contracts.md +92 -0
  106. package/docs/v4-delivery-warrant-read-candidate.md +73 -0
  107. package/docs/v4-delivery-warrant-semantic-diff.md +75 -0
  108. package/docs/v4-production-release.md +63 -0
  109. package/docs/v4-stage-capsule.md +193 -0
  110. package/docs/versioning.md +3 -5
  111. package/package.json +19 -19
  112. package/packages/core/adopter-delivery-gate.js +576 -0
  113. package/packages/core/adopter-delivery-json.js +66 -0
  114. package/packages/core/artifact-signing.js +0 -61
  115. package/packages/core/artifact-verification-envelope.js +5 -5
  116. package/packages/core/build-facts.js +12 -4
  117. package/packages/core/buildchain-agent-manuals.js +0 -2
  118. package/packages/core/buildchain-channel-identity.js +3 -2
  119. package/packages/core/buildchain-config.js +4 -69
  120. package/packages/core/buildchain-contract.js +232 -46
  121. package/packages/core/buildchain-kfd-claims.js +1 -1
  122. package/packages/core/channel-candidate.js +0 -8
  123. package/packages/core/channel-promotion-baseline.js +0 -52
  124. package/packages/core/controller-evidence.js +3 -4
  125. package/packages/core/dev-alpha-candidate-selection.js +2 -10
  126. package/packages/core/dev-delivery-warrant-cancellation.js +0 -1
  127. package/packages/core/dev-delivery-warrant-settlement.js +20 -67
  128. package/packages/core/dev-delivery-warrant.js +50 -138
  129. package/packages/core/diagnostics.js +3 -8
  130. package/packages/core/github-governance-authority.js +3 -1
  131. package/packages/core/kfd-adopter-category-driver.js +167 -0
  132. package/packages/core/kfd-adopter-manifest.js +47 -46
  133. package/packages/core/kfd-gate.js +15 -45
  134. package/packages/core/paper-agent-entry.js +7 -16
  135. package/packages/core/paper-fleet.js +2 -2
  136. package/packages/core/paper-repository.js +2 -3
  137. package/packages/core/paper-scaffold-content.js +2 -23
  138. package/packages/core/paper.js +11 -43
  139. package/packages/core/publication-reproducibility.js +4 -4
  140. package/packages/core/release-line-bootstrap.js +21 -8
  141. package/packages/core/release-passport-contract.js +5 -5
  142. package/packages/core/release-passport.js +20 -131
  143. package/packages/core/self-dogfood-version.js +48 -35
  144. package/packages/core/spawn-command.js +232 -8
  145. package/packages/core/v4-adopter-delivery-parity.js +219 -0
  146. package/packages/core/v4-canonical-contracts.js +284 -0
  147. package/packages/core/v4-delivery-warrant-fixture-runner.js +371 -0
  148. package/packages/core/v4-delivery-warrant-read-candidate.js +279 -0
  149. package/packages/core/v4-delivery-warrant-semantic-diff-gate.js +352 -0
  150. package/packages/core/v4-delivery-warrant-shadow-adapter.js +447 -0
  151. package/packages/core/v4-partial-mutation-recovery-qualification.js +395 -0
  152. package/packages/core/v4-platform-stage-checkpoints.js +471 -0
  153. package/packages/core/v4-provider-operation-journal.js +531 -0
  154. package/packages/core/v4-provider-readback-idempotency.js +394 -0
  155. package/packages/core/v4-release-activation-shadow.js +519 -0
  156. package/packages/core/v4-stable-publication-fence.js +357 -0
  157. package/packages/core/v4-stage-capsule-local-store.js +426 -0
  158. package/packages/core/v4-stage-capsule-qualification-campaign.js +512 -0
  159. package/packages/core/v4-stage-capsule-qualification.js +456 -0
  160. package/packages/core/v4-stage-capsule-resume-planner.js +397 -0
  161. package/packages/core/v4-stage-capsule-store.js +401 -0
  162. package/packages/core/v4-stage-capsule.js +319 -0
  163. package/scripts/assemble-self-publication-admission.mjs +1 -1
  164. package/scripts/audit-publication-control-plane.mjs +5 -5
  165. package/scripts/auditable-demo-bundle-verification.mjs +3 -2
  166. package/scripts/auditable-demo-platform.mjs +2 -2
  167. package/scripts/auditable-demo-renditions.mjs +1 -1
  168. package/scripts/auditable-demo.mjs +2 -2
  169. package/scripts/aws-macos-jit-controller-core.mjs +13 -346
  170. package/scripts/aws-macos-jit-controller-runtime.mjs +2 -210
  171. package/scripts/aws-macos-jit-controller.mjs +37 -275
  172. package/scripts/aws-macos-jit-core.mjs +3 -41
  173. package/scripts/aws-macos-jit.mjs +0 -12
  174. package/scripts/aws-windows-jit-campaign.mjs +2 -2
  175. package/scripts/aws-windows-jit-controller-core.mjs +1 -1
  176. package/scripts/aws-windows-jit-controller.mjs +3 -3
  177. package/scripts/build-contract-core.mjs +3 -8
  178. package/scripts/build-standalone-binary.mjs +3 -14
  179. package/scripts/buildchain-channel-router.mjs +4 -0
  180. package/scripts/buildchain-cli-help.mjs +7 -16
  181. package/scripts/buildchain-contract-lock.mjs +0 -6
  182. package/scripts/check-action-bundles.mjs +3 -4
  183. package/scripts/check-internal-architecture.mjs +7 -6
  184. package/scripts/check-inventory.mjs +30 -25
  185. package/scripts/check-v4-public-dogfood-contract.mjs +270 -0
  186. package/scripts/create-release-bundle.mjs +8 -4
  187. package/scripts/dev-alpha-candidate-patrol.mjs +1 -22
  188. package/scripts/dev-delivery-proof.mjs +2 -64
  189. package/scripts/dev-delivery-warrant.mjs +61 -86
  190. package/scripts/dev-pr-auto-merge.mjs +4 -30
  191. package/scripts/dev-pr-delivery-warrant.mjs +0 -55
  192. package/scripts/dispatch-artifact-signing-authority.mjs +7 -4
  193. package/scripts/generate-buildchain-kfd-witnesses.mjs +94 -88
  194. package/scripts/generate-channel-build-workflow.mjs +54 -24
  195. package/scripts/generate-channel-promotion-workflow.mjs +15 -6
  196. package/scripts/generate-site-bundle.mjs +8 -27
  197. package/scripts/git-fetch-process-tree.mjs +34 -1
  198. package/scripts/init-repo.mjs +64 -159
  199. package/scripts/inspect-artifact-signing-requests.mjs +0 -6
  200. package/scripts/locked-source-checkout.mjs +3 -4
  201. package/scripts/maintainability-metrics.mjs +8 -2
  202. package/scripts/npm-publish-dry-run.mjs +2 -2
  203. package/scripts/npm-publish-transaction.mjs +2 -2
  204. package/scripts/publication-commit-evidence.mjs +23 -69
  205. package/scripts/release-candidate-resolver.mjs +11 -17
  206. package/scripts/release-tail.mjs +3 -49
  207. package/scripts/resume-from-candidate-run.mjs +9 -123
  208. package/scripts/run-lifecycle-core.mjs +12 -13
  209. package/scripts/seal-artifact-signing-requests.mjs +17 -21
  210. package/scripts/site-capability-metadata.mjs +3 -20
  211. package/scripts/stable-candidate-qualification.mjs +10 -10
  212. package/scripts/v4-architecture.mjs +12 -2
  213. package/scripts/v4-bridge-bootstrap.mjs +141 -0
  214. package/scripts/v4-bridge-evidence.mjs +141 -0
  215. package/scripts/v4-host-adapter.mjs +182 -0
  216. package/scripts/v4-platform-stage-checkpoint-rehearsal.mjs +207 -0
  217. package/scripts/v4-stage-capsule-qualification.mjs +528 -0
  218. package/scripts/v4-stage-capsule-resume-rehearsal.mjs +57 -0
  219. package/scripts/v4-warrant-shadow-plan.mjs +601 -0
  220. package/scripts/verify-golden-path.mjs +5 -5
  221. package/scripts/web-surface-cloudfront-rewrite.mjs +15 -15
  222. package/scripts/web-surface-core.mjs +2 -8
  223. package/scripts/workflow-call-contract.mjs +5 -184
  224. package/contracts/dev-delivery-authority-v2.schema.json +0 -253
  225. package/contracts/fixtures/kfd-adopter-release-v1/kfd-4-perspective.json +0 -16
  226. package/contracts/fixtures/kfd-adopter-release-v1/kfd-4-replay.json +0 -57
  227. package/contracts/fixtures/next-development-transition-v1/anchored-manual-waiting.json +0 -47
  228. package/contracts/fixtures/next-development-transition-v1/semver-auto-planned.json +0 -47
  229. package/contracts/fixtures/next-development-transition-v1/version-model-cases.json +0 -40
  230. package/contracts/next-development-request-v1.schema.json +0 -66
  231. package/contracts/next-development-transition-v1.schema.json +0 -292
  232. package/contracts/publication-rehearsal-capsule-v1.schema.json +0 -173
  233. package/dist/site/schemas/dev-delivery-authority-v2.schema.json +0 -442
  234. package/dist/site/schemas/publication-rehearsal-capsule-v1.schema.json +0 -269
  235. package/dist/site/schemas/release-tail-capabilities-v1.schema.json +0 -353
  236. package/dist/site/schemas/release-tail-provider-bindings-v1.schema.json +0 -94
  237. package/docs/dev-delivery-qualification-landing-adr.md +0 -137
  238. package/docs/next-development-transition.md +0 -119
  239. package/docs/publication-rehearsal.md +0 -94
  240. package/packages/core/buildchain-compatibility-proof.js +0 -631
  241. package/packages/core/dev-delivery-authority.js +0 -996
  242. package/packages/core/dev-delivery-native-proof.js +0 -418
  243. package/packages/core/dev-delivery-warrant-shadow.js +0 -502
  244. package/packages/core/next-development-candidate-reservation.js +0 -186
  245. package/packages/core/next-development-controller.js +0 -726
  246. package/packages/core/next-development-projection.js +0 -288
  247. package/packages/core/next-development-transition.js +0 -738
  248. package/packages/core/publication-rehearsal-projection.js +0 -173
  249. package/packages/core/publication-rehearsal-runtime.js +0 -921
  250. package/scripts/aws-macos-jit-instance-rehydrate.mjs +0 -260
  251. package/scripts/aws-macos-jit-source-rebind.mjs +0 -724
  252. package/scripts/dev-delivery-authority.mjs +0 -368
  253. package/scripts/dev-delivery-native-run.mjs +0 -235
  254. package/scripts/dev-delivery-two-phase-resume.mjs +0 -90
  255. package/scripts/dev-delivery-two-phase.mjs +0 -577
  256. package/scripts/generate-next-development-guidance.mjs +0 -49
  257. package/scripts/materialize-self-release-candidate-version.mjs +0 -137
  258. package/scripts/next-development-self-dogfood-harness.mjs +0 -409
  259. package/scripts/next-development-self-dogfood.mjs +0 -532
  260. package/scripts/next-development-transition.mjs +0 -47
  261. package/scripts/release-candidate-tail-reseal.mjs +0 -426
  262. package/templates/native-dev-delivery.yml +0 -86
@@ -25,42 +25,61 @@ function parseAlphaRef(ref) {
25
25
  return Number(match[1]);
26
26
  }
27
27
 
28
- export function resolveSelfDogfoodMajor({
28
+ function isExactSha(value) {
29
+ return /^[0-9a-f]{40}$/u.test(String(value || ""));
30
+ }
31
+
32
+ export function hasQualifiedSelfDogfoodBootstrapAuthority({
29
33
  packageVersion,
30
34
  alphaRef,
31
- majorBootstrap = false,
35
+ authority,
32
36
  } = {}) {
33
37
  const version = parsePackageVersion(packageVersion);
34
38
  const acceptedMajor = parseAlphaRef(alphaRef);
35
- if (acceptedMajor === version.major) {
36
- return {
37
- packageMajor: version.major,
38
- workflowMajor: acceptedMajor,
39
- bootstrap: false,
40
- };
41
- }
42
-
43
- const stableBootstrap =
44
- version.minor === 0 && version.patch === 0 && version.alpha === undefined;
45
- const nextAlphaBootstrap =
46
- version.minor === 0 && version.patch === 1 && version.alpha !== undefined;
47
- if (
48
- majorBootstrap === true &&
39
+ const releaseLine = authority?.releaseLine;
40
+ const qualification = authority?.qualification;
41
+ return (
49
42
  acceptedMajor + 1 === version.major &&
50
- (stableBootstrap || nextAlphaBootstrap)
51
- ) {
52
- return {
53
- packageMajor: version.major,
54
- workflowMajor: acceptedMajor,
55
- bootstrap: true,
56
- };
57
- }
58
-
59
- throw new Error(
60
- "Buildchain self-dogfood alpha lock must target the current major alpha ref",
43
+ authority?.contract ===
44
+ `kungfu-buildchain-v${version.major}-bootstrap-authority` &&
45
+ releaseLine?.candidateBranch ===
46
+ `dev/v${version.major}/v${version.major}.0` &&
47
+ String(releaseLine?.sourceBranch || "").startsWith(
48
+ `dev/v${acceptedMajor}/v${acceptedMajor}.`,
49
+ ) &&
50
+ releaseLine?.status === `qualified-protected-v${version.major}-bootstrap` &&
51
+ isExactSha(releaseLine?.sourceCommit) &&
52
+ isExactSha(releaseLine?.bootstrapCommit) &&
53
+ qualification?.contract ===
54
+ `kungfu-buildchain-v${version.major}-n-minus-one-qualification` &&
55
+ qualification?.authorityRevision === releaseLine.sourceCommit &&
56
+ qualification?.candidateRevision === releaseLine.bootstrapCommit &&
57
+ qualification?.candidateSelfQualified === false &&
58
+ qualification?.activeExceptions === 0 &&
59
+ /^sha256:[0-9a-f]{64}$/u.test(
60
+ String(qualification?.qualificationRoot || ""),
61
+ )
61
62
  );
62
63
  }
63
64
 
65
+ export function resolveSelfDogfoodMajor({
66
+ packageVersion,
67
+ alphaRef,
68
+ } = {}) {
69
+ const version = parsePackageVersion(packageVersion);
70
+ const acceptedMajor = parseAlphaRef(alphaRef);
71
+ if (acceptedMajor !== version.major) {
72
+ throw new Error(
73
+ "Buildchain self-dogfood alpha lock must target the current major alpha ref",
74
+ );
75
+ }
76
+ return {
77
+ packageMajor: version.major,
78
+ workflowMajor: acceptedMajor,
79
+ bootstrap: false,
80
+ };
81
+ }
82
+
64
83
  export function contractForSelfDogfoodEvaluation({
65
84
  currentContract,
66
85
  majorResolution,
@@ -68,18 +87,12 @@ export function contractForSelfDogfoodEvaluation({
68
87
  if (!currentContract || typeof currentContract !== "object") {
69
88
  throw new Error("Buildchain self-dogfood requires a current contract");
70
89
  }
71
- if (!majorResolution?.bootstrap) {
72
- return currentContract;
73
- }
74
- return {
75
- ...currentContract,
76
- majorLine: `v${majorResolution.workflowMajor}`,
77
- };
90
+ return currentContract;
78
91
  }
79
92
 
80
93
  export function canAdmitSelfDogfoodLockEvaluation({
81
94
  evaluation,
82
95
  majorResolution,
83
96
  } = {}) {
84
- return evaluation?.compatible === true || majorResolution?.bootstrap === true;
97
+ return evaluation?.compatible === true;
85
98
  }
@@ -1,16 +1,66 @@
1
- import { spawnSync } from "node:child_process";
1
+ import { execFileSync, execSync, spawn, spawnSync } from "node:child_process";
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ import { fileURLToPath, pathToFileURL } from "node:url";
2
5
 
3
6
  const WINDOWS_CMD_SHIMS = new Set(["corepack", "npm", "npx", "pnpm", "yarn"]);
7
+ const CMD_META_CHARACTERS = /([()\][%!^`"<>&|;, *?])/g;
8
+ const INTERNAL_PROCESS_TREE_COMMAND = "--buildchain-internal-process-tree-command";
9
+ const TIMEOUT_EXIT_CODE = 124;
10
+ const modulePath = fileURLToPath(import.meta.url);
4
11
 
5
- export function resolveSpawnCommand(command, platform = process.platform) {
6
- if (platform !== "win32" || !WINDOWS_CMD_SHIMS.has(command)) {
12
+ function runningStandaloneBundle() {
13
+ return process.argv[1] && process.argv[2] !== INTERNAL_PROCESS_TREE_COMMAND
14
+ && import.meta.url === pathToFileURL(process.argv[1]).href;
15
+ }
16
+
17
+ function pathCommandShim(command, env) {
18
+ for (const directory of String(env.PATH || "").split(";")) {
19
+ const candidate = path.join(directory, `${command}.cmd`);
20
+ if (directory && fs.existsSync(candidate)) return true;
21
+ }
22
+ return false;
23
+ }
24
+
25
+ export function resolveSpawnCommand(command, platform = process.platform, env = process.env) {
26
+ if (platform !== "win32") {
7
27
  return command;
8
28
  }
9
- return `${command}.cmd`;
29
+ return pathCommandShim(command, env) || WINDOWS_CMD_SHIMS.has(command)
30
+ ? `${command}.cmd`
31
+ : command;
10
32
  }
11
33
 
12
- export function usesShellForSpawnCommand(command, platform = process.platform) {
13
- return platform === "win32" && WINDOWS_CMD_SHIMS.has(command);
34
+ export function usesShellForSpawnCommand(command, platform = process.platform, env = process.env) {
35
+ return platform === "win32" && /\.cmd$/i.test(resolveSpawnCommand(command, platform, env));
36
+ }
37
+
38
+ function cmdEscapeCommand(value) {
39
+ return String(value).replace(CMD_META_CHARACTERS, "^$1");
40
+ }
41
+
42
+ function cmdEscapeArgument(value, doubleEscapeMetaCharacters = false) {
43
+ let text = String(value);
44
+ text = text.replace(/(?=(\\+?)?)\1"/g, '$1$1\\"');
45
+ text = text.replace(/(?=(\\+?)?)\1$/g, "$1$1");
46
+ let escaped = `"${text}"`.replace(CMD_META_CHARACTERS, "^$1");
47
+ if (doubleEscapeMetaCharacters) {
48
+ escaped = escaped.replace(CMD_META_CHARACTERS, "^$1");
49
+ }
50
+ return escaped;
51
+ }
52
+
53
+ export function windowsBatchInvocation(command, args, env = process.env) {
54
+ const shellCommand = [
55
+ cmdEscapeCommand(command),
56
+ ...args.map((argument) =>
57
+ cmdEscapeArgument(argument, /\.cmd$/i.test(command)),
58
+ ),
59
+ ].join(" ");
60
+ return {
61
+ command: env.ComSpec || env.comspec || process.env.ComSpec || process.env.comspec || "cmd.exe",
62
+ args: ["/d", "/s", "/c", `"${shellCommand}"`],
63
+ };
14
64
  }
15
65
 
16
66
  export function spawnSyncCommand(
@@ -19,8 +69,182 @@ export function spawnSyncCommand(
19
69
  options = {},
20
70
  { platform = process.platform, spawn = spawnSync } = {},
21
71
  ) {
22
- return spawn(resolveSpawnCommand(command, platform), args, {
72
+ const env = options.env || process.env;
73
+ const resolvedCommand = resolveSpawnCommand(command, platform, env);
74
+ if (
75
+ platform === "win32" &&
76
+ /\.cmd$/i.test(resolvedCommand) &&
77
+ options.shell !== false
78
+ ) {
79
+ const invocation = windowsBatchInvocation(resolvedCommand, args, env);
80
+ return spawn(invocation.command, invocation.args, {
81
+ ...options,
82
+ shell: false,
83
+ windowsVerbatimArguments: true,
84
+ });
85
+ }
86
+ return spawn(resolvedCommand, args, {
23
87
  ...options,
24
- shell: options.shell ?? usesShellForSpawnCommand(command, platform),
88
+ shell: options.shell ?? false,
89
+ });
90
+ }
91
+
92
+ async function terminateProcessTree(child, graceMs) {
93
+ if (!child?.pid) return;
94
+ if (process.platform === "win32") {
95
+ await new Promise((resolve) => {
96
+ const killer = spawn("taskkill", ["/pid", String(child.pid), "/t", "/f"], {
97
+ stdio: "ignore",
98
+ windowsHide: true,
99
+ });
100
+ const fallback = setTimeout(() => {
101
+ try {
102
+ child.kill("SIGKILL");
103
+ } catch {
104
+ // The process tree may already be gone.
105
+ }
106
+ resolve();
107
+ }, graceMs);
108
+ killer.once("error", () => {
109
+ clearTimeout(fallback);
110
+ try {
111
+ child.kill("SIGKILL");
112
+ } catch {
113
+ // The process tree may already be gone.
114
+ }
115
+ resolve();
116
+ });
117
+ killer.once("close", () => {
118
+ clearTimeout(fallback);
119
+ resolve();
120
+ });
121
+ });
122
+ return;
123
+ }
124
+ try {
125
+ process.kill(-child.pid, "SIGTERM");
126
+ } catch {
127
+ return;
128
+ }
129
+ await new Promise((resolve) => setTimeout(resolve, graceMs));
130
+ try {
131
+ process.kill(-child.pid, "SIGKILL");
132
+ } catch {
133
+ // The process group exited during the grace period.
134
+ }
135
+ }
136
+
137
+ async function runInternalProcessTreeCommand() {
138
+ const payload = JSON.parse(fs.readFileSync(0, "utf8"));
139
+ const child = spawn(payload.command, payload.args, {
140
+ cwd: payload.cwd,
141
+ env: process.env,
142
+ detached: process.platform !== "win32",
143
+ stdio: ["ignore", "inherit", "inherit"],
144
+ windowsHide: true,
145
+ windowsVerbatimArguments: payload.windowsVerbatimArguments === true,
146
+ });
147
+ let timedOut = false;
148
+ let spawnError;
149
+ const closed = new Promise((resolve) => {
150
+ child.once("error", (error) => {
151
+ spawnError = error;
152
+ resolve({ code: 1, signal: "" });
153
+ });
154
+ child.once("close", (code, signal) => resolve({ code, signal }));
155
+ });
156
+ const timer = Number.isFinite(payload.timeoutMs) && payload.timeoutMs > 0
157
+ ? setTimeout(() => {
158
+ timedOut = true;
159
+ void terminateProcessTree(child, payload.graceMs);
160
+ }, payload.timeoutMs)
161
+ : undefined;
162
+ const result = await closed;
163
+ if (timer) clearTimeout(timer);
164
+ process.exitCode = timedOut
165
+ ? TIMEOUT_EXIT_CODE
166
+ : spawnError || result.signal
167
+ ? 1
168
+ : (result.code ?? 1);
169
+ }
170
+
171
+ function shellCommandInvocation(command, shell) {
172
+ if (typeof shell === "string" && shell.trim()) {
173
+ return { command: shell, args: ["-c", command] };
174
+ }
175
+ if (process.platform === "win32") {
176
+ return {
177
+ command: process.env.ComSpec || process.env.comspec || "cmd.exe",
178
+ args: ["/d", "/s", "/c", `"${command}"`],
179
+ windowsVerbatimArguments: true,
180
+ };
181
+ }
182
+ return { command: process.env.SHELL || "/bin/sh", args: ["-c", command] };
183
+ }
184
+
185
+ function standaloneProcessCommand(command, args, options) {
186
+ const result = spawnSync(command, args, { ...options, windowsHide: true });
187
+ if (result.error) throw result.error;
188
+ if (result.status !== 0 || result.signal) {
189
+ const error = new Error(`process tree command failed with status ${result.status ?? ""}`);
190
+ error.status = result.status ?? 1;
191
+ error.signal = result.signal || "";
192
+ throw error;
193
+ }
194
+ return result.stdout;
195
+ }
196
+
197
+ export function runProcessTreeCommandSync(command, args, {
198
+ cwd = process.cwd(),
199
+ env = process.env,
200
+ stdio = "inherit",
201
+ timeout,
202
+ graceMs = 2000,
203
+ windowsVerbatimArguments = false,
204
+ } = {}) {
205
+ if (runningStandaloneBundle()) {
206
+ return standaloneProcessCommand(command, args, { cwd, env, stdio, timeout });
207
+ }
208
+ const commandStdio = Array.isArray(stdio)
209
+ ? ["pipe", stdio[1] || "inherit", stdio[2] || "inherit"]
210
+ : ["pipe", stdio, stdio];
211
+ try {
212
+ return execFileSync(process.execPath, [modulePath, INTERNAL_PROCESS_TREE_COMMAND], {
213
+ cwd,
214
+ env,
215
+ stdio: commandStdio,
216
+ input: JSON.stringify({
217
+ command,
218
+ args,
219
+ cwd,
220
+ timeoutMs: timeout,
221
+ graceMs,
222
+ windowsVerbatimArguments,
223
+ }),
224
+ windowsHide: true,
225
+ });
226
+ } catch (error) {
227
+ if (error?.status === TIMEOUT_EXIT_CODE) error.code = "ETIMEDOUT";
228
+ throw error;
229
+ }
230
+ }
231
+
232
+ export function runShellCommandSync(command, options = {}) {
233
+ if (runningStandaloneBundle()) return execSync(command, options);
234
+ const invocation = shellCommandInvocation(command, options.shell);
235
+ return runProcessTreeCommandSync(invocation.command, invocation.args, {
236
+ ...options,
237
+ windowsVerbatimArguments: invocation.windowsVerbatimArguments,
238
+ });
239
+ }
240
+
241
+ if (
242
+ process.argv[1]
243
+ && process.argv[2] === INTERNAL_PROCESS_TREE_COMMAND
244
+ && import.meta.url === pathToFileURL(process.argv[1]).href
245
+ ) {
246
+ void runInternalProcessTreeCommand().catch((error) => {
247
+ console.error(`buildchain: process tree command failed: ${error.message}`);
248
+ process.exitCode = 1;
25
249
  });
26
250
  }
@@ -0,0 +1,219 @@
1
+ import { spawnSync } from "node:child_process";
2
+ import crypto from "node:crypto";
3
+ import path from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+
6
+ import {
7
+ adopterDeliveryGateDigest,
8
+ createAdopterDeliveryGate,
9
+ } from "./adopter-delivery-gate.js";
10
+
11
+ export const V4_ADOPTER_DELIVERY_PARITY_INPUT_CONTRACT =
12
+ "kungfu-buildchain-v4-adopter-delivery-parity-input";
13
+ export const V4_ADOPTER_DELIVERY_PARITY_PROJECTION_CONTRACT =
14
+ "buildchain-v4-adopter-delivery-parity-projection/v1";
15
+
16
+ const HOST_REQUEST_CONTRACT = "kungfu-buildchain-v4-host-request";
17
+ const HOST_RESPONSE_CONTRACT = "kungfu-buildchain-v4-host-response";
18
+ const DRIVER_INTERFACE = "kungfu-buildchain-adopter-protocol-driver/v1";
19
+ const PROFILE_INTERFACE = "kungfu-buildchain-adopter-artifact-profile/v1";
20
+ const REQUIRED_CAPABILITIES = Object.freeze([
21
+ "canonical-input-v1",
22
+ "adopter-delivery-parity-projection-v1",
23
+ "diagnostics-v1",
24
+ "effects-disabled-v1",
25
+ "structured-result-v1",
26
+ ]);
27
+ const MAX_RESPONSE_BYTES = 8 * 1024 * 1024;
28
+ const root = path.resolve(
29
+ path.dirname(fileURLToPath(import.meta.url)),
30
+ "../..",
31
+ );
32
+
33
+ export const V4_ADOPTER_DELIVERY_PARITY_SOURCE = Object.freeze({
34
+ v3Commit: "c3f58d76391c1c6ceddfc900a68e91c7ab82a575",
35
+ vectorSuiteRoot:
36
+ "sha256:cf329805d928a9883cbafbdfdf21ef66c6a0889ed8dfe14356b4e0d25d6738f9",
37
+ kfdPackage: "@kungfu-tech/kfd@1.0.0-alpha.62",
38
+ });
39
+
40
+ function clone(value) {
41
+ return structuredClone(value);
42
+ }
43
+
44
+ function exactKey(definition) {
45
+ return `${definition.id}@${definition.version}`;
46
+ }
47
+
48
+ function capture(operation) {
49
+ try {
50
+ return { state: "returned", result: clone(operation()) };
51
+ } catch {
52
+ return { state: "threw", result: null };
53
+ }
54
+ }
55
+
56
+ function definition(definition, execution, { profile = false } = {}) {
57
+ if (!definition) return null;
58
+ return {
59
+ interface: definition.interface,
60
+ id: definition.id,
61
+ version: definition.version,
62
+ ...(profile ? { kinds: [...definition.kinds] } : {}),
63
+ execution,
64
+ };
65
+ }
66
+
67
+ export function createV4AdopterDeliveryParityInput({
68
+ vectorId,
69
+ request,
70
+ context = {},
71
+ drivers = [],
72
+ artifactProfiles = [],
73
+ sourceAuthority = V4_ADOPTER_DELIVERY_PARITY_SOURCE,
74
+ } = {}) {
75
+ if (typeof vectorId !== "string" || vectorId.length === 0) {
76
+ throw new TypeError("vectorId must be a non-empty string");
77
+ }
78
+ const gate = createAdopterDeliveryGate({ drivers, artifactProfiles });
79
+ const expectedResult = gate.evaluate(clone(request), clone(context));
80
+ const driver = drivers.find(
81
+ (entry) =>
82
+ exactKey(entry) === `${request.protocol.id}@${request.protocol.version}`,
83
+ );
84
+ const artifactProfile = artifactProfiles.find(
85
+ (entry) =>
86
+ exactKey(entry) ===
87
+ `${request.artifactProfile.id}@${request.artifactProfile.version}`,
88
+ );
89
+ let profileExecution = null;
90
+ if (artifactProfile?.kinds.includes(request.artifact.kind)) {
91
+ profileExecution = capture(() =>
92
+ artifactProfile.verify(clone(request.artifact)),
93
+ );
94
+ }
95
+ let driverExecution = null;
96
+ if (
97
+ driver &&
98
+ profileExecution?.state === "returned" &&
99
+ profileExecution.result?.valid === true
100
+ ) {
101
+ driverExecution = capture(() =>
102
+ driver.verify({ request: clone(request), context: clone(context) }),
103
+ );
104
+ }
105
+ return {
106
+ schemaVersion: 1,
107
+ contract: V4_ADOPTER_DELIVERY_PARITY_INPUT_CONTRACT,
108
+ vectorId,
109
+ sourceAuthority: clone(sourceAuthority),
110
+ request: clone(request),
111
+ driver: definition(driver, driverExecution),
112
+ artifactProfile: definition(artifactProfile, profileExecution, {
113
+ profile: true,
114
+ }),
115
+ expectedResult,
116
+ };
117
+ }
118
+
119
+ function hostRequest(input, timeoutMs) {
120
+ return {
121
+ schemaVersion: 1,
122
+ contract: HOST_REQUEST_CONTRACT,
123
+ protocolVersion: "1.0",
124
+ requestId: crypto.randomUUID(),
125
+ command: { id: "adopter-delivery.parity-project", arguments: [] },
126
+ input: {
127
+ encoding: "base64",
128
+ bytes: Buffer.from(JSON.stringify(input), "utf8").toString("base64"),
129
+ },
130
+ requiredCapabilities: [...REQUIRED_CAPABILITIES],
131
+ timeoutMs,
132
+ };
133
+ }
134
+
135
+ export function runV4AdopterDeliveryParity(
136
+ input,
137
+ {
138
+ command = process.platform === "win32" ? "cargo.exe" : "cargo",
139
+ arguments: commandArguments = [
140
+ "run",
141
+ "--locked",
142
+ "--quiet",
143
+ "--manifest-path",
144
+ "crates/buildchain-v4-contracts/Cargo.toml",
145
+ "--",
146
+ "host",
147
+ ],
148
+ cwd = root,
149
+ timeoutMs = 30_000,
150
+ } = {},
151
+ ) {
152
+ if (!Number.isInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > 30_000) {
153
+ throw new RangeError("timeoutMs must be between 1 and 30000");
154
+ }
155
+ const request = hostRequest(input, timeoutMs);
156
+ const completed = spawnSync(command, commandArguments, {
157
+ cwd,
158
+ input: JSON.stringify(request),
159
+ encoding: "utf8",
160
+ timeout: timeoutMs,
161
+ maxBuffer: MAX_RESPONSE_BYTES,
162
+ env: process.env,
163
+ });
164
+ if (completed.error) {
165
+ throw new Error(
166
+ `v4 adopter delivery parity host failed: ${completed.error.message}`,
167
+ );
168
+ }
169
+ if (completed.status !== 0) {
170
+ throw new Error(
171
+ `v4 adopter delivery parity host exited ${completed.status}: ${completed.stderr.trim()}`,
172
+ );
173
+ }
174
+ let response;
175
+ try {
176
+ response = JSON.parse(completed.stdout);
177
+ } catch {
178
+ throw new Error("v4 adopter delivery parity host returned invalid JSON");
179
+ }
180
+ if (
181
+ response.schemaVersion !== 1 ||
182
+ response.contract !== HOST_RESPONSE_CONTRACT ||
183
+ response.protocolVersion !== "1.0" ||
184
+ response.requestId !== request.requestId ||
185
+ response.command?.id !== request.command.id ||
186
+ response.status !== "ok"
187
+ ) {
188
+ const code = response.diagnostics?.[0]?.code || "invalid-response";
189
+ throw new Error(`v4 adopter delivery parity failed closed: ${code}`);
190
+ }
191
+ const projection = response.structuredResult;
192
+ if (
193
+ projection?.schema !== V4_ADOPTER_DELIVERY_PARITY_PROJECTION_CONTRACT ||
194
+ projection.effectMode !== "disabled" ||
195
+ projection.vectorId !== input.vectorId ||
196
+ !/^sha256:[0-9a-f]{64}$/u.test(projection.projectionRoot || "")
197
+ ) {
198
+ throw new Error("v4 adopter delivery parity projection is invalid");
199
+ }
200
+ return projection;
201
+ }
202
+
203
+ export function assertV4AdopterDeliveryParity(input, options = {}) {
204
+ const projection = runV4AdopterDeliveryParity(input, options);
205
+ if (
206
+ adopterDeliveryGateDigest(projection.result) !==
207
+ adopterDeliveryGateDigest(input.expectedResult)
208
+ ) {
209
+ throw new Error(
210
+ "v4 adopter delivery parity result differs from v3 authority",
211
+ );
212
+ }
213
+ return projection;
214
+ }
215
+
216
+ export const V4_ADOPTER_DELIVERY_PARITY_INTERFACES = Object.freeze({
217
+ driver: DRIVER_INTERFACE,
218
+ artifactProfile: PROFILE_INTERFACE,
219
+ });