@kungfu-tech/buildchain 2.12.9-alpha.0 → 2.13.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 (37) hide show
  1. package/actions/run-lifecycle/README.md +5 -0
  2. package/bin/buildchain.mjs +62 -0
  3. package/dist/site/buildchain-contract.json +33 -23
  4. package/dist/site/buildchain-site.json +66 -30
  5. package/dist/site/capability-registry.json +3 -3
  6. package/dist/site/cli-registry.json +24 -0
  7. package/dist/site/controller-registry.json +11 -3
  8. package/dist/site/kfd-claims.json +64 -13
  9. package/dist/site/kfd-upstream-aggregate.json +1 -1
  10. package/dist/site/manual-registry.json +7 -7
  11. package/dist/site/node-api-registry.json +19 -6
  12. package/dist/site/page-registry.json +55 -19
  13. package/dist/site/public-surface-audit.json +47 -10
  14. package/dist/site/publication-registry.json +4 -4
  15. package/dist/site/release-provenance.json +1 -0
  16. package/dist/site/site-manifest.json +11 -11
  17. package/dist/site/workflow-registry.json +7 -4
  18. package/docs/MAP.md +1 -0
  19. package/docs/artifact-verification-envelope.md +113 -0
  20. package/docs/cli.md +22 -0
  21. package/docs/release-candidate.md +5 -0
  22. package/docs/release-governance.md +7 -0
  23. package/docs/release-propagation.md +3 -0
  24. package/docs/reusable-build-surface.md +13 -0
  25. package/docs/versioning.md +1 -0
  26. package/package.json +2 -1
  27. package/packages/core/README.md +13 -0
  28. package/packages/core/artifact-passport.js +6 -1
  29. package/packages/core/artifact-verification-envelope.js +386 -0
  30. package/packages/core/buildchain-config.js +6 -2
  31. package/packages/core/controller-evidence.js +2 -3
  32. package/packages/core/index.js +10 -0
  33. package/packages/core/release-line-bootstrap.js +24 -0
  34. package/scripts/check-inventory.mjs +5 -0
  35. package/scripts/generate-site-bundle.mjs +4 -0
  36. package/scripts/release-candidate-resolver.mjs +52 -29
  37. package/scripts/run-lifecycle-core.mjs +50 -6
@@ -97,6 +97,28 @@ function lifecycleErrorAttributes(error, extra = {}) {
97
97
  return attributes;
98
98
  }
99
99
 
100
+ function describeLifecycleTimeout(error, {
101
+ timeoutMinutes,
102
+ stageName,
103
+ platformId,
104
+ platformName,
105
+ }) {
106
+ if (
107
+ !timeoutMinutes ||
108
+ (error?.code !== "ETIMEDOUT" && error?.signal !== "SIGTERM")
109
+ ) {
110
+ return error;
111
+ }
112
+ const timeoutError = new Error(
113
+ `lifecycle ${stageName || "command"} timed out after ${timeoutMinutes} minute(s) on ${platformName} (${platformId})`,
114
+ { cause: error },
115
+ );
116
+ timeoutError.name = "LifecycleTimeoutError";
117
+ timeoutError.code = "ETIMEDOUT";
118
+ timeoutError.signal = error?.signal || "";
119
+ return timeoutError;
120
+ }
121
+
100
122
  function collectArtifactFiles(root, patterns) {
101
123
  const files = new Set();
102
124
  for (const pattern of patterns) {
@@ -245,9 +267,10 @@ function runLifecycleStageWithSampler({
245
267
  processSamplesPath,
246
268
  processSampleIntervalMs,
247
269
  requestedParallelism,
270
+ timeoutMinutes,
248
271
  }) {
249
272
  if (!sampleProcessTree) {
250
- return runLifecycleStage({ cwd, loadedConfig, name, env });
273
+ return runLifecycleStage({ cwd, loadedConfig, name, env, timeoutMinutes });
251
274
  }
252
275
  const lifecycle = loadedConfig?.config?.lifecycle || {};
253
276
  const stage = lifecycle[name];
@@ -260,7 +283,8 @@ function runLifecycleStageWithSampler({
260
283
  ...(stage.env || {}),
261
284
  ...(env || {}),
262
285
  };
263
- const timeout = stage.timeoutMinutes ? stage.timeoutMinutes * 60_000 : undefined;
286
+ const effectiveTimeoutMinutes = stage.timeoutMinutes ?? timeoutMinutes;
287
+ const timeout = effectiveTimeoutMinutes ? effectiveTimeoutMinutes * 60_000 : undefined;
264
288
  let lastError;
265
289
  for (let attempt = 1; attempt <= stage.retries; attempt += 1) {
266
290
  try {
@@ -362,6 +386,7 @@ export function runLifecycle({
362
386
  stageName = "",
363
387
  command = "",
364
388
  required = false,
389
+ timeoutMinutes,
365
390
  manifestPath = ".buildchain/artifacts/manifest.json",
366
391
  summaryPath = ".buildchain/artifacts/summary.json",
367
392
  diagnosticsPath = "",
@@ -381,6 +406,9 @@ export function runLifecycle({
381
406
  requestedParallelism = 0,
382
407
  processSummaryRequired = true,
383
408
  } = {}) {
409
+ if (timeoutMinutes !== undefined && (!Number.isFinite(timeoutMinutes) || timeoutMinutes <= 0)) {
410
+ throw new Error("lifecycle timeoutMinutes must be a positive number");
411
+ }
384
412
  const resolvedCwd = path.resolve(cwd);
385
413
  const resolvedWorkspace = path.resolve(workspace);
386
414
  const resolvedManifestPath = path.resolve(resolvedWorkspace, manifestPath);
@@ -449,6 +477,7 @@ export function runLifecycle({
449
477
  const lifecycle = loadedConfig?.config?.lifecycle || {};
450
478
  const configuredStage = stageName ? lifecycle[stageName] : undefined;
451
479
  const commandShell = configuredStage?.shell || true;
480
+ const effectiveCommandTimeoutMinutes = configuredStage?.timeoutMinutes ?? timeoutMinutes;
452
481
  const startedAt = Date.now();
453
482
  userLog.info("lifecycle.command.start", {
454
483
  attributes: {
@@ -480,6 +509,7 @@ export function runLifecycle({
480
509
  processSamplesPath: resolvedProcessSamplesPath,
481
510
  processSampleIntervalMs,
482
511
  requestedParallelism,
512
+ timeout: effectiveCommandTimeoutMinutes ? effectiveCommandTimeoutMinutes * 60_000 : undefined,
483
513
  });
484
514
  } else {
485
515
  execSync(command, {
@@ -487,6 +517,7 @@ export function runLifecycle({
487
517
  env: commandEnv,
488
518
  shell: commandShell,
489
519
  stdio: "inherit",
520
+ timeout: effectiveCommandTimeoutMinutes ? effectiveCommandTimeoutMinutes * 60_000 : undefined,
490
521
  });
491
522
  }
492
523
  executed = true;
@@ -498,16 +529,22 @@ export function runLifecycle({
498
529
  },
499
530
  });
500
531
  } catch (error) {
532
+ const lifecycleError = describeLifecycleTimeout(error, {
533
+ timeoutMinutes: effectiveCommandTimeoutMinutes,
534
+ stageName,
535
+ platformId,
536
+ platformName,
537
+ });
501
538
  userLog.error("lifecycle.command.error", {
502
539
  durationMs: Date.now() - startedAt,
503
540
  message: "lifecycle command failed",
504
- attributes: lifecycleErrorAttributes(error, {
541
+ attributes: lifecycleErrorAttributes(lifecycleError, {
505
542
  commandSource,
506
543
  stage: stageName || "command",
507
544
  sampleProcessTree,
508
545
  }),
509
546
  });
510
- throw error;
547
+ throw lifecycleError;
511
548
  }
512
549
  } else if (stageName) {
513
550
  commandSource = "buildchain.toml";
@@ -535,6 +572,7 @@ export function runLifecycle({
535
572
  processSamplesPath: resolvedProcessSamplesPath,
536
573
  processSampleIntervalMs,
537
574
  requestedParallelism,
575
+ timeoutMinutes,
538
576
  });
539
577
  userLog.info("lifecycle.stage.end", {
540
578
  durationMs: Date.now() - startedAt,
@@ -545,16 +583,22 @@ export function runLifecycle({
545
583
  },
546
584
  });
547
585
  } catch (error) {
586
+ const lifecycleError = describeLifecycleTimeout(error, {
587
+ timeoutMinutes: loadedConfig?.config?.lifecycle?.[stageName]?.timeoutMinutes ?? timeoutMinutes,
588
+ stageName,
589
+ platformId,
590
+ platformName,
591
+ });
548
592
  userLog.error("lifecycle.stage.error", {
549
593
  durationMs: Date.now() - startedAt,
550
594
  message: "lifecycle stage failed",
551
- attributes: lifecycleErrorAttributes(error, {
595
+ attributes: lifecycleErrorAttributes(lifecycleError, {
552
596
  commandSource,
553
597
  stage: stageName,
554
598
  sampleProcessTree,
555
599
  }),
556
600
  });
557
- throw error;
601
+ throw lifecycleError;
558
602
  }
559
603
  }
560
604