@treeseed/sdk 0.11.0 → 0.12.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.
- package/README.md +9 -4
- package/dist/agent-capacity.d.ts +916 -0
- package/dist/agent-capacity.js +1600 -0
- package/dist/agent-tools.d.ts +37 -0
- package/dist/agent-tools.js +301 -0
- package/dist/api/app.d.ts +1 -1
- package/dist/api/auth/d1-database.d.ts +2 -2
- package/dist/api/auth/d1-provider.d.ts +4 -4
- package/dist/api/auth/d1-store.d.ts +2 -2
- package/dist/api/auth/memory-provider.d.ts +1 -1
- package/dist/api/auth/tokens.d.ts +1 -1
- package/dist/api/config.d.ts +3 -1
- package/dist/api/config.js +34 -10
- package/dist/api/http.d.ts +2 -2
- package/dist/api/index.d.ts +10 -10
- package/dist/api/index.js +4 -2
- package/dist/api/operations-routes.d.ts +3 -3
- package/dist/api/operations.d.ts +1 -1
- package/dist/api/providers.d.ts +1 -1
- package/dist/api/providers.js +21 -4
- package/dist/api/railway.d.ts +3 -2
- package/dist/api/sdk-dispatch.d.ts +4 -4
- package/dist/api/sdk-routes.d.ts +2 -2
- package/dist/api/templates.d.ts +2 -2
- package/dist/api/types.d.ts +3 -2
- package/dist/capacity-provider.d.ts +117 -60
- package/dist/capacity-provider.js +215 -43
- package/dist/capacity.d.ts +2 -2
- package/dist/cli-tools.d.ts +1 -1
- package/dist/content-operations.d.ts +97 -0
- package/dist/content-operations.js +250 -0
- package/dist/content-store.d.ts +4 -4
- package/dist/control-plane-client.d.ts +13 -18
- package/dist/control-plane-client.js +8 -86
- package/dist/control-plane.d.ts +2 -2
- package/dist/copilot.d.ts +3 -0
- package/dist/copilot.js +16 -1
- package/dist/d1-http.d.ts +1 -1
- package/dist/d1-store.d.ts +32 -57
- package/dist/d1-store.js +115 -318
- package/dist/db/d1.d.ts +1 -232
- package/dist/db/index.d.ts +3 -3
- package/dist/db/market-schema.d.ts +49037 -11843
- package/dist/db/market-schema.js +1788 -50
- package/dist/db/node-sqlite.d.ts +1 -232
- package/dist/db/schema.d.ts +0 -462
- package/dist/db/schema.js +2 -22
- package/dist/dispatch.d.ts +1 -1
- package/dist/dispatch.js +0 -11
- package/dist/fixture-support.js +52 -4
- package/dist/governance.d.ts +133 -0
- package/dist/governance.js +285 -0
- package/dist/graph/build.d.ts +2 -2
- package/dist/graph/context-query-contracts.d.ts +1 -1
- package/dist/graph/dsl.d.ts +1 -1
- package/dist/graph/query.d.ts +4 -4
- package/dist/graph/ranking.d.ts +1 -1
- package/dist/graph/schema.d.ts +1 -1
- package/dist/graph.d.ts +11 -11
- package/dist/guarantees/index.d.ts +425 -0
- package/dist/guarantees/index.js +1146 -0
- package/dist/hosting/apps.d.ts +1 -1
- package/dist/hosting/builtins.d.ts +1 -1
- package/dist/hosting/builtins.js +9 -198
- package/dist/hosting/contracts.d.ts +3 -2
- package/dist/hosting/graph.d.ts +24 -21
- package/dist/hosting/graph.js +280 -294
- package/dist/hosting/index.d.ts +4 -4
- package/dist/index.d.ts +88 -74
- package/dist/index.js +81 -10
- package/dist/local-dev/managed-dev.d.ts +85 -0
- package/dist/local-dev/managed-dev.js +368 -0
- package/dist/managed-dependencies.d.ts +9 -0
- package/dist/managed-dependencies.js +10 -8
- package/dist/market-client.d.ts +265 -7
- package/dist/market-client.js +381 -9
- package/dist/model-registry.d.ts +1 -1
- package/dist/model-registry.js +19 -19
- package/dist/operations/agent-tools.d.ts +2 -11
- package/dist/operations/agent-tools.js +2 -14
- package/dist/operations/providers/default.d.ts +1 -1
- package/dist/operations/providers/default.js +20 -37
- package/dist/operations/repository-operations.d.ts +26 -2
- package/dist/operations/repository-operations.js +159 -1
- package/dist/operations/runtime.d.ts +3 -3
- package/dist/operations/services/bootstrap-runner.d.ts +1 -1
- package/dist/operations/services/build-warning-policy.d.ts +34 -0
- package/dist/operations/services/build-warning-policy.js +81 -82
- package/dist/operations/services/commit-message-provider.js +4 -4
- package/dist/operations/services/config-runtime.d.ts +73 -19
- package/dist/operations/services/config-runtime.js +276 -100
- package/dist/operations/services/deploy.d.ts +41 -622
- package/dist/operations/services/deploy.js +181 -213
- package/dist/operations/services/deployment-readiness.d.ts +1 -1
- package/dist/operations/services/deployment-readiness.js +38 -7
- package/dist/operations/services/git-remote-policy.js +12 -4
- package/dist/operations/services/git-runner.d.ts +66 -0
- package/dist/operations/services/git-runner.js +479 -0
- package/dist/operations/services/git-workflow.d.ts +43 -5
- package/dist/operations/services/git-workflow.js +242 -20
- package/dist/operations/services/github-actions-verification.d.ts +3 -1
- package/dist/operations/services/github-actions-verification.js +11 -3
- package/dist/operations/services/github-api.js +21 -5
- package/dist/operations/services/github-automation.d.ts +3 -3
- package/dist/operations/services/github-automation.js +15 -18
- package/dist/operations/services/github-credentials.js +2 -1
- package/dist/operations/services/hosted-service-checks.d.ts +19 -1
- package/dist/operations/services/hosted-service-checks.js +162 -11
- package/dist/operations/services/hosting-audit.d.ts +2 -2
- package/dist/operations/services/hosting-audit.js +7 -7
- package/dist/operations/services/hub-launch.d.ts +1 -1
- package/dist/operations/services/hub-provider-launch.d.ts +5 -5
- package/dist/operations/services/hub-provider-launch.js +19 -14
- package/dist/operations/services/live-hosted-service-checks.d.ts +2 -1
- package/dist/operations/services/live-hosted-service-checks.js +193 -80
- package/dist/operations/services/local-dev.js +0 -1
- package/dist/operations/services/managed-host-security.d.ts +1 -1
- package/dist/operations/services/managed-repositories.d.ts +37 -0
- package/dist/operations/services/managed-repositories.js +177 -0
- package/dist/operations/services/operations-runner-smoke.d.ts +3 -2
- package/dist/operations/services/operations-runner-smoke.js +22 -4
- package/dist/operations/services/package-adapters.d.ts +77 -2
- package/dist/operations/services/package-adapters.js +627 -56
- package/dist/operations/services/package-reference-policy.d.ts +12 -88
- package/dist/operations/services/package-reference-policy.js +81 -213
- package/dist/operations/services/project-host-operations.d.ts +4 -4
- package/dist/operations/services/project-platform.d.ts +19 -193
- package/dist/operations/services/project-platform.js +31 -103
- package/dist/operations/services/project-web-monitor.d.ts +2 -2
- package/dist/operations/services/project-web-monitor.js +97 -2
- package/dist/operations/services/railway-api.d.ts +36 -7
- package/dist/operations/services/railway-api.js +331 -100
- package/dist/operations/services/railway-deploy.d.ts +7 -95
- package/dist/operations/services/railway-deploy.js +334 -742
- package/dist/operations/services/release-history.js +3 -4
- package/dist/operations/services/release-proof-ledger.d.ts +13 -0
- package/dist/operations/services/release-proof-ledger.js +81 -0
- package/dist/operations/services/release-proof-planner.d.ts +48 -0
- package/dist/operations/services/release-proof-planner.js +195 -0
- package/dist/operations/services/release-proof-runner.d.ts +16 -0
- package/dist/operations/services/release-proof-runner.js +169 -0
- package/dist/operations/services/release-proof.d.ts +81 -0
- package/dist/operations/services/release-proof.js +79 -0
- package/dist/operations/services/repository-save-orchestrator.d.ts +6 -7
- package/dist/operations/services/repository-save-orchestrator.js +353 -174
- package/dist/operations/services/runtime-paths.d.ts +1 -3
- package/dist/operations/services/runtime-paths.js +0 -4
- package/dist/operations/services/runtime-tools.d.ts +1 -192
- package/dist/operations/services/runtime-tools.js +4 -444
- package/dist/operations/services/save-deploy-preflight.js +9 -1
- package/dist/operations/services/template-host-bindings.d.ts +2 -2
- package/dist/operations/services/template-host-bindings.js +3 -2
- package/dist/operations/services/template-registry.d.ts +6 -6
- package/dist/operations/services/template-registry.js +33 -14
- package/dist/operations/services/template-secret-sync.d.ts +3 -3
- package/dist/operations/services/workflow-timing.d.ts +25 -0
- package/dist/operations/services/workflow-timing.js +79 -0
- package/dist/operations/services/workspace-dependency-mode.js +41 -4
- package/dist/operations/services/workspace-preflight.js +8 -8
- package/dist/operations/services/workspace-save-script.d.ts +4 -4
- package/dist/operations/services/workspace-save.d.ts +1 -0
- package/dist/operations/services/workspace-save.js +41 -18
- package/dist/operations/services/workspace-tools.js +40 -6
- package/dist/operations-registry.d.ts +1 -1
- package/dist/operations-registry.js +5 -6
- package/dist/operations-types.d.ts +1 -1
- package/dist/operations.d.ts +17 -11
- package/dist/operations.js +57 -3
- package/dist/platform/book-export.js +2 -0
- package/dist/platform/books-data.d.ts +1 -1
- package/dist/platform/config.d.ts +27 -0
- package/dist/platform/config.js +100 -0
- package/dist/platform/content-runtime-source.d.ts +54 -0
- package/dist/platform/content-runtime-source.js +169 -0
- package/dist/platform/contracts.d.ts +6 -1
- package/dist/platform/deploy-config.d.ts +1 -1
- package/dist/platform/deploy-config.js +7 -1
- package/dist/platform/deploy-runtime.d.ts +1 -1
- package/dist/platform/desired-state.d.ts +63 -0
- package/dist/platform/desired-state.js +1021 -0
- package/dist/platform/env.yaml +414 -19
- package/dist/platform/environment.d.ts +2 -2
- package/dist/platform/environment.js +54 -22
- package/dist/platform/local-content-materialization.d.ts +9 -0
- package/dist/platform/local-content-materialization.js +212 -0
- package/dist/platform/plugin.d.ts +5 -5
- package/dist/platform/plugins/runtime.d.ts +3 -3
- package/dist/platform/plugins/runtime.js +62 -1
- package/dist/platform/plugins.d.ts +6 -6
- package/dist/platform/published-content-pipeline.d.ts +3 -3
- package/dist/platform/published-content-pipeline.js +5 -1
- package/dist/platform/published-content.d.ts +4 -3
- package/dist/platform/site-config-schema.d.ts +1 -0
- package/dist/platform/site-config-schema.js +4 -1
- package/dist/platform/tenant/runtime-config.d.ts +152 -2
- package/dist/platform/tenant-config.d.ts +1 -1
- package/dist/platform/utils/site-config-schema.d.ts +154 -0
- package/dist/platform/utils/site-config-schema.js +400 -461
- package/dist/platform-operation-store.d.ts +1 -1
- package/dist/plugin-default.d.ts +1 -1
- package/dist/plugin-default.js +27 -12
- package/dist/project-import.d.ts +91 -0
- package/dist/project-import.js +257 -0
- package/dist/project-workflow.d.ts +1 -1
- package/dist/reconcile/bootstrap-systems.d.ts +2 -2
- package/dist/reconcile/bootstrap-systems.js +3 -3
- package/dist/reconcile/builtin-adapters.d.ts +7 -1
- package/dist/reconcile/builtin-adapters.js +2924 -346
- package/dist/reconcile/contracts.d.ts +15 -2
- package/dist/reconcile/desired-state.d.ts +2 -193
- package/dist/reconcile/desired-state.js +24 -33
- package/dist/reconcile/engine.d.ts +60 -397
- package/dist/reconcile/engine.js +182 -18
- package/dist/reconcile/index.d.ts +10 -10
- package/dist/reconcile/live-acceptance.d.ts +22 -1
- package/dist/reconcile/live-acceptance.js +456 -44
- package/dist/reconcile/providers/docker-private.d.ts +54 -0
- package/dist/reconcile/providers/docker-private.js +101 -0
- package/dist/reconcile/providers/github-private.d.ts +65 -0
- package/dist/reconcile/providers/github-private.js +119 -0
- package/dist/reconcile/providers/local-private.d.ts +28 -0
- package/dist/reconcile/providers/local-private.js +75 -0
- package/dist/reconcile/providers/railway-iac.d.ts +66 -0
- package/dist/reconcile/providers/railway-iac.js +275 -0
- package/dist/reconcile/providers/release-private.d.ts +92 -0
- package/dist/reconcile/providers/release-private.js +152 -0
- package/dist/reconcile/registry.d.ts +2 -2
- package/dist/reconcile/registry.js +16 -1
- package/dist/reconcile/state.d.ts +1 -1
- package/dist/reconcile/state.js +3 -40
- package/dist/reconcile/units.d.ts +1 -1
- package/dist/reconcile/units.js +7 -1
- package/dist/remote.d.ts +6 -6
- package/dist/scenes/artifacts.d.ts +16 -0
- package/dist/scenes/artifacts.js +61 -0
- package/dist/scenes/auth.d.ts +2 -0
- package/dist/scenes/auth.js +28 -0
- package/dist/scenes/base-url.d.ts +12 -0
- package/dist/scenes/base-url.js +123 -0
- package/dist/scenes/builtin-plugins.d.ts +2 -0
- package/dist/scenes/builtin-plugins.js +447 -0
- package/dist/scenes/checkpoints.d.ts +14 -0
- package/dist/scenes/checkpoints.js +33 -0
- package/dist/scenes/device-matrix.d.ts +2 -0
- package/dist/scenes/device-matrix.js +97 -0
- package/dist/scenes/devices.d.ts +11 -0
- package/dist/scenes/devices.js +22 -0
- package/dist/scenes/diagnostics.d.ts +5 -0
- package/dist/scenes/diagnostics.js +22 -0
- package/dist/scenes/diagram-providers.d.ts +2 -0
- package/dist/scenes/diagram-providers.js +181 -0
- package/dist/scenes/diagram-validation.d.ts +22 -0
- package/dist/scenes/diagram-validation.js +74 -0
- package/dist/scenes/environment.d.ts +2 -0
- package/dist/scenes/environment.js +65 -0
- package/dist/scenes/evidence-bundle.d.ts +5 -0
- package/dist/scenes/evidence-bundle.js +42 -0
- package/dist/scenes/evidence-report.d.ts +10 -0
- package/dist/scenes/evidence-report.js +73 -0
- package/dist/scenes/evidence.d.ts +16 -0
- package/dist/scenes/evidence.js +277 -0
- package/dist/scenes/index.d.ts +48 -0
- package/dist/scenes/index.js +312 -0
- package/dist/scenes/inspect.d.ts +9 -0
- package/dist/scenes/inspect.js +64 -0
- package/dist/scenes/loader.d.ts +3 -0
- package/dist/scenes/loader.js +38 -0
- package/dist/scenes/logs.d.ts +2 -0
- package/dist/scenes/logs.js +47 -0
- package/dist/scenes/operations.d.ts +3 -0
- package/dist/scenes/operations.js +128 -0
- package/dist/scenes/phase0.d.ts +9 -0
- package/dist/scenes/phase0.js +637 -0
- package/dist/scenes/planner.d.ts +12 -0
- package/dist/scenes/planner.js +166 -0
- package/dist/scenes/playwright-adapter.d.ts +2 -0
- package/dist/scenes/playwright-adapter.js +63 -0
- package/dist/scenes/plugins.d.ts +5 -0
- package/dist/scenes/plugins.js +115 -0
- package/dist/scenes/progress.d.ts +17 -0
- package/dist/scenes/progress.js +24 -0
- package/dist/scenes/publish-destinations.d.ts +12 -0
- package/dist/scenes/publish-destinations.js +99 -0
- package/dist/scenes/publish-plan-report.d.ts +10 -0
- package/dist/scenes/publish-plan-report.js +70 -0
- package/dist/scenes/publish-plan.d.ts +15 -0
- package/dist/scenes/publish-plan.js +248 -0
- package/dist/scenes/publish-redaction.d.ts +16 -0
- package/dist/scenes/publish-redaction.js +148 -0
- package/dist/scenes/publish-release-record.d.ts +13 -0
- package/dist/scenes/publish-release-record.js +34 -0
- package/dist/scenes/publish-report.d.ts +10 -0
- package/dist/scenes/publish-report.js +67 -0
- package/dist/scenes/publish.d.ts +16 -0
- package/dist/scenes/publish.js +298 -0
- package/dist/scenes/registry.d.ts +12 -0
- package/dist/scenes/registry.js +65 -0
- package/dist/scenes/remotion-adapter.d.ts +3 -0
- package/dist/scenes/remotion-adapter.js +94 -0
- package/dist/scenes/remotion-composition-registry.d.ts +2 -0
- package/dist/scenes/remotion-composition-registry.js +12 -0
- package/dist/scenes/remotion-compositions.d.ts +15 -0
- package/dist/scenes/remotion-compositions.js +464 -0
- package/dist/scenes/remotion-diagrams.d.ts +9 -0
- package/dist/scenes/remotion-diagrams.js +188 -0
- package/dist/scenes/remotion-input.d.ts +13 -0
- package/dist/scenes/remotion-input.js +291 -0
- package/dist/scenes/remotion-visuals.d.ts +29 -0
- package/dist/scenes/remotion-visuals.js +198 -0
- package/dist/scenes/render-media-assets.d.ts +9 -0
- package/dist/scenes/render-media-assets.js +117 -0
- package/dist/scenes/render-report.d.ts +10 -0
- package/dist/scenes/render-report.js +27 -0
- package/dist/scenes/render.d.ts +2 -0
- package/dist/scenes/render.js +218 -0
- package/dist/scenes/reporter.d.ts +3 -0
- package/dist/scenes/reporter.js +101 -0
- package/dist/scenes/resume.d.ts +2 -0
- package/dist/scenes/resume.js +79 -0
- package/dist/scenes/runner.d.ts +2 -0
- package/dist/scenes/runner.js +674 -0
- package/dist/scenes/schema.d.ts +6 -0
- package/dist/scenes/schema.js +994 -0
- package/dist/scenes/seed.d.ts +2 -0
- package/dist/scenes/seed.js +83 -0
- package/dist/scenes/segments.d.ts +15 -0
- package/dist/scenes/segments.js +79 -0
- package/dist/scenes/selectors.d.ts +3 -0
- package/dist/scenes/selectors.js +21 -0
- package/dist/scenes/timeline.d.ts +11 -0
- package/dist/scenes/timeline.js +26 -0
- package/dist/scenes/timeouts.d.ts +6 -0
- package/dist/scenes/timeouts.js +17 -0
- package/dist/scenes/training-captions.d.ts +14 -0
- package/dist/scenes/training-captions.js +98 -0
- package/dist/scenes/training-report.d.ts +10 -0
- package/dist/scenes/training-report.js +78 -0
- package/dist/scenes/training-transcript.d.ts +24 -0
- package/dist/scenes/training-transcript.js +204 -0
- package/dist/scenes/training.d.ts +10 -0
- package/dist/scenes/training.js +134 -0
- package/dist/scenes/types.d.ts +1872 -0
- package/dist/scenes/types.js +8 -0
- package/dist/scenes/visual-audit-contact-sheets.d.ts +6 -0
- package/dist/scenes/visual-audit-contact-sheets.js +119 -0
- package/dist/scenes/visual-audit-fixtures.d.ts +25 -0
- package/dist/scenes/visual-audit-fixtures.js +210 -0
- package/dist/scenes/visual-audit-report.d.ts +11 -0
- package/dist/scenes/visual-audit-report.js +85 -0
- package/dist/scenes/visual-audit-review.d.ts +23 -0
- package/dist/scenes/visual-audit-review.js +829 -0
- package/dist/scenes/visual-audit-routes.d.ts +13 -0
- package/dist/scenes/visual-audit-routes.js +308 -0
- package/dist/scenes/visual-audit.d.ts +3 -0
- package/dist/scenes/visual-audit.js +596 -0
- package/dist/scripts/build-dist.js +154 -40
- package/dist/scripts/check-build-warnings.js +42 -53
- package/dist/scripts/cleanup-markdown.js +1 -1
- package/dist/scripts/cli-test-fixtures.js +24 -28
- package/dist/scripts/migrate-journey-csv-to-guarantees.js +140 -0
- package/dist/scripts/package-tools.js +12 -1
- package/dist/scripts/prepare.js +3 -7
- package/dist/scripts/release-verify.js +2 -5
- package/dist/scripts/run-fixture-astro-command.js +1 -1
- package/dist/scripts/template-catalog.test.js +68 -82
- package/dist/scripts/tenant-dev.js +0 -10
- package/dist/scripts/test-cloudflare-local.js +1 -1
- package/dist/scripts/test-scaffold.js +0 -1
- package/dist/scripts/test-smoke.js +3 -3
- package/dist/scripts/treeseed-build-dist.js +4 -7
- package/dist/scripts/treeseed-release-verify.js +1 -1
- package/dist/scripts/verify-driver.js +30 -21
- package/dist/scripts/workflow-commands.test.js +18 -27
- package/dist/scripts/workspace-command-e2e.js +1 -1
- package/dist/scripts/workspace-lint.js +6 -0
- package/dist/scripts/workspace-release-test.js +90 -1
- package/dist/scripts/workspace-test.js +6 -0
- package/dist/sdk-dispatch.d.ts +1 -1
- package/dist/sdk-dispatch.js +0 -16
- package/dist/sdk-fields.d.ts +1 -1
- package/dist/sdk-filters.d.ts +1 -1
- package/dist/sdk-types.d.ts +1184 -113
- package/dist/sdk-types.js +393 -0
- package/dist/sdk.d.ts +74 -79
- package/dist/sdk.js +27 -36
- package/dist/secrets-capability.d.ts +421 -0
- package/dist/secrets-capability.js +530 -0
- package/dist/seeds/normalize.js +1 -0
- package/dist/seeds/planner.js +38 -0
- package/dist/seeds/schema.js +293 -4
- package/dist/seeds/types.d.ts +60 -0
- package/dist/seeds/types.js +9 -1
- package/dist/service-credentials.d.ts +54 -0
- package/dist/service-credentials.js +112 -0
- package/dist/stores/cursor-store.d.ts +2 -2
- package/dist/stores/envelopes.d.ts +1 -1
- package/dist/stores/helpers.d.ts +1 -1
- package/dist/stores/lease-store.d.ts +2 -2
- package/dist/stores/message-store.d.ts +2 -2
- package/dist/stores/operational-store.d.ts +3 -26
- package/dist/stores/operational-store.js +0 -225
- package/dist/stores/project-workflow-store.d.ts +2 -2
- package/dist/stores/run-store.d.ts +2 -3
- package/dist/stores/run-store.js +0 -98
- package/dist/stores/subscription-store.d.ts +2 -3
- package/dist/stores/subscription-store.js +0 -100
- package/dist/template-catalog.d.ts +1 -1
- package/dist/template-launch-requirements.d.ts +2 -2
- package/dist/template-launch-ui.d.ts +2 -2
- package/dist/treedx/adapters.d.ts +6 -6
- package/dist/treedx/client.d.ts +1 -1
- package/dist/treedx/errors.d.ts +1 -1
- package/dist/treedx/federated-client.d.ts +3 -3
- package/dist/treedx/graph-adapter.d.ts +2 -2
- package/dist/treedx/index.d.ts +14 -14
- package/dist/treedx/market-integration.d.ts +1 -1
- package/dist/treedx/ports.d.ts +30 -30
- package/dist/treedx/query-adapter.d.ts +3 -3
- package/dist/treedx/registry-client.d.ts +2 -2
- package/dist/treedx/repository-adapter.d.ts +4 -4
- package/dist/treedx/repository-adapter.js +14 -3
- package/dist/treedx/sdk-integration.d.ts +3 -3
- package/dist/treedx/types.d.ts +2 -2
- package/dist/treedx/workspace-adapter.d.ts +2 -2
- package/dist/treedx-backends.d.ts +13 -11
- package/dist/treedx-backends.js +52 -50
- package/dist/treedx-client.d.ts +3 -0
- package/dist/treedx-client.js +10 -1
- package/dist/treeseed/services/compose.yml +2 -3
- package/dist/treeseed/template-catalog/catalog.fixture.json +4 -4
- package/dist/types/agents.d.ts +256 -0
- package/dist/types/agents.js +42 -1
- package/dist/verification.d.ts +1 -0
- package/dist/verification.js +143 -14
- package/dist/workflow/operations.d.ts +510 -559
- package/dist/workflow/operations.js +1891 -1342
- package/dist/workflow/policy.js +19 -7
- package/dist/workflow/runs.d.ts +9 -3
- package/dist/workflow/runs.js +66 -26
- package/dist/workflow/session.d.ts +4 -1
- package/dist/workflow/session.js +50 -10
- package/dist/workflow/worktrees.d.ts +6 -2
- package/dist/workflow/worktrees.js +98 -15
- package/dist/workflow-state.d.ts +5 -5
- package/dist/workflow-state.js +27 -17
- package/dist/workflow-support.d.ts +26 -25
- package/dist/workflow-support.js +27 -31
- package/dist/workflow.d.ts +46 -16
- package/dist/workflow.js +19 -7
- package/drizzle/d1/0000_treeseed_d1.sql +0 -18
- package/drizzle/market/0000_market_control_plane.sql +1793 -1499
- package/drizzle/market/0005_agent_capacity_coordination.sql +145 -0
- package/drizzle/market/0006_provider_assignment_lifecycle.sql +9 -0
- package/drizzle/market/0007_agent_architecture_gap_closure.sql +157 -0
- package/drizzle/market/0008_agent_capacity_operational_closure.sql +27 -0
- package/drizzle/market/0009_agent_capacity_runtime_hardening.sql +29 -0
- package/drizzle/market/0010_secrets_capability_persistence.sql +130 -0
- package/drizzle/market/0011_github_app_adapter.sql +47 -0
- package/drizzle/market/0012_workday_test_runs.sql +44 -0
- package/drizzle/market/0013_runtime_task_lifecycle.sql +39 -0
- package/drizzle/market/0014_governance_pipeline.sql +189 -0
- package/package.json +75 -18
- package/scripts/{verify-driver.mjs → verify-driver.ts} +19 -4
- package/templates/github/deploy-web.workflow.yml +12 -8
- package/dist/operations/services/mailpit-runtime.d.ts +0 -20
- package/dist/operations/services/mailpit-runtime.js +0 -67
- package/dist/operations/services/release-candidate.d.ts +0 -60
- package/dist/operations/services/release-candidate.js +0 -953
- package/dist/scripts/ensure-mailpit.js +0 -48
- package/dist/scripts/logs-mailpit.js +0 -2
- package/dist/scripts/run-ts.js +0 -45
- package/dist/scripts/stop-mailpit.js +0 -5
- package/dist/scripts/treeseed-run-ts.js +0 -45
|
@@ -1,953 +0,0 @@
|
|
|
1
|
-
import { createHash } from "node:crypto";
|
|
2
|
-
import { spawnSync } from "node:child_process";
|
|
3
|
-
import { cpSync, existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
4
|
-
import { tmpdir } from "node:os";
|
|
5
|
-
import { dirname, join, relative, resolve } from "node:path";
|
|
6
|
-
import { isTreeseedEnvironmentEntryRelevant, isTreeseedEnvironmentEntryRequired } from "../../platform/environment.js";
|
|
7
|
-
import { maybeResolveGitHubRepositorySlug } from "./github-automation.js";
|
|
8
|
-
import { createGitHubApiClient, listGitHubEnvironmentSecretNames, listGitHubEnvironmentVariableNames } from "./github-api.js";
|
|
9
|
-
import { resolveGitHubCredentialForRepository } from "./github-credentials.js";
|
|
10
|
-
import { collectInternalDevReferenceIssues, installableInternalDependencyVersions, normalizeGitRemoteForManifest } from "./package-reference-policy.js";
|
|
11
|
-
import { collectTreeseedEnvironmentContext, resolveTreeseedMachineEnvironmentValues, validateTreeseedCommandEnvironment } from "./config-runtime.js";
|
|
12
|
-
import { loadDeployState } from "./deploy.js";
|
|
13
|
-
import { loadCliDeployConfig } from "./runtime-tools.js";
|
|
14
|
-
import { packagesWithScript, run, workspacePackages } from "./workspace-tools.js";
|
|
15
|
-
import { createBuildWarningSummary, formatAllowedBuildWarnings } from "./build-warning-policy.js";
|
|
16
|
-
import { discoverTreeseedPackageAdapters } from "./package-adapters.js";
|
|
17
|
-
const RELEASE_CANDIDATE_CACHE_DIR = ".treeseed/workflow/release-candidates";
|
|
18
|
-
const RELEASE_CANDIDATE_POLICY_VERSION = "package-adapters-v2-hybrid";
|
|
19
|
-
const RELEASE_CANDIDATE_TOPOLOGY_POLICY_VERSION = "topology-v1";
|
|
20
|
-
const STABLE_SEMVER = /^\d+\.\d+\.\d+$/u;
|
|
21
|
-
const INTERNAL_DEPENDENCY_FIELDS = ["dependencies", "optionalDependencies", "peerDependencies", "devDependencies"];
|
|
22
|
-
const TOPOLOGY_SCRIPT_PREFIXES = ["build", "check", "prepare", "prepack", "postpack", "release:", "verify", "sandbox:"];
|
|
23
|
-
const REHEARSAL_IGNORED_SEGMENTS = /* @__PURE__ */ new Set([
|
|
24
|
-
".git",
|
|
25
|
-
".treeseed",
|
|
26
|
-
".wrangler",
|
|
27
|
-
".astro",
|
|
28
|
-
"coverage",
|
|
29
|
-
"dist",
|
|
30
|
-
"node_modules"
|
|
31
|
-
]);
|
|
32
|
-
const ROOT_WEB_EXCLUDED_DEPLOY_CONFIG_IDS = /* @__PURE__ */ new Set([
|
|
33
|
-
"DOCKERHUB_TOKEN",
|
|
34
|
-
"SECRET_KEY_BASE",
|
|
35
|
-
"TREEDX_JWT_HS256_SECRET",
|
|
36
|
-
"TREESEED_CREDENTIAL_SESSION_SECRET",
|
|
37
|
-
"TREESEED_PLATFORM_RUNNER_SECRET"
|
|
38
|
-
]);
|
|
39
|
-
const API_APP_SERVICE_TARGETS = /* @__PURE__ */ new Set([
|
|
40
|
-
"api",
|
|
41
|
-
"operationsRunner",
|
|
42
|
-
"marketOperationsRunner",
|
|
43
|
-
"publicTreeDxFederation",
|
|
44
|
-
"publicTreeDxNode",
|
|
45
|
-
"treedx",
|
|
46
|
-
"treeDx"
|
|
47
|
-
]);
|
|
48
|
-
function nowIso() {
|
|
49
|
-
return (/* @__PURE__ */ new Date()).toISOString();
|
|
50
|
-
}
|
|
51
|
-
function sortedRecord(record) {
|
|
52
|
-
return Object.fromEntries(Object.entries(record).sort(([left], [right]) => left.localeCompare(right)));
|
|
53
|
-
}
|
|
54
|
-
function sha256(value) {
|
|
55
|
-
return createHash("sha256").update(value).digest("hex");
|
|
56
|
-
}
|
|
57
|
-
function fileSha256(filePath) {
|
|
58
|
-
if (!existsSync(filePath)) return null;
|
|
59
|
-
return createHash("sha256").update(readFileSync(filePath)).digest("hex");
|
|
60
|
-
}
|
|
61
|
-
function safeGitHead(repoDir) {
|
|
62
|
-
try {
|
|
63
|
-
return run("git", ["rev-parse", "HEAD"], { cwd: repoDir, capture: true }).trim();
|
|
64
|
-
} catch {
|
|
65
|
-
return null;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
function safePackageJson(filePath) {
|
|
69
|
-
try {
|
|
70
|
-
return JSON.parse(readFileSync(filePath, "utf8"));
|
|
71
|
-
} catch {
|
|
72
|
-
return null;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
function dockerManifestCheckMode() {
|
|
76
|
-
return process.env.TREESEED_RELEASE_CANDIDATE_DOCKER_MANIFEST_MODE === "check" ? "check" : "skip";
|
|
77
|
-
}
|
|
78
|
-
function writeJsonFile(filePath, value) {
|
|
79
|
-
writeFileSync(filePath, `${JSON.stringify(value, null, 2)}
|
|
80
|
-
`, "utf8");
|
|
81
|
-
}
|
|
82
|
-
function packageScripts(filePath) {
|
|
83
|
-
const packageJson = safePackageJson(filePath);
|
|
84
|
-
return packageJson?.scripts && typeof packageJson.scripts === "object" && !Array.isArray(packageJson.scripts) ? packageJson.scripts : {};
|
|
85
|
-
}
|
|
86
|
-
function releaseCandidateCachePath(root, key) {
|
|
87
|
-
return resolve(root, RELEASE_CANDIDATE_CACHE_DIR, `${key}.json`);
|
|
88
|
-
}
|
|
89
|
-
function releaseCandidateTopologyCachePath(root, key) {
|
|
90
|
-
return resolve(root, RELEASE_CANDIDATE_CACHE_DIR, `topology-${key}.json`);
|
|
91
|
-
}
|
|
92
|
-
function ensureReleaseCandidateCacheDir(root) {
|
|
93
|
-
const dir = resolve(root, RELEASE_CANDIDATE_CACHE_DIR);
|
|
94
|
-
mkdirSync(dir, { recursive: true });
|
|
95
|
-
const gitignorePath = resolve(root, ".treeseed", "workflow", ".gitignore");
|
|
96
|
-
mkdirSync(dirname(gitignorePath), { recursive: true });
|
|
97
|
-
if (!existsSync(gitignorePath)) {
|
|
98
|
-
writeFileSync(gitignorePath, "*\n!.gitignore\n!runs/\nruns/*\n!runs/.gitignore\n", "utf8");
|
|
99
|
-
}
|
|
100
|
-
return dir;
|
|
101
|
-
}
|
|
102
|
-
function buildReleaseCandidateFingerprint(input) {
|
|
103
|
-
const selectedPackages = [...new Set((input.selectedPackageNames ?? []).map(String))].sort();
|
|
104
|
-
const selectedPackageSet = new Set(selectedPackages);
|
|
105
|
-
const packages = discoverTreeseedPackageAdapters(input.root).filter((pkg) => selectedPackageSet.size === 0 || selectedPackageSet.has(pkg.id) || selectedPackageSet.has(pkg.name));
|
|
106
|
-
const packageShas = sortedRecord(Object.fromEntries(
|
|
107
|
-
packages.map((pkg) => [pkg.id, safeGitHead(pkg.dir)])
|
|
108
|
-
));
|
|
109
|
-
const plannedVersions = sortedRecord(Object.fromEntries(
|
|
110
|
-
Object.entries(input.plannedVersions).filter(([name]) => name === "@treeseed/market" || selectedPackageSet.has(name)).map(([name, version]) => [name, String(version)])
|
|
111
|
-
));
|
|
112
|
-
const lockfiles = sortedRecord({
|
|
113
|
-
"@treeseed/market": fileSha256(resolve(input.root, "package-lock.json")),
|
|
114
|
-
...Object.fromEntries(packages.map((pkg) => [
|
|
115
|
-
pkg.id,
|
|
116
|
-
pkg.kind === "node-typescript" ? fileSha256(resolve(pkg.dir, "package-lock.json")) : fileSha256(resolve(pkg.dir, "Cargo.lock")) ?? fileSha256(resolve(pkg.dir, "mix.lock"))
|
|
117
|
-
]))
|
|
118
|
-
});
|
|
119
|
-
const base = {
|
|
120
|
-
policyVersion: RELEASE_CANDIDATE_POLICY_VERSION,
|
|
121
|
-
rootSha: safeGitHead(input.root),
|
|
122
|
-
packageShas,
|
|
123
|
-
plannedVersions,
|
|
124
|
-
lockfiles,
|
|
125
|
-
selectedPackages
|
|
126
|
-
};
|
|
127
|
-
return {
|
|
128
|
-
...base,
|
|
129
|
-
key: sha256(JSON.stringify(base))
|
|
130
|
-
};
|
|
131
|
-
}
|
|
132
|
-
function isInternalTreeseedPackageName(name, internalPackageNames) {
|
|
133
|
-
return internalPackageNames.has(name) || name.startsWith("@treeseed/");
|
|
134
|
-
}
|
|
135
|
-
function normalizeDependencySpecForTopology(name, spec, internalPackageNames) {
|
|
136
|
-
if (!isInternalTreeseedPackageName(name, internalPackageNames)) return spec;
|
|
137
|
-
const value = String(spec ?? "").trim();
|
|
138
|
-
if (!value) return value;
|
|
139
|
-
if (/^(?:git\+|github:|gitlab:|bitbucket:|ssh:\/\/|https:\/\/|file:)/u.test(value) || /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/u.test(value) || /^workspace:/u.test(value)) {
|
|
140
|
-
return "<internal-treeseed-reference>";
|
|
141
|
-
}
|
|
142
|
-
return value;
|
|
143
|
-
}
|
|
144
|
-
function normalizePackageJsonForTopology(packageJson, internalPackageNames) {
|
|
145
|
-
const normalized = {};
|
|
146
|
-
for (const [key, value] of Object.entries(packageJson)) {
|
|
147
|
-
if (key === "version") continue;
|
|
148
|
-
if (INTERNAL_DEPENDENCY_FIELDS.includes(key) && value && typeof value === "object" && !Array.isArray(value)) {
|
|
149
|
-
normalized[key] = sortedRecord(Object.fromEntries(Object.entries(value).map(([dependencyName, spec]) => [dependencyName, normalizeDependencySpecForTopology(dependencyName, spec, internalPackageNames)])));
|
|
150
|
-
continue;
|
|
151
|
-
}
|
|
152
|
-
if (key === "scripts" && value && typeof value === "object" && !Array.isArray(value)) {
|
|
153
|
-
normalized[key] = sortedRecord(Object.fromEntries(Object.entries(value).filter(([scriptName]) => TOPOLOGY_SCRIPT_PREFIXES.some((prefix) => scriptName === prefix || scriptName.startsWith(prefix))).map(([scriptName, command]) => [scriptName, command])));
|
|
154
|
-
continue;
|
|
155
|
-
}
|
|
156
|
-
if (["name", "type", "private", "workspaces", "main", "module", "exports", "files", "bin", "publishConfig", "repository", "engines", "packageManager"].includes(key)) {
|
|
157
|
-
normalized[key] = value;
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
return sortedRecord(normalized);
|
|
161
|
-
}
|
|
162
|
-
function normalizePackageLockForTopology(lockfile, internalPackageNames) {
|
|
163
|
-
const packages = lockfile.packages && typeof lockfile.packages === "object" && !Array.isArray(lockfile.packages) ? lockfile.packages : {};
|
|
164
|
-
const normalizedPackages = {};
|
|
165
|
-
for (const [path, entry] of Object.entries(packages)) {
|
|
166
|
-
if (!entry || typeof entry !== "object" || Array.isArray(entry)) continue;
|
|
167
|
-
const record = entry;
|
|
168
|
-
const packageName = typeof record.name === "string" ? record.name : path.startsWith("node_modules/") ? path.replace(/^node_modules\//u, "") : null;
|
|
169
|
-
const normalized = {};
|
|
170
|
-
for (const key of ["name", "link", "dev", "optional", "peer"]) {
|
|
171
|
-
if (key in record) normalized[key] = record[key];
|
|
172
|
-
}
|
|
173
|
-
for (const field of INTERNAL_DEPENDENCY_FIELDS) {
|
|
174
|
-
const values = record[field];
|
|
175
|
-
if (values && typeof values === "object" && !Array.isArray(values)) {
|
|
176
|
-
normalized[field] = sortedRecord(Object.fromEntries(Object.entries(values).map(([dependencyName, spec]) => [dependencyName, normalizeDependencySpecForTopology(dependencyName, spec, internalPackageNames)])));
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
if (packageName && isInternalTreeseedPackageName(packageName, internalPackageNames)) {
|
|
180
|
-
normalized.version = "<internal-treeseed-reference>";
|
|
181
|
-
normalized.resolved = "<internal-treeseed-reference>";
|
|
182
|
-
normalized.integrity = "<internal-treeseed-reference>";
|
|
183
|
-
} else {
|
|
184
|
-
for (const key of ["version", "resolved", "integrity", "license"]) {
|
|
185
|
-
if (key in record) normalized[key] = record[key];
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
normalizedPackages[path] = sortedRecord(normalized);
|
|
189
|
-
}
|
|
190
|
-
return sortedRecord({
|
|
191
|
-
name: lockfile.name,
|
|
192
|
-
lockfileVersion: lockfile.lockfileVersion,
|
|
193
|
-
requires: lockfile.requires,
|
|
194
|
-
packages: sortedRecord(normalizedPackages)
|
|
195
|
-
});
|
|
196
|
-
}
|
|
197
|
-
function topologyJsonHash(value) {
|
|
198
|
-
return sha256(JSON.stringify(value));
|
|
199
|
-
}
|
|
200
|
-
function topologyPackageHash(packageJsonPath, internalPackageNames) {
|
|
201
|
-
const packageJson = safePackageJson(packageJsonPath);
|
|
202
|
-
if (!packageJson) return null;
|
|
203
|
-
return topologyJsonHash(normalizePackageJsonForTopology(packageJson, internalPackageNames));
|
|
204
|
-
}
|
|
205
|
-
function topologyLockfileHash(lockfilePath, internalPackageNames) {
|
|
206
|
-
const lockfile = safePackageJson(lockfilePath);
|
|
207
|
-
if (!lockfile) return null;
|
|
208
|
-
return topologyJsonHash(normalizePackageLockForTopology(lockfile, internalPackageNames));
|
|
209
|
-
}
|
|
210
|
-
function buildReleaseCandidateTopologyFingerprint(input) {
|
|
211
|
-
const selectedPackages = [...new Set((input.selectedPackageNames ?? []).map(String))].sort();
|
|
212
|
-
const selectedPackageSet = new Set(selectedPackages);
|
|
213
|
-
const packages = discoverTreeseedPackageAdapters(input.root).filter((pkg) => selectedPackageSet.size === 0 || selectedPackageSet.has(pkg.id) || selectedPackageSet.has(pkg.name));
|
|
214
|
-
const internalPackageNames = /* @__PURE__ */ new Set([
|
|
215
|
-
"@treeseed/market",
|
|
216
|
-
...discoverTreeseedPackageAdapters(input.root).map((pkg) => pkg.name)
|
|
217
|
-
]);
|
|
218
|
-
const packageManifests = sortedRecord({
|
|
219
|
-
"@treeseed/market": topologyPackageHash(resolve(input.root, "package.json"), internalPackageNames),
|
|
220
|
-
...Object.fromEntries(packages.map((pkg) => [pkg.id, topologyPackageHash(resolve(pkg.dir, "package.json"), internalPackageNames)]))
|
|
221
|
-
});
|
|
222
|
-
const lockfiles = sortedRecord({
|
|
223
|
-
"@treeseed/market": topologyLockfileHash(resolve(input.root, "package-lock.json"), internalPackageNames),
|
|
224
|
-
...Object.fromEntries(packages.map((pkg) => [
|
|
225
|
-
pkg.id,
|
|
226
|
-
pkg.kind === "node-typescript" ? topologyLockfileHash(resolve(pkg.dir, "package-lock.json"), internalPackageNames) : fileSha256(resolve(pkg.dir, "Cargo.lock")) ?? fileSha256(resolve(pkg.dir, "mix.lock"))
|
|
227
|
-
]))
|
|
228
|
-
});
|
|
229
|
-
const manifestEntries = {
|
|
230
|
-
"treeseed.site.yaml": fileSha256(resolve(input.root, "treeseed.site.yaml")),
|
|
231
|
-
"treeseed.package.yaml": fileSha256(resolve(input.root, "treeseed.package.yaml"))
|
|
232
|
-
};
|
|
233
|
-
for (const pkg of packages) {
|
|
234
|
-
manifestEntries[`${pkg.id}:treeseed.package.yaml`] = fileSha256(resolve(pkg.dir, "treeseed.package.yaml"));
|
|
235
|
-
manifestEntries[`${pkg.id}:treeseed.site.yaml`] = fileSha256(resolve(pkg.dir, "treeseed.site.yaml"));
|
|
236
|
-
}
|
|
237
|
-
const base = {
|
|
238
|
-
policyVersion: RELEASE_CANDIDATE_TOPOLOGY_POLICY_VERSION,
|
|
239
|
-
packageManifests,
|
|
240
|
-
lockfiles,
|
|
241
|
-
treeseedManifests: sortedRecord(manifestEntries),
|
|
242
|
-
selectedPackages
|
|
243
|
-
};
|
|
244
|
-
return {
|
|
245
|
-
...base,
|
|
246
|
-
key: sha256(JSON.stringify(base))
|
|
247
|
-
};
|
|
248
|
-
}
|
|
249
|
-
function readCachedReleaseCandidateReport(root, key) {
|
|
250
|
-
const cachePath = releaseCandidateCachePath(root, key);
|
|
251
|
-
if (!existsSync(cachePath)) return null;
|
|
252
|
-
try {
|
|
253
|
-
return JSON.parse(readFileSync(cachePath, "utf8"));
|
|
254
|
-
} catch {
|
|
255
|
-
return null;
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
function writeReleaseCandidateReport(root, report) {
|
|
259
|
-
ensureReleaseCandidateCacheDir(root);
|
|
260
|
-
writeFileSync(releaseCandidateCachePath(root, report.fingerprint.key), `${JSON.stringify(report, null, 2)}
|
|
261
|
-
`, "utf8");
|
|
262
|
-
if (report.status === "passed" && report.mode === "strict") {
|
|
263
|
-
writeFileSync(releaseCandidateTopologyCachePath(root, report.topology.key), `${JSON.stringify({
|
|
264
|
-
key: report.topology.key,
|
|
265
|
-
checkedAt: report.checkedAt,
|
|
266
|
-
fingerprintKey: report.fingerprint.key,
|
|
267
|
-
mode: report.mode,
|
|
268
|
-
reason: report.reason
|
|
269
|
-
}, null, 2)}
|
|
270
|
-
`, "utf8");
|
|
271
|
-
}
|
|
272
|
-
return report;
|
|
273
|
-
}
|
|
274
|
-
function readStrictTopologyProof(root, key) {
|
|
275
|
-
const cachePath = releaseCandidateTopologyCachePath(root, key);
|
|
276
|
-
if (!existsSync(cachePath)) return null;
|
|
277
|
-
try {
|
|
278
|
-
return JSON.parse(readFileSync(cachePath, "utf8"));
|
|
279
|
-
} catch {
|
|
280
|
-
return null;
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
function addFailure(failures, failure) {
|
|
284
|
-
failures.push({
|
|
285
|
-
...failure,
|
|
286
|
-
details: failure.details ?? null,
|
|
287
|
-
provider: failure.provider ?? null
|
|
288
|
-
});
|
|
289
|
-
}
|
|
290
|
-
function packageReadinessChecks(root, selectedPackageNames, failures, options = {}) {
|
|
291
|
-
if (selectedPackageNames.length === 0) {
|
|
292
|
-
return { name: "package-release-readiness", status: "skipped", detail: "No packages are selected for this release." };
|
|
293
|
-
}
|
|
294
|
-
const selected = new Set(selectedPackageNames);
|
|
295
|
-
const packages = discoverTreeseedPackageAdapters(root).filter((pkg) => selected.has(pkg.id) || selected.has(pkg.name));
|
|
296
|
-
for (const pkg of packages) {
|
|
297
|
-
checkPackageAdapterReadiness(pkg, failures, options);
|
|
298
|
-
}
|
|
299
|
-
return {
|
|
300
|
-
name: "package-release-readiness",
|
|
301
|
-
status: failures.some((failure) => failure.code.startsWith("missing_") || failure.code === "npm_pack_dry_run_failed" || failure.code === "docker_manifest_check_failed") ? "failed" : "passed",
|
|
302
|
-
detail: `Checked ${packages.length} selected package adapter${packages.length === 1 ? "" : "s"}${options.skipNpmPack ? " without npm pack rehearsal" : ""}: ${packages.map((pkg) => `${pkg.id} (${pkg.kind})`).join(", ") || "none"}.`
|
|
303
|
-
};
|
|
304
|
-
}
|
|
305
|
-
function checkPackageAdapterReadiness(pkg, failures, options = {}) {
|
|
306
|
-
if (pkg.kind === "node-typescript") {
|
|
307
|
-
const packageJson = safePackageJson(resolve(pkg.dir, "package.json"));
|
|
308
|
-
const scripts = packageJson?.scripts && typeof packageJson.scripts === "object" && !Array.isArray(packageJson.scripts) ? packageJson.scripts : {};
|
|
309
|
-
if (!existsSync(resolve(pkg.dir, ".github", "workflows", "publish.yml"))) {
|
|
310
|
-
addFailure(failures, {
|
|
311
|
-
code: "missing_publish_workflow",
|
|
312
|
-
scope: pkg.id,
|
|
313
|
-
provider: "github",
|
|
314
|
-
message: `${pkg.id} is missing .github/workflows/publish.yml.`
|
|
315
|
-
});
|
|
316
|
-
}
|
|
317
|
-
if (typeof scripts["release:publish"] !== "string") {
|
|
318
|
-
addFailure(failures, {
|
|
319
|
-
code: "missing_publish_script",
|
|
320
|
-
scope: pkg.id,
|
|
321
|
-
message: `${pkg.id} is missing a release:publish script.`
|
|
322
|
-
});
|
|
323
|
-
}
|
|
324
|
-
if (typeof scripts["verify:local"] !== "string" && typeof scripts.verify !== "string" && typeof scripts["verify:action"] !== "string") {
|
|
325
|
-
addFailure(failures, {
|
|
326
|
-
code: "missing_verify_script",
|
|
327
|
-
scope: pkg.id,
|
|
328
|
-
message: `${pkg.id} is missing a release-ready verify script.`
|
|
329
|
-
});
|
|
330
|
-
}
|
|
331
|
-
if (!options.skipNpmPack) {
|
|
332
|
-
try {
|
|
333
|
-
run("npm", ["pack", "--dry-run"], { cwd: pkg.dir, capture: true, timeoutMs: 12e4 });
|
|
334
|
-
} catch (error) {
|
|
335
|
-
addFailure(failures, {
|
|
336
|
-
code: "npm_pack_dry_run_failed",
|
|
337
|
-
scope: pkg.id,
|
|
338
|
-
message: `${pkg.id} failed npm pack --dry-run.`,
|
|
339
|
-
details: { error: error instanceof Error ? error.message : String(error) }
|
|
340
|
-
});
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
return;
|
|
344
|
-
}
|
|
345
|
-
if (!pkg.version) {
|
|
346
|
-
addFailure(failures, {
|
|
347
|
-
code: "missing_package_version",
|
|
348
|
-
scope: pkg.id,
|
|
349
|
-
message: `${pkg.id} is missing a readable BEAM package version.`,
|
|
350
|
-
details: { versionSource: pkg.versionSource }
|
|
351
|
-
});
|
|
352
|
-
}
|
|
353
|
-
if (pkg.id === "treedx" && !existsSync(resolve(pkg.dir, ".github", "workflows", "dev-image.yml"))) {
|
|
354
|
-
addFailure(failures, {
|
|
355
|
-
code: "missing_development_image_workflow",
|
|
356
|
-
scope: pkg.id,
|
|
357
|
-
provider: "github",
|
|
358
|
-
message: `${pkg.id} is missing .github/workflows/dev-image.yml for staging-safe development image publication.`
|
|
359
|
-
});
|
|
360
|
-
}
|
|
361
|
-
if (!pkg.verifyCommands.local) {
|
|
362
|
-
addFailure(failures, {
|
|
363
|
-
code: "missing_verify_script",
|
|
364
|
-
scope: pkg.id,
|
|
365
|
-
message: `${pkg.id} is missing a BEAM package local verification command.`
|
|
366
|
-
});
|
|
367
|
-
}
|
|
368
|
-
if (!pkg.verifyCommands.release) {
|
|
369
|
-
addFailure(failures, {
|
|
370
|
-
code: "missing_release_gate",
|
|
371
|
-
scope: pkg.id,
|
|
372
|
-
message: `${pkg.id} is missing a BEAM package release gate command.`
|
|
373
|
-
});
|
|
374
|
-
}
|
|
375
|
-
if (dockerManifestCheckMode() !== "check") return;
|
|
376
|
-
for (const artifact of pkg.artifacts.filter((entry) => entry.provider === "docker")) {
|
|
377
|
-
for (const tag of artifact.tags ?? []) {
|
|
378
|
-
if (tag.includes("<")) continue;
|
|
379
|
-
try {
|
|
380
|
-
run("docker", ["manifest", "inspect", `${artifact.name}:${tag}`], { cwd: pkg.dir, capture: true, timeoutMs: 12e4 });
|
|
381
|
-
} catch (error) {
|
|
382
|
-
addFailure(failures, {
|
|
383
|
-
code: "docker_manifest_check_failed",
|
|
384
|
-
scope: pkg.id,
|
|
385
|
-
provider: "docker",
|
|
386
|
-
message: `${pkg.id} Docker artifact is not published: ${artifact.name}:${tag}.`,
|
|
387
|
-
details: { error: error instanceof Error ? error.message : String(error) }
|
|
388
|
-
});
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
function copyWorkspaceForProductionRehearsal(root) {
|
|
394
|
-
const tempParent = mkdtempSync(join(tmpdir(), "treeseed-release-candidate-"));
|
|
395
|
-
const tempRoot = join(tempParent, "workspace");
|
|
396
|
-
cpSync(root, tempRoot, {
|
|
397
|
-
recursive: true,
|
|
398
|
-
filter: (source) => {
|
|
399
|
-
const rel = relative(root, source);
|
|
400
|
-
if (!rel) return true;
|
|
401
|
-
const segments = rel.split(/[\\/]+/u);
|
|
402
|
-
return !segments.some((segment) => REHEARSAL_IGNORED_SEGMENTS.has(segment));
|
|
403
|
-
}
|
|
404
|
-
});
|
|
405
|
-
return { tempParent, tempRoot };
|
|
406
|
-
}
|
|
407
|
-
function applyPlannedStableMetadata(root, plannedVersions) {
|
|
408
|
-
const stableVersions = new Map(
|
|
409
|
-
Object.entries(plannedVersions).filter(([, version]) => STABLE_SEMVER.test(version))
|
|
410
|
-
);
|
|
411
|
-
const dependencyVersions = installableInternalDependencyVersions(root, stableVersions);
|
|
412
|
-
const stableGitReferences = stablePackageGitReferences(root, dependencyVersions);
|
|
413
|
-
const targets = [
|
|
414
|
-
{ name: "@treeseed/market", dir: root },
|
|
415
|
-
...workspacePackages(root).map((pkg) => ({ name: pkg.name, dir: pkg.dir }))
|
|
416
|
-
];
|
|
417
|
-
for (const target of targets) {
|
|
418
|
-
const packageJsonPath = resolve(target.dir, "package.json");
|
|
419
|
-
const packageJson = safePackageJson(packageJsonPath);
|
|
420
|
-
if (!packageJson) continue;
|
|
421
|
-
let changed = false;
|
|
422
|
-
const plannedVersion = stableVersions.get(target.name);
|
|
423
|
-
if (plannedVersion && packageJson.version !== plannedVersion) {
|
|
424
|
-
packageJson.version = plannedVersion;
|
|
425
|
-
changed = true;
|
|
426
|
-
}
|
|
427
|
-
for (const field of ["dependencies", "optionalDependencies", "peerDependencies", "devDependencies"]) {
|
|
428
|
-
const values = packageJson[field];
|
|
429
|
-
if (!values || typeof values !== "object" || Array.isArray(values)) continue;
|
|
430
|
-
for (const [dependencyName, version] of dependencyVersions.entries()) {
|
|
431
|
-
if (!(dependencyName in values)) continue;
|
|
432
|
-
const dependencySpec = stableGitReferences.get(dependencyName) ?? version;
|
|
433
|
-
if (String(values[dependencyName]) === dependencySpec) continue;
|
|
434
|
-
values[dependencyName] = dependencySpec;
|
|
435
|
-
changed = true;
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
|
-
if (changed) {
|
|
439
|
-
writeJsonFile(packageJsonPath, packageJson);
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
function stablePackageGitReferences(root, versions) {
|
|
444
|
-
return new Map(workspacePackages(root).map((pkg) => {
|
|
445
|
-
const version = versions.get(pkg.name);
|
|
446
|
-
if (!version) return null;
|
|
447
|
-
let remote = null;
|
|
448
|
-
try {
|
|
449
|
-
remote = run("git", ["remote", "get-url", "origin"], { cwd: pkg.dir, capture: true }).trim();
|
|
450
|
-
} catch {
|
|
451
|
-
remote = null;
|
|
452
|
-
}
|
|
453
|
-
const manifestRemote = normalizeGitRemoteForManifest(remote ?? "", "preserve-origin");
|
|
454
|
-
return manifestRemote ? [pkg.name, `${manifestRemote}#${version}`] : null;
|
|
455
|
-
}).filter((entry) => Boolean(entry)));
|
|
456
|
-
}
|
|
457
|
-
function rehearsalVerifyScript(root) {
|
|
458
|
-
const scripts = packageScripts(resolve(root, "package.json"));
|
|
459
|
-
for (const scriptName of ["verify:direct", "verify:local", "verify", "build"]) {
|
|
460
|
-
if (typeof scripts[scriptName] === "string") {
|
|
461
|
-
return scriptName;
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
|
-
return null;
|
|
465
|
-
}
|
|
466
|
-
function runNpmRehearsalCommand(args, options) {
|
|
467
|
-
const result = spawnSync("npm", args, {
|
|
468
|
-
cwd: options.cwd,
|
|
469
|
-
env: options.env ?? process.env,
|
|
470
|
-
stdio: "pipe",
|
|
471
|
-
encoding: "utf8",
|
|
472
|
-
timeout: options.timeoutMs
|
|
473
|
-
});
|
|
474
|
-
const stdout = result.stdout ?? "";
|
|
475
|
-
const stderr = result.stderr ?? "";
|
|
476
|
-
if (result.status !== 0) {
|
|
477
|
-
if (stdout) process.stdout.write(stdout);
|
|
478
|
-
if (stderr) process.stderr.write(stderr);
|
|
479
|
-
const message = (result.error?.message ? `${result.error.message}
|
|
480
|
-
` : "") + (stderr.trim() || stdout.trim() || `npm ${args.join(" ")} failed`);
|
|
481
|
-
throw new Error(message);
|
|
482
|
-
}
|
|
483
|
-
const warningSummary = createBuildWarningSummary();
|
|
484
|
-
const outputFailures = [];
|
|
485
|
-
const emitFiltered = (text, stream) => {
|
|
486
|
-
for (const line of text.split(/\r?\n/u)) {
|
|
487
|
-
if (!line) continue;
|
|
488
|
-
const classified = warningSummary.record(line);
|
|
489
|
-
if (classified.kind === "allowed") continue;
|
|
490
|
-
for (const failure of collectReleaseCandidateOutputFailures(line)) {
|
|
491
|
-
outputFailures.push(failure);
|
|
492
|
-
}
|
|
493
|
-
stream.write(`${line}
|
|
494
|
-
`);
|
|
495
|
-
}
|
|
496
|
-
};
|
|
497
|
-
emitFiltered(stdout, process.stdout);
|
|
498
|
-
emitFiltered(stderr, process.stderr);
|
|
499
|
-
for (const line of formatAllowedBuildWarnings(warningSummary.allowedWarnings)) {
|
|
500
|
-
process.stdout.write(`${line}
|
|
501
|
-
`);
|
|
502
|
-
}
|
|
503
|
-
if (outputFailures.length > 0) {
|
|
504
|
-
throw new Error([
|
|
505
|
-
`npm ${args.join(" ")} completed with error output despite exit code 0.`,
|
|
506
|
-
...outputFailures.slice(0, 12)
|
|
507
|
-
].join("\n"));
|
|
508
|
-
}
|
|
509
|
-
}
|
|
510
|
-
function npmRehearsalEnv(extra = {}) {
|
|
511
|
-
return {
|
|
512
|
-
...process.env,
|
|
513
|
-
npm_config_jobs: process.env.npm_config_jobs ?? "2",
|
|
514
|
-
npm_config_audit: process.env.npm_config_audit ?? "false",
|
|
515
|
-
npm_config_fund: process.env.npm_config_fund ?? "false",
|
|
516
|
-
...extra
|
|
517
|
-
};
|
|
518
|
-
}
|
|
519
|
-
function collectReleaseCandidateOutputFailures(line) {
|
|
520
|
-
const value = String(line ?? "").trim();
|
|
521
|
-
if (!value) return [];
|
|
522
|
-
const failures = [];
|
|
523
|
-
if (/^stderr\s+\|\s+/u.test(value)) {
|
|
524
|
-
failures.push(`Captured test stderr: ${value}`);
|
|
525
|
-
}
|
|
526
|
-
if (/(^|\s)ERROR(?:\s|\[|:)/u.test(value)) {
|
|
527
|
-
failures.push(`Error output: ${value}`);
|
|
528
|
-
}
|
|
529
|
-
if (/\bFailed to run background task\b/u.test(value)) {
|
|
530
|
-
failures.push(`Background task failure output: ${value}`);
|
|
531
|
-
}
|
|
532
|
-
return failures;
|
|
533
|
-
}
|
|
534
|
-
function buildRehearsalWorkspacePackageArtifacts(root) {
|
|
535
|
-
for (const pkg of packagesWithScript("build:dist", root)) {
|
|
536
|
-
runNpmRehearsalCommand(["--prefix", pkg.dir, "run", "build:dist"], { cwd: root, timeoutMs: 3e5 });
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
function runProductionDependencyRehearsal(root, plannedVersions, selectedPackageNames, failures) {
|
|
540
|
-
if (process.env.TREESEED_RELEASE_CANDIDATE_REHEARSAL_MODE === "skip") {
|
|
541
|
-
return "Skipped clean install rehearsal by request.";
|
|
542
|
-
}
|
|
543
|
-
const selectedPackageSet = new Set(selectedPackageNames);
|
|
544
|
-
let tempParent = null;
|
|
545
|
-
try {
|
|
546
|
-
const copied = copyWorkspaceForProductionRehearsal(root);
|
|
547
|
-
tempParent = copied.tempParent;
|
|
548
|
-
applyPlannedStableMetadata(copied.tempRoot, plannedVersions);
|
|
549
|
-
const npmEnv = npmRehearsalEnv();
|
|
550
|
-
runNpmRehearsalCommand(["install", "--package-lock-only", "--ignore-scripts", "--no-audit", "--no-fund", "--prefer-offline"], { cwd: copied.tempRoot, timeoutMs: 3e5, env: npmEnv });
|
|
551
|
-
runNpmRehearsalCommand(["ci", "--ignore-scripts", "--no-audit", "--no-fund", "--prefer-offline"], { cwd: copied.tempRoot, timeoutMs: 6e5, env: npmEnv });
|
|
552
|
-
buildRehearsalWorkspacePackageArtifacts(copied.tempRoot);
|
|
553
|
-
const scriptName = rehearsalVerifyScript(copied.tempRoot);
|
|
554
|
-
if (scriptName) {
|
|
555
|
-
const packageJson = safePackageJson(resolve(copied.tempRoot, "package.json"));
|
|
556
|
-
const parallelMarketVerify = process.env.TREESEED_RELEASE_CANDIDATE_MARKET_VERIFY_PARALLEL === "1" && packageJson?.name === "@treeseed/market" && (scriptName === "verify:direct" || scriptName === "verify:local" || scriptName === "verify");
|
|
557
|
-
runNpmRehearsalCommand(["run", scriptName], {
|
|
558
|
-
cwd: copied.tempRoot,
|
|
559
|
-
timeoutMs: 9e5,
|
|
560
|
-
env: parallelMarketVerify ? npmRehearsalEnv({ TREESEED_VERIFY_PARALLEL: "1" }) : npmEnv
|
|
561
|
-
});
|
|
562
|
-
}
|
|
563
|
-
const postInstallIssues = collectInternalDevReferenceIssues(copied.tempRoot, selectedPackageSet);
|
|
564
|
-
if (postInstallIssues.length > 0) {
|
|
565
|
-
addFailure(failures, {
|
|
566
|
-
code: "internal_dev_references_after_rehearsal",
|
|
567
|
-
scope: "@treeseed/market",
|
|
568
|
-
message: "Production dependency rehearsal still found internal dev references after clean install.",
|
|
569
|
-
details: {
|
|
570
|
-
references: postInstallIssues.map((issue) => ({
|
|
571
|
-
filePath: issue.filePath,
|
|
572
|
-
field: issue.field,
|
|
573
|
-
dependencyName: issue.dependencyName,
|
|
574
|
-
spec: issue.spec,
|
|
575
|
-
reason: issue.reason
|
|
576
|
-
}))
|
|
577
|
-
}
|
|
578
|
-
});
|
|
579
|
-
}
|
|
580
|
-
return scriptName ? `Ran clean install and npm run ${scriptName} in a temporary production rehearsal workspace.` : "Ran clean install in a temporary production rehearsal workspace.";
|
|
581
|
-
} catch (error) {
|
|
582
|
-
addFailure(failures, {
|
|
583
|
-
code: "production_dependency_rehearsal_failed",
|
|
584
|
-
scope: "@treeseed/market",
|
|
585
|
-
message: "Production dependency rehearsal failed in the temporary workspace.",
|
|
586
|
-
details: { error: error instanceof Error ? error.message : String(error) }
|
|
587
|
-
});
|
|
588
|
-
return "Production dependency rehearsal failed.";
|
|
589
|
-
} finally {
|
|
590
|
-
if (tempParent) {
|
|
591
|
-
rmSync(tempParent, { recursive: true, force: true });
|
|
592
|
-
}
|
|
593
|
-
}
|
|
594
|
-
}
|
|
595
|
-
function dependencyRehearsalChecks(root, plannedVersions, selectedPackageNames, failures) {
|
|
596
|
-
const before = failures.length;
|
|
597
|
-
for (const [name, version] of Object.entries(plannedVersions)) {
|
|
598
|
-
if ((name === "@treeseed/market" || selectedPackageNames.includes(name)) && !STABLE_SEMVER.test(version)) {
|
|
599
|
-
addFailure(failures, {
|
|
600
|
-
code: "unstable_planned_version",
|
|
601
|
-
scope: name,
|
|
602
|
-
message: `${name} planned release version is not stable semver: ${version}.`
|
|
603
|
-
});
|
|
604
|
-
}
|
|
605
|
-
}
|
|
606
|
-
const devReferenceIssues = collectInternalDevReferenceIssues(root);
|
|
607
|
-
const unrehearsableDevReferences = devReferenceIssues.filter((issue) => {
|
|
608
|
-
const dependencyName = issue.dependencyName ?? "";
|
|
609
|
-
const planned = plannedVersions[dependencyName];
|
|
610
|
-
return !planned || !STABLE_SEMVER.test(planned);
|
|
611
|
-
});
|
|
612
|
-
if (unrehearsableDevReferences.length > 0) {
|
|
613
|
-
addFailure(failures, {
|
|
614
|
-
code: "internal_dev_references",
|
|
615
|
-
scope: "@treeseed/market",
|
|
616
|
-
message: "Production dependency rehearsal found internal dev references without a stable planned replacement.",
|
|
617
|
-
details: {
|
|
618
|
-
references: unrehearsableDevReferences.map((issue) => ({
|
|
619
|
-
filePath: issue.filePath,
|
|
620
|
-
field: issue.field,
|
|
621
|
-
dependencyName: issue.dependencyName,
|
|
622
|
-
spec: issue.spec,
|
|
623
|
-
reason: issue.reason
|
|
624
|
-
}))
|
|
625
|
-
}
|
|
626
|
-
});
|
|
627
|
-
}
|
|
628
|
-
const rehearsalDetail = unrehearsableDevReferences.length === 0 && failures.length === before ? runProductionDependencyRehearsal(root, plannedVersions, selectedPackageNames, failures) : "Skipped clean install rehearsal because stable dependency metadata is incomplete.";
|
|
629
|
-
return {
|
|
630
|
-
name: "production-dependency-rehearsal",
|
|
631
|
-
status: failures.length > before ? "failed" : "passed",
|
|
632
|
-
detail: `${devReferenceIssues.length > 0 ? `Rehearsed stable replacements for ${devReferenceIssues.length} internal dev reference${devReferenceIssues.length === 1 ? "" : "s"}.` : "Checked planned stable versions and internal dependency references."} ${rehearsalDetail}`
|
|
633
|
-
};
|
|
634
|
-
}
|
|
635
|
-
function validateInternalGitReferenceTags(root, failures) {
|
|
636
|
-
const issues = collectInternalDevReferenceIssues(root);
|
|
637
|
-
let checked = 0;
|
|
638
|
-
const seen = /* @__PURE__ */ new Set();
|
|
639
|
-
for (const issue of issues) {
|
|
640
|
-
const spec = issue.spec;
|
|
641
|
-
const hashIndex = spec.lastIndexOf("#");
|
|
642
|
-
if (hashIndex === -1 || !/^(?:git\+|github:|gitlab:|bitbucket:|ssh:\/\/|https:\/\/|file:)/u.test(spec)) continue;
|
|
643
|
-
const rawRemote = spec.slice(0, hashIndex).replace(/^git\+/u, "");
|
|
644
|
-
const githubMatch = rawRemote.match(/^github:([^/]+\/[^/]+?)(?:\.git)?$/u);
|
|
645
|
-
const remote = githubMatch ? `https://github.com/${githubMatch[1]}.git` : rawRemote;
|
|
646
|
-
const tagName = decodeURIComponent(spec.slice(hashIndex + 1));
|
|
647
|
-
if (!remote || !tagName) continue;
|
|
648
|
-
const key = `${remote}#${tagName}`;
|
|
649
|
-
if (seen.has(key)) continue;
|
|
650
|
-
seen.add(key);
|
|
651
|
-
checked += 1;
|
|
652
|
-
try {
|
|
653
|
-
run("git", ["ls-remote", "--exit-code", "--tags", remote, `refs/tags/${tagName}`], { cwd: root, capture: true, timeoutMs: 12e4 });
|
|
654
|
-
} catch (error) {
|
|
655
|
-
addFailure(failures, {
|
|
656
|
-
code: "internal_git_tag_missing",
|
|
657
|
-
scope: issue.dependencyName ?? issue.repoName,
|
|
658
|
-
provider: "git",
|
|
659
|
-
message: `Internal git dependency tag is not reachable: ${issue.dependencyName ?? issue.repoName}#${tagName}.`,
|
|
660
|
-
details: { spec, remote, tagName, filePath: issue.filePath, error: error instanceof Error ? error.message : String(error) }
|
|
661
|
-
});
|
|
662
|
-
}
|
|
663
|
-
}
|
|
664
|
-
return checked;
|
|
665
|
-
}
|
|
666
|
-
function lightweightDependencyChecks(root, failures) {
|
|
667
|
-
const before = failures.length;
|
|
668
|
-
try {
|
|
669
|
-
runNpmRehearsalCommand(["install", "--package-lock-only", "--ignore-scripts", "--dry-run", "--workspaces=false", "--no-audit", "--no-fund", "--prefer-offline"], {
|
|
670
|
-
cwd: root,
|
|
671
|
-
timeoutMs: 3e5,
|
|
672
|
-
env: npmRehearsalEnv()
|
|
673
|
-
});
|
|
674
|
-
} catch (error) {
|
|
675
|
-
addFailure(failures, {
|
|
676
|
-
code: "lockfile_dry_run_failed",
|
|
677
|
-
scope: "@treeseed/market",
|
|
678
|
-
message: "Root lockfile dry-run validation failed.",
|
|
679
|
-
details: { error: error instanceof Error ? error.message : String(error) }
|
|
680
|
-
});
|
|
681
|
-
}
|
|
682
|
-
const checkedTags = validateInternalGitReferenceTags(root, failures);
|
|
683
|
-
return {
|
|
684
|
-
name: "hybrid-dependency-readiness",
|
|
685
|
-
status: failures.length > before ? "failed" : "passed",
|
|
686
|
-
detail: `Validated root lockfile with npm install --package-lock-only --ignore-scripts --dry-run --workspaces=false and checked ${checkedTags} internal git tag${checkedTags === 1 ? "" : "s"} without temp install rehearsal.`
|
|
687
|
-
};
|
|
688
|
-
}
|
|
689
|
-
function skippedReleaseCandidateReport(fingerprint, topology) {
|
|
690
|
-
return {
|
|
691
|
-
status: "passed",
|
|
692
|
-
fingerprint,
|
|
693
|
-
mode: "skip",
|
|
694
|
-
reason: "Release-candidate checks skipped by explicit request.",
|
|
695
|
-
topology,
|
|
696
|
-
reused: false,
|
|
697
|
-
checkedAt: nowIso(),
|
|
698
|
-
failures: [],
|
|
699
|
-
checks: [{
|
|
700
|
-
name: "release-candidate",
|
|
701
|
-
status: "skipped",
|
|
702
|
-
detail: "Skipped by --release-candidate skip or TREESEED_RELEASE_CANDIDATE_MODE=skip."
|
|
703
|
-
}]
|
|
704
|
-
};
|
|
705
|
-
}
|
|
706
|
-
function entryServiceTargets(entry) {
|
|
707
|
-
return Array.isArray(entry.serviceTargets) ? entry.serviceTargets.filter((target) => typeof target === "string") : [];
|
|
708
|
-
}
|
|
709
|
-
function isRootWebReleaseCandidateEntry(entry) {
|
|
710
|
-
if (ROOT_WEB_EXCLUDED_DEPLOY_CONFIG_IDS.has(entry.id)) return false;
|
|
711
|
-
const serviceTargets = entryServiceTargets(entry);
|
|
712
|
-
if (serviceTargets.length > 0 && serviceTargets.every((target) => API_APP_SERVICE_TARGETS.has(target))) {
|
|
713
|
-
return false;
|
|
714
|
-
}
|
|
715
|
-
if (entry.group === "docker") return false;
|
|
716
|
-
return true;
|
|
717
|
-
}
|
|
718
|
-
function localConfigCheck(root, scope, failures) {
|
|
719
|
-
try {
|
|
720
|
-
const report = validateTreeseedCommandEnvironment({ tenantRoot: root, scope, purpose: "deploy" });
|
|
721
|
-
const problems = [...report.validation.missing, ...report.validation.invalid];
|
|
722
|
-
for (const problem of problems) {
|
|
723
|
-
if (!isRootWebReleaseCandidateEntry(problem.entry)) continue;
|
|
724
|
-
addFailure(failures, {
|
|
725
|
-
code: "missing_local_config",
|
|
726
|
-
scope,
|
|
727
|
-
provider: problem.entry.group ?? "config",
|
|
728
|
-
message: `${scope} deploy config is missing or invalid: ${problem.id}.`,
|
|
729
|
-
details: { key: problem.id, provider: problem.entry.group ?? null }
|
|
730
|
-
});
|
|
731
|
-
}
|
|
732
|
-
} catch (error) {
|
|
733
|
-
addFailure(failures, {
|
|
734
|
-
code: "config_validation_failed",
|
|
735
|
-
scope,
|
|
736
|
-
provider: "config",
|
|
737
|
-
message: `${scope} deploy config could not be validated.`,
|
|
738
|
-
details: { error: error instanceof Error ? error.message : String(error) }
|
|
739
|
-
});
|
|
740
|
-
}
|
|
741
|
-
}
|
|
742
|
-
async function githubRemoteConfigCheck(root, scope, failures) {
|
|
743
|
-
const repository = maybeResolveGitHubRepositorySlug(root);
|
|
744
|
-
if (!repository) {
|
|
745
|
-
addFailure(failures, {
|
|
746
|
-
code: "missing_github_repository",
|
|
747
|
-
scope,
|
|
748
|
-
provider: "github",
|
|
749
|
-
message: `${scope} GitHub config parity could not determine the repository from origin.`
|
|
750
|
-
});
|
|
751
|
-
return;
|
|
752
|
-
}
|
|
753
|
-
try {
|
|
754
|
-
const environment = scope === "prod" ? "production" : scope;
|
|
755
|
-
const expected = expectedGitHubDeployEnvironment(root, scope);
|
|
756
|
-
const values = resolveTreeseedMachineEnvironmentValues(root, scope);
|
|
757
|
-
const credential = resolveGitHubCredentialForRepository(repository, { values, env: process.env });
|
|
758
|
-
const client = createGitHubApiClient({
|
|
759
|
-
env: credential.token ? { GH_TOKEN: credential.token, GITHUB_TOKEN: credential.token } : process.env
|
|
760
|
-
});
|
|
761
|
-
const [secretNames, variableNames] = await Promise.all([
|
|
762
|
-
listGitHubEnvironmentSecretNames(repository, environment, { client }),
|
|
763
|
-
listGitHubEnvironmentVariableNames(repository, environment, { client })
|
|
764
|
-
]);
|
|
765
|
-
const missingSecrets = expected.secrets.filter((key) => !secretNames.has(key));
|
|
766
|
-
const missingVariables = expected.variables.filter((key) => !variableNames.has(key));
|
|
767
|
-
for (const key of missingSecrets) {
|
|
768
|
-
addFailure(failures, {
|
|
769
|
-
code: "missing_remote_config",
|
|
770
|
-
scope,
|
|
771
|
-
provider: "github-secret",
|
|
772
|
-
message: `${scope} GitHub secret is missing: ${key}.`,
|
|
773
|
-
details: { key, provider: "github-secret", repository, environment }
|
|
774
|
-
});
|
|
775
|
-
}
|
|
776
|
-
for (const key of missingVariables) {
|
|
777
|
-
addFailure(failures, {
|
|
778
|
-
code: "missing_remote_config",
|
|
779
|
-
scope,
|
|
780
|
-
provider: "github-variable",
|
|
781
|
-
message: `${scope} GitHub variable is missing: ${key}.`,
|
|
782
|
-
details: { key, provider: "github-variable", repository, environment }
|
|
783
|
-
});
|
|
784
|
-
}
|
|
785
|
-
} catch (error) {
|
|
786
|
-
addFailure(failures, {
|
|
787
|
-
code: "remote_config_check_failed",
|
|
788
|
-
scope,
|
|
789
|
-
provider: "github",
|
|
790
|
-
message: `${scope} GitHub config parity check failed.`,
|
|
791
|
-
details: { error: error instanceof Error ? error.message : String(error) }
|
|
792
|
-
});
|
|
793
|
-
}
|
|
794
|
-
}
|
|
795
|
-
function expectedGitHubDeployEnvironment(root, scope) {
|
|
796
|
-
const registry = collectTreeseedEnvironmentContext(root);
|
|
797
|
-
const values = resolveTreeseedMachineEnvironmentValues(root, scope);
|
|
798
|
-
const expectedEntries = registry.entries.filter((entry) => {
|
|
799
|
-
if (!isRootWebReleaseCandidateEntry(entry)) return false;
|
|
800
|
-
if (!isTreeseedEnvironmentEntryRelevant(entry, registry.context, scope, "deploy")) return false;
|
|
801
|
-
if (isTreeseedEnvironmentEntryRequired(entry, registry.context, scope, "deploy")) return true;
|
|
802
|
-
return typeof values[entry.id] === "string" && values[entry.id].trim().length > 0;
|
|
803
|
-
});
|
|
804
|
-
return {
|
|
805
|
-
secrets: [...new Set(expectedEntries.filter((entry) => entry.targets.includes("github-secret")).map((entry) => entry.id))],
|
|
806
|
-
variables: [...new Set(expectedEntries.filter((entry) => entry.targets.includes("github-variable")).map((entry) => entry.id))]
|
|
807
|
-
};
|
|
808
|
-
}
|
|
809
|
-
function providerResourceIdentifierCheck(root, scope, failures) {
|
|
810
|
-
try {
|
|
811
|
-
const deployConfig = loadCliDeployConfig(root);
|
|
812
|
-
const state = loadDeployState(root, deployConfig, { scope });
|
|
813
|
-
const siteDataDb = state.d1Databases?.SITE_DATA_DB;
|
|
814
|
-
if (!siteDataDb?.databaseName || !siteDataDb?.databaseId) {
|
|
815
|
-
addFailure(failures, {
|
|
816
|
-
code: "missing_remote_resource_identifier",
|
|
817
|
-
scope,
|
|
818
|
-
provider: "cloudflare-d1",
|
|
819
|
-
message: `${scope} Cloudflare D1 SITE_DATA_DB is missing a database name or id.`,
|
|
820
|
-
details: { resource: "SITE_DATA_DB", required: ["databaseName", "databaseId"] }
|
|
821
|
-
});
|
|
822
|
-
}
|
|
823
|
-
const services = state.services && typeof state.services === "object" && !Array.isArray(state.services) ? state.services : {};
|
|
824
|
-
for (const [serviceKey, service] of Object.entries(services)) {
|
|
825
|
-
if ((service.provider ?? "railway") !== "railway") continue;
|
|
826
|
-
if (!service.projectName && !service.projectId) {
|
|
827
|
-
addFailure(failures, {
|
|
828
|
-
code: "missing_remote_resource_identifier",
|
|
829
|
-
scope,
|
|
830
|
-
provider: "railway",
|
|
831
|
-
message: `${scope} Railway service ${serviceKey} is missing a project name or id.`,
|
|
832
|
-
details: { service: serviceKey, required: ["projectName", "projectId"] }
|
|
833
|
-
});
|
|
834
|
-
}
|
|
835
|
-
if (!service.serviceName && !service.serviceId) {
|
|
836
|
-
addFailure(failures, {
|
|
837
|
-
code: "missing_remote_resource_identifier",
|
|
838
|
-
scope,
|
|
839
|
-
provider: "railway",
|
|
840
|
-
message: `${scope} Railway service ${serviceKey} is missing a service name or id.`,
|
|
841
|
-
details: { service: serviceKey, required: ["serviceName", "serviceId"] }
|
|
842
|
-
});
|
|
843
|
-
}
|
|
844
|
-
}
|
|
845
|
-
} catch (error) {
|
|
846
|
-
addFailure(failures, {
|
|
847
|
-
code: "provider_resource_check_failed",
|
|
848
|
-
scope,
|
|
849
|
-
provider: "deployment-state",
|
|
850
|
-
message: `${scope} provider resource identifiers could not be validated.`,
|
|
851
|
-
details: { error: error instanceof Error ? error.message : String(error) }
|
|
852
|
-
});
|
|
853
|
-
}
|
|
854
|
-
}
|
|
855
|
-
async function configParityChecks(root, failures) {
|
|
856
|
-
if (process.env.TREESEED_RELEASE_CANDIDATE_CONFIG_PARITY_MODE === "skip") {
|
|
857
|
-
return { name: "config-parity", status: "skipped", detail: "Remote config parity skipped by request." };
|
|
858
|
-
}
|
|
859
|
-
const before = failures.length;
|
|
860
|
-
localConfigCheck(root, "staging", failures);
|
|
861
|
-
localConfigCheck(root, "prod", failures);
|
|
862
|
-
await githubRemoteConfigCheck(root, "staging", failures);
|
|
863
|
-
await githubRemoteConfigCheck(root, "prod", failures);
|
|
864
|
-
providerResourceIdentifierCheck(root, "staging", failures);
|
|
865
|
-
providerResourceIdentifierCheck(root, "prod", failures);
|
|
866
|
-
return {
|
|
867
|
-
name: "config-parity",
|
|
868
|
-
status: failures.length > before ? "failed" : "passed",
|
|
869
|
-
detail: "Checked staging and production config, GitHub names, Railway service identifiers, and D1 identifiers without reading secret values."
|
|
870
|
-
};
|
|
871
|
-
}
|
|
872
|
-
function migrationCompatibilityChecks(root, failures) {
|
|
873
|
-
if (!existsSync(resolve(root, "packages/sdk/package.json"))) {
|
|
874
|
-
return {
|
|
875
|
-
name: "migration-compatibility",
|
|
876
|
-
status: "skipped",
|
|
877
|
-
detail: "No SDK package checkout is present in this workspace."
|
|
878
|
-
};
|
|
879
|
-
}
|
|
880
|
-
const requiredArtifacts = [
|
|
881
|
-
"packages/sdk/drizzle/d1/0000_treeseed_d1.sql",
|
|
882
|
-
"packages/sdk/drizzle/market/0000_market_control_plane.sql"
|
|
883
|
-
];
|
|
884
|
-
const missing = requiredArtifacts.filter((path) => !existsSync(resolve(root, path)));
|
|
885
|
-
for (const path of missing) {
|
|
886
|
-
addFailure(failures, {
|
|
887
|
-
code: "missing_drizzle_migration_artifact",
|
|
888
|
-
scope: "@treeseed/market",
|
|
889
|
-
message: `Drizzle migration compatibility check is missing ${path}.`,
|
|
890
|
-
details: { path }
|
|
891
|
-
});
|
|
892
|
-
}
|
|
893
|
-
return {
|
|
894
|
-
name: "migration-compatibility",
|
|
895
|
-
status: missing.length > 0 ? "failed" : "passed",
|
|
896
|
-
detail: "Checked required Drizzle migration artifacts for Treeseed PostgreSQL and SDK D1."
|
|
897
|
-
};
|
|
898
|
-
}
|
|
899
|
-
async function runReleaseCandidateGate(input) {
|
|
900
|
-
const fingerprint = buildReleaseCandidateFingerprint(input);
|
|
901
|
-
const topology = buildReleaseCandidateTopologyFingerprint(input);
|
|
902
|
-
const requestedMode = input.mode ?? "strict";
|
|
903
|
-
if (input.allowReuse !== false) {
|
|
904
|
-
const cached = readCachedReleaseCandidateReport(input.root, fingerprint.key);
|
|
905
|
-
if (cached?.status === "passed") {
|
|
906
|
-
return {
|
|
907
|
-
...cached,
|
|
908
|
-
mode: cached.mode ?? "strict",
|
|
909
|
-
reason: cached.reason ?? "Reused cached release-candidate report.",
|
|
910
|
-
topology: cached.topology ?? topology,
|
|
911
|
-
reused: true
|
|
912
|
-
};
|
|
913
|
-
}
|
|
914
|
-
}
|
|
915
|
-
if (requestedMode === "skip") {
|
|
916
|
-
return skippedReleaseCandidateReport(fingerprint, topology);
|
|
917
|
-
}
|
|
918
|
-
const selectedPackageNames = [...new Set((input.selectedPackageNames ?? []).map(String))].sort();
|
|
919
|
-
const plannedVersions = Object.fromEntries(
|
|
920
|
-
Object.entries(input.plannedVersions).map(([name, version]) => [name, String(version)])
|
|
921
|
-
);
|
|
922
|
-
const strictTopologyProof = readStrictTopologyProof(input.root, topology.key);
|
|
923
|
-
const effectiveMode = requestedMode;
|
|
924
|
-
const reason = requestedMode === "hybrid" ? strictTopologyProof ? `Hybrid release-candidate selected; strict rehearsal skipped because topology ${topology.key.slice(0, 12)} was already proven.` : `Hybrid release-candidate selected; lightweight checks used because strict topology proof is reserved for promotion lanes.` : "Strict release-candidate selected.";
|
|
925
|
-
const failures = [];
|
|
926
|
-
const checks = [];
|
|
927
|
-
checks.push(effectiveMode === "hybrid" ? lightweightDependencyChecks(input.root, failures) : dependencyRehearsalChecks(input.root, plannedVersions, selectedPackageNames, failures));
|
|
928
|
-
checks.push(packageReadinessChecks(input.root, selectedPackageNames, failures, { skipNpmPack: effectiveMode === "hybrid" }));
|
|
929
|
-
checks.push(await configParityChecks(input.root, failures));
|
|
930
|
-
checks.push(migrationCompatibilityChecks(input.root, failures));
|
|
931
|
-
const report = {
|
|
932
|
-
status: failures.length === 0 ? "passed" : "failed",
|
|
933
|
-
fingerprint,
|
|
934
|
-
mode: effectiveMode,
|
|
935
|
-
reason,
|
|
936
|
-
topology,
|
|
937
|
-
reused: false,
|
|
938
|
-
checkedAt: nowIso(),
|
|
939
|
-
failures,
|
|
940
|
-
checks
|
|
941
|
-
};
|
|
942
|
-
writeReleaseCandidateReport(input.root, report);
|
|
943
|
-
return report;
|
|
944
|
-
}
|
|
945
|
-
export {
|
|
946
|
-
buildReleaseCandidateFingerprint,
|
|
947
|
-
buildReleaseCandidateTopologyFingerprint,
|
|
948
|
-
collectReleaseCandidateOutputFailures,
|
|
949
|
-
isRootWebReleaseCandidateEntry,
|
|
950
|
-
readCachedReleaseCandidateReport,
|
|
951
|
-
runReleaseCandidateGate,
|
|
952
|
-
writeReleaseCandidateReport
|
|
953
|
-
};
|