@treeseed/sdk 0.10.28 → 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 +213 -7
- 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 +118 -59
- package/dist/capacity-provider.js +235 -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 +3 -2
- package/dist/control-plane.js +38 -13
- 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 +50900 -11018
- package/dist/db/market-schema.js +2313 -467
- package/dist/db/node-sqlite.d.ts +1 -232
- package/dist/db/node-sqlite.js +7 -2
- 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 +12 -0
- package/dist/hosting/apps.js +107 -0
- package/dist/hosting/builtins.d.ts +25 -0
- package/dist/hosting/builtins.js +602 -0
- package/dist/hosting/contracts.d.ts +208 -0
- package/dist/hosting/contracts.js +0 -0
- package/dist/hosting/graph.d.ts +195 -0
- package/dist/hosting/graph.js +1092 -0
- package/dist/hosting/index.d.ts +4 -0
- package/dist/hosting/index.js +4 -0
- package/dist/index.d.ts +88 -67
- package/dist/index.js +142 -14
- 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 -9
- package/dist/market-client.d.ts +327 -9
- package/dist/market-client.js +464 -20
- 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 +4 -2
- package/dist/operations/services/bootstrap-runner.js +22 -2
- 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 +83 -24
- package/dist/operations/services/config-runtime.js +449 -130
- package/dist/operations/services/deploy.d.ts +106 -624
- package/dist/operations/services/deploy.js +746 -263
- package/dist/operations/services/deployment-readiness.d.ts +30 -0
- package/dist/operations/services/deployment-readiness.js +206 -0
- 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 +45 -6
- package/dist/operations/services/git-workflow.js +251 -23
- package/dist/operations/services/github-actions-verification.d.ts +4 -1
- package/dist/operations/services/github-actions-verification.js +12 -3
- package/dist/operations/services/github-api.js +22 -6
- package/dist/operations/services/github-automation.d.ts +4 -4
- package/dist/operations/services/github-automation.js +19 -21
- package/dist/operations/services/github-credentials.d.ts +13 -0
- package/dist/operations/services/github-credentials.js +59 -0
- package/dist/operations/services/hosted-service-checks.d.ts +81 -0
- package/dist/operations/services/hosted-service-checks.js +478 -0
- 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 +22 -17
- package/dist/operations/services/live-hosted-service-checks.d.ts +26 -0
- package/dist/operations/services/live-hosted-service-checks.js +463 -0
- 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-host-security.js +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 +31 -0
- package/dist/operations/services/operations-runner-smoke.js +198 -0
- package/dist/operations/services/package-adapters.d.ts +170 -0
- package/dist/operations/services/package-adapters.js +859 -0
- package/dist/operations/services/package-reference-policy.d.ts +13 -88
- package/dist/operations/services/package-reference-policy.js +96 -215
- package/dist/operations/services/project-host-operations.d.ts +4 -4
- package/dist/operations/services/project-platform.d.ts +57 -173
- package/dist/operations/services/project-platform.js +80 -111
- package/dist/operations/services/project-web-monitor.d.ts +2 -2
- package/dist/operations/services/project-web-monitor.js +122 -5
- package/dist/operations/services/railway-api.d.ts +117 -5
- package/dist/operations/services/railway-api.js +915 -93
- package/dist/operations/services/railway-deploy.d.ts +30 -112
- package/dist/operations/services/railway-deploy.js +521 -961
- 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 +8 -7
- package/dist/operations/services/repository-save-orchestrator.js +604 -212
- 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 -191
- package/dist/operations/services/runtime-tools.js +4 -443
- 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/verification-cache.d.ts +25 -0
- package/dist/operations/services/verification-cache.js +71 -0
- 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 +50 -5
- 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 +42 -19
- package/dist/operations/services/workspace-tools.js +42 -7
- 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 +38 -2
- package/dist/platform/deploy-config.d.ts +1 -1
- package/dist/platform/deploy-config.js +80 -9
- 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 +568 -45
- package/dist/platform/environment.d.ts +3 -2
- package/dist/platform/environment.js +122 -21
- 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 +13 -4
- 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/platform-operation-store.js +2 -2
- package/dist/platform-operations.js +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 +5 -5
- package/dist/reconcile/builtin-adapters.d.ts +7 -1
- package/dist/reconcile/builtin-adapters.js +3190 -429
- package/dist/reconcile/contracts.d.ts +23 -6
- package/dist/reconcile/desired-state.d.ts +2 -192
- package/dist/reconcile/desired-state.js +29 -38
- package/dist/reconcile/engine.d.ts +61 -395
- package/dist/reconcile/engine.js +229 -44
- package/dist/reconcile/index.d.ts +10 -8
- package/dist/reconcile/index.js +2 -0
- package/dist/reconcile/live-acceptance.d.ts +100 -0
- package/dist/reconcile/live-acceptance.js +2027 -0
- package/dist/reconcile/platform.d.ts +104 -0
- package/dist/reconcile/platform.js +100 -0
- 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 +7 -44
- package/dist/reconcile/units.d.ts +1 -1
- package/dist/reconcile/units.js +9 -3
- 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/deployment-readiness.js +20 -0
- package/dist/scripts/generate-treedx-openapi-types.js +186 -0
- package/dist/scripts/migrate-journey-csv-to-guarantees.js +140 -0
- package/dist/scripts/operations-runner-smoke.js +16 -0
- package/dist/scripts/package-tools.js +12 -1
- package/dist/scripts/prepare.js +3 -7
- package/dist/scripts/release-verify.js +6 -6
- 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/tenant-workflow-action.js +10 -1
- 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 +1352 -116
- package/dist/sdk-types.js +413 -2
- package/dist/sdk.d.ts +106 -100
- package/dist/sdk.js +211 -51
- 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-requirements.js +9 -0
- package/dist/template-launch-ui.d.ts +2 -2
- package/dist/treedx/adapters.d.ts +6 -0
- package/dist/treedx/adapters.js +36 -0
- package/dist/treedx/client.d.ts +222 -0
- package/dist/treedx/client.js +871 -0
- package/dist/treedx/errors.d.ts +13 -0
- package/dist/treedx/errors.js +17 -0
- package/dist/treedx/federated-client.d.ts +27 -0
- package/dist/treedx/federated-client.js +158 -0
- package/dist/treedx/generated/openapi-types.d.ts +3558 -0
- package/dist/treedx/generated/openapi-types.js +0 -0
- package/dist/treedx/graph-adapter.d.ts +33 -0
- package/dist/treedx/graph-adapter.js +156 -0
- package/dist/treedx/index.d.ts +14 -0
- package/dist/treedx/index.js +48 -0
- package/dist/treedx/market-integration.d.ts +27 -0
- package/dist/treedx/market-integration.js +131 -0
- package/dist/treedx/ports.d.ts +166 -0
- package/dist/treedx/ports.js +231 -0
- package/dist/treedx/query-adapter.d.ts +19 -0
- package/dist/treedx/query-adapter.js +62 -0
- package/dist/treedx/registry-client.d.ts +11 -0
- package/dist/treedx/registry-client.js +19 -0
- package/dist/treedx/repository-adapter.d.ts +45 -0
- package/dist/treedx/repository-adapter.js +319 -0
- package/dist/treedx/sdk-integration.d.ts +27 -0
- package/dist/treedx/sdk-integration.js +63 -0
- package/dist/treedx/types.d.ts +1084 -0
- package/dist/treedx/types.js +8 -0
- package/dist/treedx/workspace-adapter.d.ts +27 -0
- package/dist/treedx/workspace-adapter.js +65 -0
- package/dist/treedx-backends.d.ts +220 -0
- package/dist/treedx-backends.js +634 -0
- package/dist/treedx-client.d.ts +89 -0
- package/dist/treedx-client.js +184 -0
- package/dist/treeseed/services/compose.yml +2 -3
- package/dist/treeseed/template-catalog/catalog.fixture.json +27 -27
- 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 +580 -523
- package/dist/workflow/operations.js +2084 -1279
- 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 +17 -4
- package/dist/workflow-state.js +68 -41
- package/dist/workflow-support.d.ts +26 -17
- package/dist/workflow-support.js +84 -24
- package/dist/workflow.d.ts +51 -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/0004_treedx_market_integration.sql +99 -0
- 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 +106 -18
- package/scripts/{verify-driver.mjs → verify-driver.ts} +19 -4
- package/templates/github/deploy-web.workflow.yml +49 -12
- 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 -41
- package/dist/operations/services/release-candidate.js +0 -616
- 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,7 +1,8 @@
|
|
|
1
|
-
import { existsSync,
|
|
2
|
-
import { tmpdir } from "node:os";
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
3
2
|
import { basename, resolve, relative } from "node:path";
|
|
4
3
|
import { spawn, spawnSync } from "node:child_process";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
import { classifyTreeseedGitMode, runTreeseedGitText } from "./git-runner.js";
|
|
5
6
|
import {
|
|
6
7
|
ensureSshPushUrlForOrigin,
|
|
7
8
|
remoteWriteUrl,
|
|
@@ -11,8 +12,8 @@ import {
|
|
|
11
12
|
generateRepositoryCommitMessage
|
|
12
13
|
} from "./commit-message-provider.js";
|
|
13
14
|
import {
|
|
14
|
-
createDevTagMessage,
|
|
15
15
|
createPackageDependencyReference,
|
|
16
|
+
normalizeGitRemoteForDependency,
|
|
16
17
|
updateInternalDependencySpecs
|
|
17
18
|
} from "./package-reference-policy.js";
|
|
18
19
|
import {
|
|
@@ -33,15 +34,39 @@ import {
|
|
|
33
34
|
} from "./workspace-save.js";
|
|
34
35
|
import {
|
|
35
36
|
hasCompleteTreeseedPackageCheckout,
|
|
36
|
-
run,
|
|
37
37
|
sortWorkspacePackages,
|
|
38
38
|
workspacePackages
|
|
39
39
|
} from "./workspace-tools.js";
|
|
40
|
-
import { collectDeploymentLockfileWorkspaceIssues } from "./workspace-dependency-mode.js";
|
|
40
|
+
import { collectDeploymentLockfileWorkspaceIssues, ensureLocalWorkspaceLinks } from "./workspace-dependency-mode.js";
|
|
41
41
|
import {
|
|
42
42
|
createBuildWarningSummary,
|
|
43
43
|
formatAllowedBuildWarnings
|
|
44
44
|
} from "./build-warning-policy.js";
|
|
45
|
+
import {
|
|
46
|
+
readTreeseedVerificationCache,
|
|
47
|
+
writeTreeseedVerificationCache
|
|
48
|
+
} from "./verification-cache.js";
|
|
49
|
+
import {
|
|
50
|
+
discoverTreeseedPackageAdapters
|
|
51
|
+
} from "./package-adapters.js";
|
|
52
|
+
import {
|
|
53
|
+
discoverTreeseedManagedRepositories,
|
|
54
|
+
parseGitmodulesPaths,
|
|
55
|
+
readTreeseedTemplateRepositoryManifest
|
|
56
|
+
} from "./managed-repositories.js";
|
|
57
|
+
function runGit(args, options) {
|
|
58
|
+
return runTreeseedGitText(args, {
|
|
59
|
+
cwd: options.cwd,
|
|
60
|
+
mode: classifyTreeseedGitMode(args),
|
|
61
|
+
timeoutMs: options.timeoutMs,
|
|
62
|
+
maxBuffer: options.maxBuffer
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
function sleepMs(durationMs) {
|
|
66
|
+
return new Promise((resolvePromise) => {
|
|
67
|
+
setTimeout(resolvePromise, durationMs);
|
|
68
|
+
});
|
|
69
|
+
}
|
|
45
70
|
class RepositorySaveError extends Error {
|
|
46
71
|
exitCode;
|
|
47
72
|
details;
|
|
@@ -71,11 +96,66 @@ function emitProgress(options, node, phase, message, stream = "stdout") {
|
|
|
71
96
|
function prefixedOutput(node, phase, output) {
|
|
72
97
|
return String(output ?? "").split(/\r?\n/u).map((line) => line.trimEnd()).filter(Boolean).map((line) => `${progressPrefix(node, phase)} ${line}`).join("\n");
|
|
73
98
|
}
|
|
99
|
+
function withShortProcessTempEnv(env = {}) {
|
|
100
|
+
const merged = { ...process.env, ...env };
|
|
101
|
+
if (process.platform === "win32") {
|
|
102
|
+
return merged;
|
|
103
|
+
}
|
|
104
|
+
const shortTemp = tmpdir();
|
|
105
|
+
const tempKeys = ["TMPDIR", "TMP", "TEMP"];
|
|
106
|
+
for (const key of tempKeys) {
|
|
107
|
+
const value = merged[key];
|
|
108
|
+
if (value && value.length > shortTemp.length) {
|
|
109
|
+
merged[key] = shortTemp;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return merged;
|
|
113
|
+
}
|
|
114
|
+
function npmCacheForCwd(cwd) {
|
|
115
|
+
const cacheDir = resolve(cwd, ".treeseed", "cache", "npm");
|
|
116
|
+
mkdirSync(cacheDir, { recursive: true });
|
|
117
|
+
return cacheDir;
|
|
118
|
+
}
|
|
119
|
+
function npmWorkflowEnv(env = {}, cwd = process.cwd()) {
|
|
120
|
+
const npmCache = env.npm_config_cache ?? env.NPM_CONFIG_CACHE ?? process.env.npm_config_cache ?? process.env.NPM_CONFIG_CACHE ?? npmCacheForCwd(cwd);
|
|
121
|
+
return withShortProcessTempEnv({
|
|
122
|
+
...env,
|
|
123
|
+
NPM_CONFIG_CACHE: npmCache,
|
|
124
|
+
npm_config_audit: env.npm_config_audit ?? process.env.npm_config_audit ?? "false",
|
|
125
|
+
npm_config_cache: npmCache,
|
|
126
|
+
npm_config_fetch_retries: env.npm_config_fetch_retries ?? process.env.npm_config_fetch_retries ?? "2",
|
|
127
|
+
npm_config_fund: env.npm_config_fund ?? process.env.npm_config_fund ?? "false",
|
|
128
|
+
npm_config_foreground_scripts: env.npm_config_foreground_scripts ?? process.env.npm_config_foreground_scripts ?? "true",
|
|
129
|
+
npm_config_loglevel: env.npm_config_loglevel ?? process.env.npm_config_loglevel ?? "warn",
|
|
130
|
+
npm_config_maxsockets: env.npm_config_maxsockets ?? process.env.npm_config_maxsockets ?? "4",
|
|
131
|
+
npm_config_prefer_offline: env.npm_config_prefer_offline ?? process.env.npm_config_prefer_offline ?? "true",
|
|
132
|
+
npm_config_progress: env.npm_config_progress ?? process.env.npm_config_progress ?? "false"
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
function npmCommandForSpawn(args) {
|
|
136
|
+
if (process.platform === "win32") {
|
|
137
|
+
return { command: "npm", args };
|
|
138
|
+
}
|
|
139
|
+
return {
|
|
140
|
+
command: "bash",
|
|
141
|
+
args: [
|
|
142
|
+
"-lc",
|
|
143
|
+
'ulimit -n 65535 2>/dev/null || ulimit -n 32768 2>/dev/null || ulimit -n 16384 2>/dev/null || true; exec npm "$@"',
|
|
144
|
+
"npm-fd-guard",
|
|
145
|
+
...args
|
|
146
|
+
]
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
function displayCommand(command, args) {
|
|
150
|
+
return command === "npm" ? `npm ${args.join(" ")}` : `${command} ${args.join(" ")}`;
|
|
151
|
+
}
|
|
74
152
|
function runCapturedCommand(node, options, phase, command, args, commandOptions = {}) {
|
|
75
|
-
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
153
|
+
const cwd = commandOptions.cwd ?? node.path;
|
|
154
|
+
const spawnCommand = command === "npm" ? npmCommandForSpawn(args) : { command, args };
|
|
155
|
+
emitProgress(options, node, phase, `$ ${displayCommand(command, args)}`);
|
|
156
|
+
const result = spawnSync(spawnCommand.command, spawnCommand.args, {
|
|
157
|
+
cwd,
|
|
158
|
+
env: command === "npm" ? npmWorkflowEnv(commandOptions.env, cwd) : withShortProcessTempEnv(commandOptions.env),
|
|
79
159
|
stdio: "pipe",
|
|
80
160
|
encoding: "utf8",
|
|
81
161
|
timeout: commandOptions.timeoutMs
|
|
@@ -88,12 +168,12 @@ function runCapturedCommand(node, options, phase, command, args, commandOptions
|
|
|
88
168
|
}
|
|
89
169
|
if (result.status !== 0) {
|
|
90
170
|
const message = (result.error?.message ? `${result.error.message}
|
|
91
|
-
` : "") + (prefixedOutput(node, phase, stderr) || prefixedOutput(node, phase, stdout) || `${progressPrefix(node, phase)} ${command
|
|
171
|
+
` : "") + (prefixedOutput(node, phase, stderr) || prefixedOutput(node, phase, stdout) || `${progressPrefix(node, phase)} ${displayCommand(command, args)} failed`);
|
|
92
172
|
throw new RepositorySaveError(message, {
|
|
93
173
|
details: {
|
|
94
174
|
failingRepo: node.name,
|
|
95
175
|
phase,
|
|
96
|
-
command:
|
|
176
|
+
command: displayCommand(command, args)
|
|
97
177
|
}
|
|
98
178
|
});
|
|
99
179
|
}
|
|
@@ -121,9 +201,11 @@ function isNoOpGitCommitError(error) {
|
|
|
121
201
|
return /nothing to commit|no changes added to commit/u.test(error.message);
|
|
122
202
|
}
|
|
123
203
|
function runQuietCommand(node, phase, command, args, commandOptions = {}) {
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
|
|
204
|
+
const cwd = commandOptions.cwd ?? node.path;
|
|
205
|
+
const spawnCommand = command === "npm" ? npmCommandForSpawn(args) : { command, args };
|
|
206
|
+
const result = spawnSync(spawnCommand.command, spawnCommand.args, {
|
|
207
|
+
cwd,
|
|
208
|
+
env: command === "npm" ? npmWorkflowEnv(commandOptions.env, cwd) : withShortProcessTempEnv(commandOptions.env),
|
|
127
209
|
stdio: "pipe",
|
|
128
210
|
encoding: "utf8",
|
|
129
211
|
timeout: commandOptions.timeoutMs
|
|
@@ -133,14 +215,14 @@ function runQuietCommand(node, phase, command, args, commandOptions = {}) {
|
|
|
133
215
|
if (result.status !== 0) {
|
|
134
216
|
throw new RepositorySaveError(
|
|
135
217
|
[
|
|
136
|
-
`${progressPrefix(node, phase)} ${command
|
|
218
|
+
`${progressPrefix(node, phase)} ${displayCommand(command, args)} failed`,
|
|
137
219
|
stderr || stdout
|
|
138
220
|
].filter(Boolean).join("\n"),
|
|
139
221
|
{
|
|
140
222
|
details: {
|
|
141
223
|
failingRepo: node.name,
|
|
142
224
|
phase,
|
|
143
|
-
command:
|
|
225
|
+
command: displayCommand(command, args)
|
|
144
226
|
}
|
|
145
227
|
}
|
|
146
228
|
);
|
|
@@ -148,11 +230,13 @@ function runQuietCommand(node, phase, command, args, commandOptions = {}) {
|
|
|
148
230
|
return stdout;
|
|
149
231
|
}
|
|
150
232
|
async function runStreamingCommand(node, options, phase, command, args, commandOptions = {}) {
|
|
151
|
-
|
|
233
|
+
const cwd = commandOptions.cwd ?? node.path;
|
|
234
|
+
const spawnCommand = command === "npm" ? npmCommandForSpawn(args) : { command, args };
|
|
235
|
+
emitProgress(options, node, phase, `$ ${displayCommand(command, args)}`);
|
|
152
236
|
return await new Promise((resolvePromise, reject) => {
|
|
153
|
-
const child = spawn(command, args, {
|
|
154
|
-
cwd
|
|
155
|
-
env:
|
|
237
|
+
const child = spawn(spawnCommand.command, spawnCommand.args, {
|
|
238
|
+
cwd,
|
|
239
|
+
env: command === "npm" ? npmWorkflowEnv(commandOptions.env, cwd) : withShortProcessTempEnv(commandOptions.env),
|
|
156
240
|
stdio: ["ignore", "pipe", "pipe"]
|
|
157
241
|
});
|
|
158
242
|
let stdout = "";
|
|
@@ -179,7 +263,7 @@ async function runStreamingCommand(node, options, phase, command, args, commandO
|
|
|
179
263
|
if (settled) return;
|
|
180
264
|
settled = true;
|
|
181
265
|
child.kill("SIGTERM");
|
|
182
|
-
reject(new Error(`${progressPrefix(node, phase)} ${command
|
|
266
|
+
reject(new Error(`${progressPrefix(node, phase)} ${displayCommand(command, args)} timed out after ${commandOptions.timeoutMs}ms`));
|
|
183
267
|
}, commandOptions.timeoutMs) : null;
|
|
184
268
|
child.stdout?.on("data", (chunk) => {
|
|
185
269
|
const text = chunk.toString();
|
|
@@ -219,12 +303,12 @@ async function runStreamingCommand(node, options, phase, command, args, commandO
|
|
|
219
303
|
return;
|
|
220
304
|
}
|
|
221
305
|
reject(new RepositorySaveError(
|
|
222
|
-
prefixedOutput(node, phase, stderr) || prefixedOutput(node, phase, stdout) || `${progressPrefix(node, phase)} ${command
|
|
306
|
+
prefixedOutput(node, phase, stderr) || prefixedOutput(node, phase, stdout) || `${progressPrefix(node, phase)} ${displayCommand(command, args)} failed with exit code ${code ?? "unknown"}`,
|
|
223
307
|
{
|
|
224
308
|
details: {
|
|
225
309
|
failingRepo: node.name,
|
|
226
310
|
phase,
|
|
227
|
-
command:
|
|
311
|
+
command: displayCommand(command, args)
|
|
228
312
|
}
|
|
229
313
|
}
|
|
230
314
|
));
|
|
@@ -235,7 +319,9 @@ function packageScripts(packageJson) {
|
|
|
235
319
|
const scripts = packageJson?.scripts;
|
|
236
320
|
return scripts && typeof scripts === "object" && !Array.isArray(scripts) ? Object.fromEntries(Object.entries(scripts).map(([key, value]) => [key, String(value)])) : {};
|
|
237
321
|
}
|
|
238
|
-
function classifyRepoKind(packageJson) {
|
|
322
|
+
function classifyRepoKind(packageJson, managedKind) {
|
|
323
|
+
if (managedKind === "template") return "template";
|
|
324
|
+
if (managedKind === "fixture") return "fixture";
|
|
239
325
|
if (typeof packageJson?.name !== "string" || typeof packageJson?.version !== "string") {
|
|
240
326
|
return "project";
|
|
241
327
|
}
|
|
@@ -255,12 +341,19 @@ function repoIdForPath(root, repoDir) {
|
|
|
255
341
|
}
|
|
256
342
|
function isGitRepo(repoDir) {
|
|
257
343
|
try {
|
|
258
|
-
|
|
344
|
+
runGit(["rev-parse", "--is-inside-work-tree"], { cwd: repoDir, capture: true });
|
|
259
345
|
return true;
|
|
260
346
|
} catch {
|
|
261
347
|
return false;
|
|
262
348
|
}
|
|
263
349
|
}
|
|
350
|
+
function isIndependentGitRepo(repoDir) {
|
|
351
|
+
try {
|
|
352
|
+
return resolve(repoRoot(repoDir)) === resolve(repoDir);
|
|
353
|
+
} catch {
|
|
354
|
+
return false;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
264
357
|
function originRemoteUrlSafe(repoDir) {
|
|
265
358
|
try {
|
|
266
359
|
return originRemoteUrl(repoDir);
|
|
@@ -278,17 +371,23 @@ function ensureWritableRemote(node, options) {
|
|
|
278
371
|
function repoDisplayName(repoDir, packageJson) {
|
|
279
372
|
return typeof packageJson?.name === "string" && packageJson.name.length > 0 ? packageJson.name : basename(repoDir);
|
|
280
373
|
}
|
|
374
|
+
function emptyManifestVerifyCommands() {
|
|
375
|
+
return { fast: null, local: null, release: null };
|
|
376
|
+
}
|
|
377
|
+
function verifyCommandFromString(repoDir, label, command) {
|
|
378
|
+
return command ? { label, command: "bash", args: ["-lc", command], cwd: repoDir } : null;
|
|
379
|
+
}
|
|
380
|
+
function templateVerifyCommands(repoDir) {
|
|
381
|
+
const manifest = readTreeseedTemplateRepositoryManifest(repoDir);
|
|
382
|
+
if (!manifest) return null;
|
|
383
|
+
return {
|
|
384
|
+
fast: verifyCommandFromString(repoDir, "fast", manifest.verify.fast),
|
|
385
|
+
local: verifyCommandFromString(repoDir, "local", manifest.verify.local),
|
|
386
|
+
release: verifyCommandFromString(repoDir, "release", manifest.verify.release)
|
|
387
|
+
};
|
|
388
|
+
}
|
|
281
389
|
function parseGitmodules(root) {
|
|
282
|
-
|
|
283
|
-
if (!existsSync(gitmodulesPath)) {
|
|
284
|
-
return [];
|
|
285
|
-
}
|
|
286
|
-
const source = readFileSync(gitmodulesPath, "utf8");
|
|
287
|
-
const paths = [];
|
|
288
|
-
for (const match of source.matchAll(/^\s*path\s*=\s*(.+?)\s*$/gmu)) {
|
|
289
|
-
paths.push(match[1].replaceAll("\\", "/"));
|
|
290
|
-
}
|
|
291
|
-
return paths;
|
|
390
|
+
return parseGitmodulesPaths(root);
|
|
292
391
|
}
|
|
293
392
|
function slugBranch(branch) {
|
|
294
393
|
return branch.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40) || "dev";
|
|
@@ -312,18 +411,38 @@ function isDevVersionForBranch(version, branch) {
|
|
|
312
411
|
function packageVersionAtHead(node) {
|
|
313
412
|
if (!node.packageJsonPath) return null;
|
|
314
413
|
try {
|
|
315
|
-
const source =
|
|
414
|
+
const source = runGit(["show", "HEAD:package.json"], { cwd: node.path, capture: true });
|
|
316
415
|
const packageJson = JSON.parse(source);
|
|
317
416
|
return typeof packageJson.version === "string" ? packageJson.version : null;
|
|
318
417
|
} catch {
|
|
319
418
|
return null;
|
|
320
419
|
}
|
|
321
420
|
}
|
|
421
|
+
function headCommitOrPlanPlaceholder(cwd) {
|
|
422
|
+
try {
|
|
423
|
+
return headCommit(cwd);
|
|
424
|
+
} catch {
|
|
425
|
+
return "HEAD";
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
function remoteBranchCommitSafe(cwd, branch) {
|
|
429
|
+
try {
|
|
430
|
+
const output = runGit(["ls-remote", "origin", `refs/heads/${branch}`], { cwd, capture: true });
|
|
431
|
+
const [sha] = output.trim().split(/\s+/u);
|
|
432
|
+
return /^[a-f0-9]{40}$/u.test(sha ?? "") ? sha : null;
|
|
433
|
+
} catch {
|
|
434
|
+
return null;
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
function canManagePackageJsonVersion(node) {
|
|
438
|
+
return node.kind === "package" && Boolean(node.packageJsonPath) && typeof node.packageJson?.version === "string";
|
|
439
|
+
}
|
|
322
440
|
function packageVersionEligibleForBranch(node, version, options) {
|
|
323
441
|
return node.branchMode === "package-release-main" ? isStableSemverVersion(version) : isDevVersionForBranch(version, node.branch || options.branch);
|
|
324
442
|
}
|
|
325
443
|
function packageVersionTagConflictsWithHead(node, options) {
|
|
326
444
|
if (node.kind !== "package") return false;
|
|
445
|
+
if (node.branchMode === "package-dev-save" && (options.devDependencyReferenceMode ?? "git-commit") === "git-commit") return false;
|
|
327
446
|
const version = typeof node.packageJson?.version === "string" ? node.packageJson.version : null;
|
|
328
447
|
if (!version || !packageVersionEligibleForBranch(node, version, options)) return false;
|
|
329
448
|
const head = headCommit(node.path);
|
|
@@ -332,7 +451,7 @@ function packageVersionTagConflictsWithHead(node, options) {
|
|
|
332
451
|
}
|
|
333
452
|
function selectPackageVersion(node, options) {
|
|
334
453
|
const current = String(node.packageJson?.version ?? "0.0.0");
|
|
335
|
-
if (node.branchMode === "package-dev-save" && isDevVersionForBranch(current, node.branch || options.branch) && !tagExists(node.path, current)) {
|
|
454
|
+
if (node.branchMode === "package-dev-save" && isDevVersionForBranch(current, node.branch || options.branch) && ((options.devDependencyReferenceMode ?? "git-commit") === "git-commit" || !tagExists(node.path, current))) {
|
|
336
455
|
return { version: current, reused: true };
|
|
337
456
|
}
|
|
338
457
|
if (node.branchMode === "package-release-main") {
|
|
@@ -363,8 +482,6 @@ function createReport(node) {
|
|
|
363
482
|
publishWait: null,
|
|
364
483
|
version: typeof node.packageJson?.version === "string" ? node.packageJson.version : null,
|
|
365
484
|
dependencySpec: node.plannedDependencySpec,
|
|
366
|
-
devTagMetadata: null,
|
|
367
|
-
replacedDevTags: [],
|
|
368
485
|
branchMode: node.branchMode,
|
|
369
486
|
verification: null,
|
|
370
487
|
install: null,
|
|
@@ -377,29 +494,43 @@ function createReport(node) {
|
|
|
377
494
|
}
|
|
378
495
|
function discoverRepositorySaveNodes(root, gitRoot = repoRoot(root), branch = currentBranch(gitRoot), options = {}) {
|
|
379
496
|
const repoDirs = /* @__PURE__ */ new Map();
|
|
380
|
-
|
|
497
|
+
const packageAdaptersByDir = new Map(discoverTreeseedPackageAdapters(root).map((adapter) => [resolve(adapter.dir), adapter]));
|
|
498
|
+
const managedRepositoriesByDir = new Map(discoverTreeseedManagedRepositories(root).map((repo) => [resolve(repo.dir), repo]));
|
|
499
|
+
for (const repo of managedRepositoriesByDir.values()) {
|
|
500
|
+
repoDirs.set(repo.relativeDir, repo.dir);
|
|
501
|
+
}
|
|
502
|
+
if (!repoDirs.has(".")) {
|
|
503
|
+
repoDirs.set(".", gitRoot);
|
|
504
|
+
}
|
|
381
505
|
if (hasCompleteTreeseedPackageCheckout(root)) {
|
|
382
506
|
for (const pkg of workspacePackages(root)) {
|
|
383
|
-
if (
|
|
507
|
+
if (isIndependentGitRepo(pkg.dir)) {
|
|
384
508
|
repoDirs.set(pkg.relativeDir, pkg.dir);
|
|
385
509
|
}
|
|
386
510
|
}
|
|
387
511
|
}
|
|
512
|
+
for (const adapter of packageAdaptersByDir.values()) {
|
|
513
|
+
if (isIndependentGitRepo(adapter.dir)) {
|
|
514
|
+
repoDirs.set(adapter.relativeDir, adapter.dir);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
388
517
|
for (const submodulePath of parseGitmodules(root)) {
|
|
389
518
|
const dir = resolve(root, submodulePath);
|
|
390
|
-
if (existsSync(dir) &&
|
|
519
|
+
if (existsSync(dir) && isIndependentGitRepo(dir)) {
|
|
391
520
|
repoDirs.set(submodulePath, dir);
|
|
392
521
|
}
|
|
393
522
|
}
|
|
394
523
|
const nodes = [...repoDirs.entries()].map(([relativePath, repoDir]) => {
|
|
395
524
|
const packageJsonPath = resolve(repoDir, "package.json");
|
|
396
525
|
const packageJson = existsSync(packageJsonPath) ? readJson(packageJsonPath) : null;
|
|
397
|
-
const
|
|
526
|
+
const adapter = packageAdaptersByDir.get(resolve(repoDir)) ?? null;
|
|
527
|
+
const managed = managedRepositoriesByDir.get(resolve(repoDir)) ?? null;
|
|
528
|
+
const kind = adapter && !packageJson ? "package" : classifyRepoKind(packageJson, managed?.kind);
|
|
398
529
|
const repoBranch = relativePath === "." ? currentBranch(repoDir) || branch || null : branch || currentBranch(repoDir) || null;
|
|
399
530
|
const branchMode = kind === "project" ? "project-save" : options.stablePackageRelease === true && repoBranch === PRODUCTION_BRANCH ? "package-release-main" : "package-dev-save";
|
|
400
531
|
return {
|
|
401
532
|
id: relativePath,
|
|
402
|
-
name: repoDisplayName(repoDir, packageJson),
|
|
533
|
+
name: managed?.kind === "template" || managed?.kind === "fixture" ? managed.name : adapter?.id ?? repoDisplayName(repoDir, packageJson),
|
|
403
534
|
path: repoDir,
|
|
404
535
|
relativePath,
|
|
405
536
|
kind,
|
|
@@ -408,6 +539,7 @@ function discoverRepositorySaveNodes(root, gitRoot = repoRoot(root), branch = cu
|
|
|
408
539
|
packageJsonPath: packageJson ? packageJsonPath : null,
|
|
409
540
|
packageJson,
|
|
410
541
|
scripts: packageScripts(packageJson),
|
|
542
|
+
manifestVerifyCommands: adapter?.verifyCommands ?? templateVerifyCommands(repoDir) ?? emptyManifestVerifyCommands(),
|
|
411
543
|
remoteUrl: originRemoteUrlSafe(repoDir),
|
|
412
544
|
dependencies: [],
|
|
413
545
|
dependents: [],
|
|
@@ -502,9 +634,16 @@ function runLimited(items, limit, action) {
|
|
|
502
634
|
});
|
|
503
635
|
return Promise.all(workers);
|
|
504
636
|
}
|
|
637
|
+
function repositorySaveConcurrency(options) {
|
|
638
|
+
if (options.verifyMode && options.verifyMode !== "skip") {
|
|
639
|
+
return 1;
|
|
640
|
+
}
|
|
641
|
+
const configured = Number.parseInt(process.env.TREESEED_SAVE_REPOSITORY_CONCURRENCY ?? "", 10);
|
|
642
|
+
return Number.isFinite(configured) && configured > 0 ? configured : 3;
|
|
643
|
+
}
|
|
505
644
|
function remoteBranchExistsSafe(repoDir, branch) {
|
|
506
645
|
try {
|
|
507
|
-
|
|
646
|
+
runGit(["rev-parse", "--verify", `refs/remotes/origin/${branch}`], { cwd: repoDir, capture: true });
|
|
508
647
|
return true;
|
|
509
648
|
} catch {
|
|
510
649
|
}
|
|
@@ -553,13 +692,18 @@ function commitSubject(message) {
|
|
|
553
692
|
return String(message ?? "").split(/\r?\n/u)[0]?.trim() || null;
|
|
554
693
|
}
|
|
555
694
|
function gitDiffSummary(repoDir) {
|
|
556
|
-
const changedFiles =
|
|
557
|
-
const
|
|
695
|
+
const changedFiles = runGit(["status", "--porcelain"], { cwd: repoDir, capture: true });
|
|
696
|
+
const rawDiff = runGit(["diff", "--cached"], { cwd: repoDir, capture: true, maxBuffer: 1024 * 1024 * 32 });
|
|
697
|
+
const maxDiffChars = 12e4;
|
|
698
|
+
const diff = rawDiff.length > maxDiffChars ? `${rawDiff.slice(0, maxDiffChars)}
|
|
699
|
+
|
|
700
|
+
[treeseed-save: diff truncated from ${rawDiff.length} characters for commit-message generation]
|
|
701
|
+
` : rawDiff;
|
|
558
702
|
return { changedFiles, diff };
|
|
559
703
|
}
|
|
560
704
|
function hasStagedChanges(repoDir) {
|
|
561
705
|
try {
|
|
562
|
-
return
|
|
706
|
+
return runGit(["diff", "--cached", "--name-only"], { cwd: repoDir, capture: true }).trim().length > 0;
|
|
563
707
|
} catch {
|
|
564
708
|
return false;
|
|
565
709
|
}
|
|
@@ -572,6 +716,54 @@ function updateDependencyReferences(node, finalizedReferences) {
|
|
|
572
716
|
}
|
|
573
717
|
return changed;
|
|
574
718
|
}
|
|
719
|
+
function isRootWorkspaceRepository(node, options) {
|
|
720
|
+
const packageJson = node.packageJson ?? (existsSync(resolve(node.path, "package.json")) ? readJson(resolve(node.path, "package.json")) : null);
|
|
721
|
+
return node.path === options.root && Array.isArray(packageJson?.workspaces);
|
|
722
|
+
}
|
|
723
|
+
function syncDirectGitDependencyLockfileEntries(node, options, references) {
|
|
724
|
+
if (references.length === 0) return false;
|
|
725
|
+
const lockfilePath = resolve(node.path, "package-lock.json");
|
|
726
|
+
if (!existsSync(lockfilePath)) return false;
|
|
727
|
+
const lockfile = readJson(lockfilePath);
|
|
728
|
+
const rootPackage = lockfile.packages && typeof lockfile.packages === "object" && !Array.isArray(lockfile.packages) ? lockfile.packages[""] : null;
|
|
729
|
+
const packageEntries = lockfile.packages && typeof lockfile.packages === "object" && !Array.isArray(lockfile.packages) ? lockfile.packages : null;
|
|
730
|
+
if (!rootPackage || !packageEntries) return false;
|
|
731
|
+
let changed = false;
|
|
732
|
+
for (const reference of references) {
|
|
733
|
+
const manifestSpec = reference.manifestSpec ?? reference.spec;
|
|
734
|
+
for (const field of dependencyFields(rootPackage)) {
|
|
735
|
+
const values = rootPackage[field];
|
|
736
|
+
if (!values || typeof values !== "object" || Array.isArray(values)) continue;
|
|
737
|
+
const dependencies = values;
|
|
738
|
+
if (reference.packageName in dependencies && dependencies[reference.packageName] !== manifestSpec) {
|
|
739
|
+
dependencies[reference.packageName] = manifestSpec;
|
|
740
|
+
changed = true;
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
const entryKey = `node_modules/${reference.packageName}`;
|
|
744
|
+
const entry = packageEntries[entryKey];
|
|
745
|
+
if (entry) {
|
|
746
|
+
const nextResolved = normalizeGitRemoteForDependency(reference.remoteUrl ?? "", "ssh");
|
|
747
|
+
const resolved = nextResolved ? `${nextResolved}#${manifestSpec.slice(manifestSpec.lastIndexOf("#") + 1)}` : manifestSpec;
|
|
748
|
+
if (entry.resolved !== resolved) {
|
|
749
|
+
entry.resolved = resolved;
|
|
750
|
+
changed = true;
|
|
751
|
+
}
|
|
752
|
+
if (typeof reference.version === "string" && reference.version && entry.version !== reference.version) {
|
|
753
|
+
entry.version = reference.version;
|
|
754
|
+
changed = true;
|
|
755
|
+
}
|
|
756
|
+
if ("integrity" in entry) {
|
|
757
|
+
delete entry.integrity;
|
|
758
|
+
changed = true;
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
if (!changed) return false;
|
|
763
|
+
writeJson(lockfilePath, lockfile);
|
|
764
|
+
emitProgress(options, node, "lockfile", "Synchronized direct internal Git dependency lockfile entries without npm git preparation.");
|
|
765
|
+
return true;
|
|
766
|
+
}
|
|
575
767
|
function planPackageVersion(node, options) {
|
|
576
768
|
if (!node.packageJson || !node.packageJsonPath) return null;
|
|
577
769
|
const current = String(node.packageJson.version ?? "0.0.0");
|
|
@@ -593,44 +785,106 @@ function shouldSkipGitDependencySmoke(options) {
|
|
|
593
785
|
function hasNpmLockfile(repoDir) {
|
|
594
786
|
return existsSync(resolve(repoDir, "package-lock.json")) || existsSync(resolve(repoDir, "npm-shrinkwrap.json"));
|
|
595
787
|
}
|
|
596
|
-
|
|
597
|
-
if (
|
|
598
|
-
const
|
|
599
|
-
|
|
600
|
-
const
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
788
|
+
function syncRootWorkspaceLockfileMetadata(node, options) {
|
|
789
|
+
if (node.path !== options.root || !Array.isArray(node.packageJson?.workspaces)) return false;
|
|
790
|
+
const lockfilePath = resolve(node.path, "package-lock.json");
|
|
791
|
+
if (!existsSync(lockfilePath)) return false;
|
|
792
|
+
const lockfile = readJson(lockfilePath);
|
|
793
|
+
const packages = lockfile.packages;
|
|
794
|
+
if (!packages || typeof packages !== "object" || Array.isArray(packages)) return false;
|
|
795
|
+
let changed = false;
|
|
796
|
+
const packageEntries = packages;
|
|
797
|
+
const rootEntry = packageEntries[""] ?? {};
|
|
798
|
+
const workspacePackageList = workspacePackages(node.path);
|
|
799
|
+
const workspaceVersionByName = new Map(workspacePackageList.map((workspacePackage) => [String(workspacePackage.packageJson.name ?? ""), String(workspacePackage.packageJson.version ?? "")]).filter(([name, version]) => name.length > 0 && version.length > 0));
|
|
800
|
+
const rootDependencySpecs = /* @__PURE__ */ new Map();
|
|
801
|
+
for (const field of dependencyFields(node.packageJson)) {
|
|
802
|
+
const rootDeps = node.packageJson[field];
|
|
803
|
+
if (!rootDeps || typeof rootDeps !== "object" || Array.isArray(rootDeps)) continue;
|
|
804
|
+
for (const [dependencyName, dependencySpec] of Object.entries(rootDeps)) {
|
|
805
|
+
if (typeof dependencySpec === "string") {
|
|
806
|
+
rootDependencySpecs.set(dependencyName, dependencySpec);
|
|
610
807
|
}
|
|
611
|
-
}
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
const stableWorkspaceDependencySpec = (dependencyName) => rootDependencySpecs.get(dependencyName) ?? workspaceVersionByName.get(dependencyName) ?? null;
|
|
811
|
+
const normalizeWorkspaceDependencySpecs = (value) => Object.fromEntries(
|
|
812
|
+
Object.entries(value).map(([dependencyName, dependencySpec]) => [
|
|
813
|
+
dependencyName,
|
|
814
|
+
workspaceVersionByName.has(dependencyName) ? stableWorkspaceDependencySpec(dependencyName) : dependencySpec
|
|
815
|
+
])
|
|
816
|
+
);
|
|
817
|
+
if (JSON.stringify(rootEntry.workspaces ?? []) !== JSON.stringify(node.packageJson.workspaces)) {
|
|
818
|
+
rootEntry.workspaces = node.packageJson.workspaces;
|
|
819
|
+
packageEntries[""] = rootEntry;
|
|
820
|
+
changed = true;
|
|
821
|
+
}
|
|
822
|
+
for (const field of dependencyFields(node.packageJson)) {
|
|
823
|
+
const nextValue = node.packageJson[field];
|
|
824
|
+
if (nextValue && typeof nextValue === "object" && !Array.isArray(nextValue)) {
|
|
825
|
+
const currentValue = rootEntry[field];
|
|
826
|
+
const currentDeps = currentValue && typeof currentValue === "object" && !Array.isArray(currentValue) ? currentValue : {};
|
|
827
|
+
const mergedDeps = { ...currentDeps };
|
|
828
|
+
let fieldChanged = false;
|
|
829
|
+
for (const [dependencyName, dependencySpec] of Object.entries(nextValue)) {
|
|
830
|
+
if (mergedDeps[dependencyName] != null) continue;
|
|
831
|
+
mergedDeps[dependencyName] = dependencySpec;
|
|
832
|
+
fieldChanged = true;
|
|
620
833
|
}
|
|
621
|
-
if (
|
|
622
|
-
|
|
623
|
-
|
|
834
|
+
if (fieldChanged) {
|
|
835
|
+
rootEntry[field] = mergedDeps;
|
|
836
|
+
packageEntries[""] = rootEntry;
|
|
837
|
+
changed = true;
|
|
624
838
|
}
|
|
625
839
|
}
|
|
626
|
-
throw new RepositorySaveError([
|
|
627
|
-
`Git dependency smoke install failed for ${reference.packageName} after 5 attempts.`,
|
|
628
|
-
`Spec: ${installSpec}`,
|
|
629
|
-
lastError ?? ""
|
|
630
|
-
].join("\n"));
|
|
631
|
-
} finally {
|
|
632
|
-
rmSync(tempRoot, { recursive: true, force: true });
|
|
633
840
|
}
|
|
841
|
+
for (const workspacePackage of workspacePackageList) {
|
|
842
|
+
const relativeDir = workspacePackage.relativeDir.replace(/\\/gu, "/");
|
|
843
|
+
const packageJson = workspacePackage.packageJson;
|
|
844
|
+
const packageName = String(packageJson.name ?? "");
|
|
845
|
+
if (!packageName) continue;
|
|
846
|
+
const packageEntry = packageEntries[relativeDir] ?? {};
|
|
847
|
+
if (packageEntry.name !== packageName) {
|
|
848
|
+
packageEntry.name = packageName;
|
|
849
|
+
changed = true;
|
|
850
|
+
}
|
|
851
|
+
if (typeof packageJson.version === "string" && packageEntry.version !== packageJson.version) {
|
|
852
|
+
packageEntry.version = packageJson.version;
|
|
853
|
+
changed = true;
|
|
854
|
+
}
|
|
855
|
+
for (const field of dependencyFields(packageJson)) {
|
|
856
|
+
const nextValue = packageJson[field];
|
|
857
|
+
if (nextValue && typeof nextValue === "object" && !Array.isArray(nextValue)) {
|
|
858
|
+
const normalizedValue = normalizeWorkspaceDependencySpecs(nextValue);
|
|
859
|
+
if (JSON.stringify(packageEntry[field] ?? {}) !== JSON.stringify(normalizedValue)) {
|
|
860
|
+
packageEntry[field] = normalizedValue;
|
|
861
|
+
changed = true;
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
packageEntries[relativeDir] = packageEntry;
|
|
866
|
+
const linkKey = `node_modules/${packageName}`;
|
|
867
|
+
const linkEntry = packageEntries[linkKey] ?? {};
|
|
868
|
+
if (linkEntry.resolved !== relativeDir) {
|
|
869
|
+
linkEntry.resolved = relativeDir;
|
|
870
|
+
changed = true;
|
|
871
|
+
}
|
|
872
|
+
if (linkEntry.link !== true) {
|
|
873
|
+
linkEntry.link = true;
|
|
874
|
+
changed = true;
|
|
875
|
+
}
|
|
876
|
+
packageEntries[linkKey] = linkEntry;
|
|
877
|
+
}
|
|
878
|
+
if (!changed) return false;
|
|
879
|
+
lockfile.packages = packageEntries;
|
|
880
|
+
writeJson(lockfilePath, lockfile);
|
|
881
|
+
emitProgress(options, node, "lockfile", "Synchronized root workspace lockfile metadata before validation.");
|
|
882
|
+
return true;
|
|
883
|
+
}
|
|
884
|
+
async function runGitDependencySmoke(node, options, reference) {
|
|
885
|
+
void node;
|
|
886
|
+
void options;
|
|
887
|
+
void reference;
|
|
634
888
|
}
|
|
635
889
|
async function runNpmInstallWithRetry(node, options, gitDependencyRefreshSpecs = []) {
|
|
636
890
|
if (shouldSkipNetworkInstall()) {
|
|
@@ -640,7 +894,7 @@ async function runNpmInstallWithRetry(node, options, gitDependencyRefreshSpecs =
|
|
|
640
894
|
let lastError = null;
|
|
641
895
|
const packageJson = node.packageJson ?? (existsSync(resolve(node.path, "package.json")) ? readJson(resolve(node.path, "package.json")) : null);
|
|
642
896
|
const rootWorkspaceInstall = node.path === options.root && Array.isArray(packageJson?.workspaces);
|
|
643
|
-
const installFlags = ["--package-lock-only", "--ignore-scripts"];
|
|
897
|
+
const installFlags = rootWorkspaceInstall ? ["--package-lock-only", "--ignore-scripts"] : node.branchMode === "project-save" ? ["--ignore-scripts"] : ["--package-lock-only", "--ignore-scripts"];
|
|
644
898
|
const args = rootWorkspaceInstall ? gitDependencyRefreshSpecs.length > 0 ? ["install", ...gitDependencyRefreshSpecs, ...installFlags, "--force"] : ["install", ...installFlags] : gitDependencyRefreshSpecs.length > 0 ? ["install", ...gitDependencyRefreshSpecs, ...installFlags, "--force", "--workspaces=false"] : ["install", ...installFlags, "--workspaces=false"];
|
|
645
899
|
for (let attempt = 1; attempt <= 5; attempt += 1) {
|
|
646
900
|
emitProgress(options, node, "install", `npm ${args.join(" ")} attempt ${attempt}/5.`);
|
|
@@ -652,12 +906,42 @@ async function runNpmInstallWithRetry(node, options, gitDependencyRefreshSpecs =
|
|
|
652
906
|
}
|
|
653
907
|
if (attempt < 5) {
|
|
654
908
|
emitProgress(options, node, "install", "npm install failed; retrying in 60 seconds.", "stderr");
|
|
655
|
-
|
|
909
|
+
await sleepMs(6e4);
|
|
656
910
|
}
|
|
657
911
|
}
|
|
658
912
|
throw new RepositorySaveError(`npm install failed after 5 attempts.
|
|
659
913
|
${lastError ?? ""}`);
|
|
660
914
|
}
|
|
915
|
+
async function runProjectVerificationInstallWithRetry(node, options) {
|
|
916
|
+
if (!hasNpmLockfile(node.path)) return;
|
|
917
|
+
if (shouldSkipNetworkInstall()) {
|
|
918
|
+
emitProgress(options, node, "install", "Skipped project verification dependency install because network install mode is disabled.");
|
|
919
|
+
return;
|
|
920
|
+
}
|
|
921
|
+
let lastError = null;
|
|
922
|
+
const packageJson = node.packageJson ?? (existsSync(resolve(node.path, "package.json")) ? readJson(resolve(node.path, "package.json")) : null);
|
|
923
|
+
const rootWorkspaceInstall = node.path === options.root && Array.isArray(packageJson?.workspaces);
|
|
924
|
+
if (rootWorkspaceInstall) {
|
|
925
|
+
emitProgress(options, node, "install", "Skipped root npm ci project verification install; lockfile dry-run and restored workspace links provide save-time dependency proof.");
|
|
926
|
+
return;
|
|
927
|
+
}
|
|
928
|
+
const args = rootWorkspaceInstall ? ["ci"] : ["ci", "--workspaces=false"];
|
|
929
|
+
for (let attempt = 1; attempt <= 5; attempt += 1) {
|
|
930
|
+
emitProgress(options, node, "install", `npm ${args.join(" ")} for project verification attempt ${attempt}/5.`);
|
|
931
|
+
try {
|
|
932
|
+
await runStreamingCommand(node, options, "install", "npm", args);
|
|
933
|
+
return;
|
|
934
|
+
} catch (error) {
|
|
935
|
+
lastError = error instanceof Error ? error.message : String(error);
|
|
936
|
+
}
|
|
937
|
+
if (attempt < 5) {
|
|
938
|
+
emitProgress(options, node, "install", "npm ci for verification failed; retrying in 60 seconds.", "stderr");
|
|
939
|
+
await sleepMs(6e4);
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
throw new RepositorySaveError(`Project verification dependency install failed after 5 attempts.
|
|
943
|
+
${lastError ?? ""}`);
|
|
944
|
+
}
|
|
661
945
|
function lockfileValidationCommand(node, options) {
|
|
662
946
|
const packageJson = node.packageJson ?? (existsSync(resolve(node.path, "package.json")) ? readJson(resolve(node.path, "package.json")) : null);
|
|
663
947
|
const rootWorkspaceInstall = node.path === options.root && Array.isArray(packageJson?.workspaces);
|
|
@@ -668,6 +952,7 @@ async function validateRepositoryLockfile(node, options) {
|
|
|
668
952
|
if (!hasNpmLockfile(node.path)) {
|
|
669
953
|
return { status: "skipped", command: null, issues: [], error: "no npm lockfile" };
|
|
670
954
|
}
|
|
955
|
+
syncRootWorkspaceLockfileMetadata(node, options);
|
|
671
956
|
const issues = collectDeploymentLockfileWorkspaceIssues(node.path).map((issue) => `${issue.filePath}: ${issue.packageName} ${issue.reason}`);
|
|
672
957
|
if (issues.length > 0) {
|
|
673
958
|
throw new RepositorySaveError([
|
|
@@ -713,38 +998,99 @@ async function validateRepositoryLockfile(node, options) {
|
|
|
713
998
|
function hasScript(node, scriptName) {
|
|
714
999
|
return typeof node.scripts[scriptName] === "string" && node.scripts[scriptName].length > 0;
|
|
715
1000
|
}
|
|
1001
|
+
function manifestVerifyCommand(node, key) {
|
|
1002
|
+
return node.manifestVerifyCommands[key] ?? null;
|
|
1003
|
+
}
|
|
1004
|
+
function hasAnyVerificationCommand(node) {
|
|
1005
|
+
return hasScript(node, "verify:action") || hasScript(node, "verify:local") || hasScript(node, "verify") || Boolean(manifestVerifyCommand(node, "local")) || Boolean(manifestVerifyCommand(node, "fast"));
|
|
1006
|
+
}
|
|
716
1007
|
async function runScript(node, options, scriptName) {
|
|
717
1008
|
await runStreamingCommand(node, options, "verify", "npm", ["run", scriptName]);
|
|
718
1009
|
}
|
|
1010
|
+
async function runManifestVerifyCommand(node, options, verifyMode, key) {
|
|
1011
|
+
const manifestCommand = manifestVerifyCommand(node, key);
|
|
1012
|
+
if (!manifestCommand) {
|
|
1013
|
+
throw new RepositorySaveError(`${node.name} is missing a ${key} verification command in treeseed.package.yaml.`);
|
|
1014
|
+
}
|
|
1015
|
+
const command = `${manifestCommand.command} ${manifestCommand.args.join(" ")}`;
|
|
1016
|
+
const cacheInput = {
|
|
1017
|
+
workspaceRoot: options.root,
|
|
1018
|
+
repoName: node.name,
|
|
1019
|
+
repoPath: node.path,
|
|
1020
|
+
command,
|
|
1021
|
+
verifyMode,
|
|
1022
|
+
env: process.env
|
|
1023
|
+
};
|
|
1024
|
+
const cached = readTreeseedVerificationCache(cacheInput);
|
|
1025
|
+
if (cached) {
|
|
1026
|
+
emitProgress(options, node, "verify", `[verify][cache] Reused ${node.name} ${manifestCommand.label} for ${cached.headSha.slice(0, 12)}.`);
|
|
1027
|
+
return { cached: true };
|
|
1028
|
+
}
|
|
1029
|
+
const started = Date.now();
|
|
1030
|
+
await runStreamingCommand(node, options, "verify", manifestCommand.command, manifestCommand.args, { cwd: manifestCommand.cwd });
|
|
1031
|
+
writeTreeseedVerificationCache(cacheInput, Date.now() - started);
|
|
1032
|
+
return { cached: false };
|
|
1033
|
+
}
|
|
1034
|
+
async function runCachedScript(node, options, verifyMode, scriptName) {
|
|
1035
|
+
const command = `npm run ${scriptName}`;
|
|
1036
|
+
const cacheInput = {
|
|
1037
|
+
workspaceRoot: options.root,
|
|
1038
|
+
repoName: node.name,
|
|
1039
|
+
repoPath: node.path,
|
|
1040
|
+
command,
|
|
1041
|
+
verifyMode,
|
|
1042
|
+
env: process.env
|
|
1043
|
+
};
|
|
1044
|
+
const cached = readTreeseedVerificationCache(cacheInput);
|
|
1045
|
+
if (cached) {
|
|
1046
|
+
emitProgress(options, node, "verify", `[verify][cache] Reused ${node.name} ${scriptName} for ${cached.headSha.slice(0, 12)}.`);
|
|
1047
|
+
return { cached: true };
|
|
1048
|
+
}
|
|
1049
|
+
const started = Date.now();
|
|
1050
|
+
await runScript(node, options, scriptName);
|
|
1051
|
+
writeTreeseedVerificationCache(cacheInput, Date.now() - started);
|
|
1052
|
+
return { cached: false };
|
|
1053
|
+
}
|
|
719
1054
|
async function runRepoVerification(node, options, verifyMode) {
|
|
720
1055
|
if (verifyMode === "skip") {
|
|
721
1056
|
emitProgress(options, node, "verify", "Skipped verification by request.");
|
|
722
1057
|
return { mode: verifyMode, status: "skipped", primary: null, fallbackUsed: false, error: null };
|
|
723
1058
|
}
|
|
724
|
-
if (node.kind !== "package") {
|
|
725
|
-
emitProgress(options, node, "verify", "Skipped
|
|
1059
|
+
if (node.kind !== "package" && !hasAnyVerificationCommand(node)) {
|
|
1060
|
+
emitProgress(options, node, "verify", "Skipped verification because project repository does not declare a Treeseed verify script.");
|
|
726
1061
|
return { mode: verifyMode, status: "skipped", primary: null, fallbackUsed: false, error: null };
|
|
727
1062
|
}
|
|
1063
|
+
await runProjectVerificationInstallWithRetry(node, options);
|
|
728
1064
|
if (verifyMode === "local-only") {
|
|
1065
|
+
if (hasScript(node, "verify:local")) {
|
|
1066
|
+
await runCachedScript(node, options, verifyMode, "verify:local");
|
|
1067
|
+
return { mode: verifyMode, status: "passed", primary: "verify:local", fallbackUsed: false, error: null };
|
|
1068
|
+
}
|
|
1069
|
+
if (manifestVerifyCommand(node, "local")) {
|
|
1070
|
+
await runManifestVerifyCommand(node, options, verifyMode, "local");
|
|
1071
|
+
return { mode: verifyMode, status: "passed", primary: "manifest:local", fallbackUsed: false, error: null };
|
|
1072
|
+
}
|
|
1073
|
+
if (manifestVerifyCommand(node, "fast")) {
|
|
1074
|
+
await runManifestVerifyCommand(node, options, verifyMode, "fast");
|
|
1075
|
+
return { mode: verifyMode, status: "passed", primary: "manifest:fast", fallbackUsed: false, error: null };
|
|
1076
|
+
}
|
|
729
1077
|
if (!hasScript(node, "verify:local")) {
|
|
730
|
-
throw new RepositorySaveError(
|
|
1078
|
+
throw new RepositorySaveError(`${node.kind === "package" ? "Package" : "Project"} ${node.name} is missing required verify:local script.`);
|
|
731
1079
|
}
|
|
732
|
-
await runScript(node, options, "verify:local");
|
|
733
|
-
return { mode: verifyMode, status: "passed", primary: "verify:local", fallbackUsed: false, error: null };
|
|
734
1080
|
}
|
|
735
|
-
if (!
|
|
736
|
-
throw new RepositorySaveError(
|
|
1081
|
+
if (!hasAnyVerificationCommand(node)) {
|
|
1082
|
+
throw new RepositorySaveError(`${node.kind === "package" ? "Package" : "Project"} ${node.name} is missing required verify:action, verify:local, or verify script.`);
|
|
737
1083
|
}
|
|
738
1084
|
if (hasScript(node, "verify:action")) {
|
|
739
1085
|
try {
|
|
740
|
-
await
|
|
1086
|
+
await runCachedScript(node, options, verifyMode, "verify:action");
|
|
741
1087
|
return { mode: verifyMode, status: "passed", primary: "verify:action", fallbackUsed: false, error: null };
|
|
742
1088
|
} catch (error) {
|
|
743
1089
|
if (!hasScript(node, "verify:local")) {
|
|
744
1090
|
throw error;
|
|
745
1091
|
}
|
|
746
1092
|
emitProgress(options, node, "verify", "verify:action failed; falling back to verify:local.", "stderr");
|
|
747
|
-
await
|
|
1093
|
+
await runCachedScript(node, options, verifyMode, "verify:local");
|
|
748
1094
|
return {
|
|
749
1095
|
mode: verifyMode,
|
|
750
1096
|
status: "passed",
|
|
@@ -754,7 +1100,19 @@ async function runRepoVerification(node, options, verifyMode) {
|
|
|
754
1100
|
};
|
|
755
1101
|
}
|
|
756
1102
|
}
|
|
757
|
-
|
|
1103
|
+
if (hasScript(node, "verify:local")) {
|
|
1104
|
+
await runCachedScript(node, options, verifyMode, "verify:local");
|
|
1105
|
+
return { mode: verifyMode, status: "passed", primary: "verify:local", fallbackUsed: true, error: null };
|
|
1106
|
+
}
|
|
1107
|
+
if (manifestVerifyCommand(node, "local")) {
|
|
1108
|
+
await runManifestVerifyCommand(node, options, verifyMode, "local");
|
|
1109
|
+
return { mode: verifyMode, status: "passed", primary: "manifest:local", fallbackUsed: true, error: null };
|
|
1110
|
+
}
|
|
1111
|
+
if (manifestVerifyCommand(node, "fast")) {
|
|
1112
|
+
await runManifestVerifyCommand(node, options, verifyMode, "fast");
|
|
1113
|
+
return { mode: verifyMode, status: "passed", primary: "manifest:fast", fallbackUsed: true, error: null };
|
|
1114
|
+
}
|
|
1115
|
+
await runCachedScript(node, options, verifyMode, "verify");
|
|
758
1116
|
return { mode: verifyMode, status: "passed", primary: "verify:local", fallbackUsed: true, error: null };
|
|
759
1117
|
}
|
|
760
1118
|
function pullRebaseFromOrigin(node, options, branch) {
|
|
@@ -800,9 +1158,57 @@ function pushCurrentBranch(node, options, branch, tagName) {
|
|
|
800
1158
|
combinedBranchAndTagPush: pushedTag
|
|
801
1159
|
};
|
|
802
1160
|
}
|
|
1161
|
+
async function finishRepositorySavePublish(node, options, state, report, input) {
|
|
1162
|
+
const reference = input.reference ?? null;
|
|
1163
|
+
const tagName = input.tagName ?? reference?.tagName ?? null;
|
|
1164
|
+
const shouldDeferPush = options.deferPushUntilVerified === true && node.id === ".";
|
|
1165
|
+
if (shouldDeferPush) {
|
|
1166
|
+
state.deferredPushes.push({
|
|
1167
|
+
node,
|
|
1168
|
+
report,
|
|
1169
|
+
branch: input.branch,
|
|
1170
|
+
tagName,
|
|
1171
|
+
rebase: input.rebase,
|
|
1172
|
+
reference
|
|
1173
|
+
});
|
|
1174
|
+
report.pushed = false;
|
|
1175
|
+
report.publishWait = {
|
|
1176
|
+
...input.rebase,
|
|
1177
|
+
deferredPush: true
|
|
1178
|
+
};
|
|
1179
|
+
return;
|
|
1180
|
+
}
|
|
1181
|
+
const push = pushCurrentBranch(node, options, input.branch, tagName);
|
|
1182
|
+
if (reference) {
|
|
1183
|
+
await runGitDependencySmoke(node, options, reference);
|
|
1184
|
+
report.dependencySpec = reference.spec;
|
|
1185
|
+
}
|
|
1186
|
+
report.pushed = push.pushed;
|
|
1187
|
+
report.publishWait = {
|
|
1188
|
+
...input.rebase,
|
|
1189
|
+
...push
|
|
1190
|
+
};
|
|
1191
|
+
}
|
|
1192
|
+
async function publishDeferredRepositoryPushes(options, state) {
|
|
1193
|
+
if (state.deferredPushes.length === 0) return;
|
|
1194
|
+
for (const deferred of state.deferredPushes) {
|
|
1195
|
+
const push = pushCurrentBranch(deferred.node, options, deferred.branch, deferred.tagName);
|
|
1196
|
+
if (deferred.reference) {
|
|
1197
|
+
await runGitDependencySmoke(deferred.node, options, deferred.reference);
|
|
1198
|
+
deferred.report.dependencySpec = deferred.reference.spec;
|
|
1199
|
+
}
|
|
1200
|
+
deferred.report.pushed = push.pushed;
|
|
1201
|
+
deferred.report.publishWait = {
|
|
1202
|
+
...deferred.rebase,
|
|
1203
|
+
...push,
|
|
1204
|
+
deferredPush: true
|
|
1205
|
+
};
|
|
1206
|
+
}
|
|
1207
|
+
state.deferredPushes = [];
|
|
1208
|
+
}
|
|
803
1209
|
function tagExists(repoDir, tagName) {
|
|
804
1210
|
try {
|
|
805
|
-
|
|
1211
|
+
runGit(["rev-parse", "--verify", `refs/tags/${tagName}`], { cwd: repoDir, capture: true });
|
|
806
1212
|
return true;
|
|
807
1213
|
} catch {
|
|
808
1214
|
return false;
|
|
@@ -810,14 +1216,14 @@ function tagExists(repoDir, tagName) {
|
|
|
810
1216
|
}
|
|
811
1217
|
function localTagCommit(repoDir, tagName) {
|
|
812
1218
|
try {
|
|
813
|
-
return
|
|
1219
|
+
return runGit(["rev-list", "-n", "1", tagName], { cwd: repoDir, capture: true }).trim();
|
|
814
1220
|
} catch {
|
|
815
1221
|
return null;
|
|
816
1222
|
}
|
|
817
1223
|
}
|
|
818
1224
|
function remoteTagCommit(repoDir, tagName) {
|
|
819
1225
|
try {
|
|
820
|
-
const output =
|
|
1226
|
+
const output = runGit(["ls-remote", "--tags", "origin", `refs/tags/${tagName}*`], { cwd: repoDir, capture: true });
|
|
821
1227
|
const lines = output.split(/\r?\n/u).map((line) => line.trim()).filter(Boolean);
|
|
822
1228
|
const dereferenced = lines.find((line) => line.endsWith(`refs/tags/${tagName}^{}`));
|
|
823
1229
|
const exact = lines.find((line) => line.endsWith(`refs/tags/${tagName}`));
|
|
@@ -829,7 +1235,7 @@ function remoteTagCommit(repoDir, tagName) {
|
|
|
829
1235
|
}
|
|
830
1236
|
function localTagMessage(repoDir, tagName) {
|
|
831
1237
|
try {
|
|
832
|
-
return
|
|
1238
|
+
return runGit(["tag", "-l", tagName, "--format=%(contents)"], { cwd: repoDir, capture: true }).trim();
|
|
833
1239
|
} catch {
|
|
834
1240
|
return null;
|
|
835
1241
|
}
|
|
@@ -870,13 +1276,9 @@ function assertTagStateMatchesHead(node, tagName, state, head) {
|
|
|
870
1276
|
}
|
|
871
1277
|
}
|
|
872
1278
|
function createPackageTagMessage(node, tagName, branch, workflowRunId) {
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
branch,
|
|
877
|
-
commitSha: headCommit(node.path),
|
|
878
|
-
workflowRunId
|
|
879
|
-
}) : `release: ${tagName}`;
|
|
1279
|
+
void branch;
|
|
1280
|
+
void workflowRunId;
|
|
1281
|
+
return `release: ${tagName}`;
|
|
880
1282
|
}
|
|
881
1283
|
function ensureRemoteAccessBeforeVerification(node, options, state) {
|
|
882
1284
|
if (shouldSkipRemoteAccessPreflight()) return;
|
|
@@ -906,12 +1308,6 @@ function ensureRemoteAccessBeforeVerification(node, options, state) {
|
|
|
906
1308
|
function shouldSkipRemoteAccessPreflight() {
|
|
907
1309
|
return process.env.TREESEED_SAVE_REMOTE_PREFLIGHT === "skip";
|
|
908
1310
|
}
|
|
909
|
-
function localTreeseedTagWasCreatedByThisRun(node, tagName, workflowRunId) {
|
|
910
|
-
const message = localTagMessage(node.path, tagName);
|
|
911
|
-
if (!message?.includes("treeseed-dev-tag: true")) return false;
|
|
912
|
-
if (!workflowRunId) return true;
|
|
913
|
-
return message.includes(`workflowRunId: ${workflowRunId}`);
|
|
914
|
-
}
|
|
915
1311
|
function ensurePackageTagReady(node, options, tagName, branch, workflowRunId) {
|
|
916
1312
|
let message = null;
|
|
917
1313
|
ensureWritableRemote(node, options);
|
|
@@ -936,7 +1332,7 @@ function ensurePackageTagReady(node, options, tagName, branch, workflowRunId) {
|
|
|
936
1332
|
}
|
|
937
1333
|
function treeCommitForPath(repoDir, ref, path) {
|
|
938
1334
|
try {
|
|
939
|
-
const output =
|
|
1335
|
+
const output = runGit(["ls-tree", ref, "--", path], { cwd: repoDir, capture: true }).trim();
|
|
940
1336
|
const match = output.match(/^\d+\s+commit\s+([0-9a-f]{40})\t/u);
|
|
941
1337
|
return match?.[1] ?? null;
|
|
942
1338
|
} catch {
|
|
@@ -950,7 +1346,7 @@ function collectSubmodulePointerChanges(node, finalizedCommits) {
|
|
|
950
1346
|
if (!childRelativePath) continue;
|
|
951
1347
|
const childPath = resolve(node.path, childRelativePath);
|
|
952
1348
|
if (!existsSync(childPath) || !isGitRepo(childPath)) continue;
|
|
953
|
-
const status =
|
|
1349
|
+
const status = runGit(["status", "--porcelain", "--", childRelativePath], { cwd: node.path, capture: true });
|
|
954
1350
|
const oldSha = treeCommitForPath(node.path, "HEAD", childRelativePath);
|
|
955
1351
|
const newSha = finalizedCommit || headCommit(childPath);
|
|
956
1352
|
if (status.trim().length > 0 || oldSha && newSha && oldSha !== newSha) {
|
|
@@ -1007,7 +1403,7 @@ function refreshRepositoryNodePackageMetadata(node) {
|
|
|
1007
1403
|
node.packageJson = packageJson;
|
|
1008
1404
|
node.scripts = packageScripts(packageJson);
|
|
1009
1405
|
node.remoteUrl = originRemoteUrlSafe(node.path);
|
|
1010
|
-
if (node.kind === "package") {
|
|
1406
|
+
if (node.kind === "package" && packageJson) {
|
|
1011
1407
|
node.name = repoDisplayName(node.path, packageJson);
|
|
1012
1408
|
}
|
|
1013
1409
|
}
|
|
@@ -1017,7 +1413,8 @@ function finalizePackageReference(node, version, options) {
|
|
|
1017
1413
|
version,
|
|
1018
1414
|
branchMode: node.branchMode === "package-release-main" ? "package-release-main" : "package-dev-save",
|
|
1019
1415
|
remoteUrl: node.remoteUrl,
|
|
1020
|
-
|
|
1416
|
+
commitSha: headCommit(node.path),
|
|
1417
|
+
devDependencyReferenceMode: options.devDependencyReferenceMode ?? "git-commit",
|
|
1021
1418
|
gitDependencyProtocol: options.gitDependencyProtocol ?? "preserve-origin"
|
|
1022
1419
|
});
|
|
1023
1420
|
node.plannedDependencySpec = reference.spec;
|
|
@@ -1029,21 +1426,25 @@ async function finalizeCleanPackageVersion(node, options, state, report, branch)
|
|
|
1029
1426
|
return false;
|
|
1030
1427
|
}
|
|
1031
1428
|
const head = headCommit(node.path);
|
|
1032
|
-
const
|
|
1033
|
-
|
|
1429
|
+
const reference = finalizePackageReference(node, version, options);
|
|
1430
|
+
const currentTagState = reference.tagName ? tagState(node.path, reference.tagName) : null;
|
|
1431
|
+
if (reference.tagName && currentTagState) {
|
|
1432
|
+
assertTagStateMatchesHead(node, reference.tagName, currentTagState, head);
|
|
1433
|
+
}
|
|
1034
1434
|
const remoteBranchExists2 = remoteBranchExistsSafe(node.path, branch);
|
|
1035
|
-
const
|
|
1435
|
+
const remoteBranchCommit = remoteBranchCommitSafe(node.path, branch);
|
|
1436
|
+
const finalizedRemotely = remoteBranchExists2 && remoteBranchCommit === head && (!reference.tagName || currentTagState?.localCommit === head && currentTagState?.remoteCommit === head);
|
|
1036
1437
|
report.version = version;
|
|
1037
|
-
report.tagName =
|
|
1438
|
+
report.tagName = reference.tagName;
|
|
1038
1439
|
report.commitSha = head;
|
|
1039
|
-
report.dependencySpec =
|
|
1440
|
+
report.dependencySpec = reference.spec;
|
|
1040
1441
|
state.finalizedVersions.set(node.name, version);
|
|
1041
|
-
state.finalizedReferences.set(node.name,
|
|
1442
|
+
state.finalizedReferences.set(node.name, reference);
|
|
1042
1443
|
state.finalizedCommits.set(node.relativePath, head);
|
|
1043
1444
|
if (finalizedRemotely) {
|
|
1044
1445
|
report.pushed = true;
|
|
1045
1446
|
report.skippedReason = "already-finalized";
|
|
1046
|
-
report.publishWait = { recoveredPartialSave: true, remoteBranchExisted: true, tagAlreadyPushed:
|
|
1447
|
+
report.publishWait = { recoveredPartialSave: true, remoteBranchExisted: true, tagAlreadyPushed: Boolean(reference.tagName) };
|
|
1047
1448
|
emitProgress(options, node, "finalize", `Using existing finalized package version ${version}.`);
|
|
1048
1449
|
return true;
|
|
1049
1450
|
}
|
|
@@ -1053,36 +1454,24 @@ async function finalizeCleanPackageVersion(node, options, state, report, branch)
|
|
|
1053
1454
|
report.lockfileValidation = await validateRepositoryLockfile(node, options);
|
|
1054
1455
|
}
|
|
1055
1456
|
const rebase = pullRebaseFromOrigin(node, options, branch);
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
primary: null,
|
|
1062
|
-
fallbackUsed: false,
|
|
1063
|
-
error: "verified-before-interruption"
|
|
1064
|
-
};
|
|
1065
|
-
report.verified = true;
|
|
1066
|
-
} else {
|
|
1067
|
-
ensureRemoteAccessBeforeVerification(node, options, state);
|
|
1068
|
-
report.verification = await runRepoVerification(node, options, options.verifyMode ?? "action-first");
|
|
1069
|
-
report.verified = report.verification.status === "passed";
|
|
1070
|
-
}
|
|
1071
|
-
const tagMessage = ensurePackageTagReady(node, options, version, branch, options.workflowRunId);
|
|
1072
|
-
report.devTagMetadata = tagMessage?.includes("treeseed-dev-tag: true") ? tagMessage : null;
|
|
1073
|
-
const reference = finalizePackageReference(node, version, options);
|
|
1074
|
-
const push = pushCurrentBranch(node, options, branch, version);
|
|
1075
|
-
await runGitDependencySmoke(node, options, reference);
|
|
1457
|
+
ensureRemoteAccessBeforeVerification(node, options, state);
|
|
1458
|
+
report.verification = await runRepoVerification(node, options, options.verifyMode ?? "action-first");
|
|
1459
|
+
report.verified = report.verification.status === "passed";
|
|
1460
|
+
const tagMessage = reference.tagName ? ensurePackageTagReady(node, options, reference.tagName, branch, options.workflowRunId) : null;
|
|
1461
|
+
void tagMessage;
|
|
1076
1462
|
report.dependencySpec = reference.spec;
|
|
1077
|
-
report.pushed = push.pushed;
|
|
1078
1463
|
report.skippedReason = "finalized-partial-save";
|
|
1079
1464
|
report.commitSha = headCommit(node.path);
|
|
1080
1465
|
state.finalizedCommits.set(node.relativePath, report.commitSha);
|
|
1081
|
-
report
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1466
|
+
await finishRepositorySavePublish(node, options, state, report, {
|
|
1467
|
+
branch,
|
|
1468
|
+
rebase: {
|
|
1469
|
+
...rebase,
|
|
1470
|
+
recoveredPartialSave: true
|
|
1471
|
+
},
|
|
1472
|
+
reference,
|
|
1473
|
+
tagName: reference.tagName
|
|
1474
|
+
});
|
|
1086
1475
|
return true;
|
|
1087
1476
|
}
|
|
1088
1477
|
function branchModeLabel(branchMode) {
|
|
@@ -1115,9 +1504,9 @@ function repoPlanCommands(node, options, plannedVersion, plannedDependencySpec,
|
|
|
1115
1504
|
const rootWorkspaceInstall = node.path === options.root && Array.isArray(packageJson?.workspaces);
|
|
1116
1505
|
if (node.kind === "package" && plannedVersion) {
|
|
1117
1506
|
commands.push(`update package.json version to ${plannedVersion}`);
|
|
1118
|
-
commands.push("npm install --workspaces=false # explicitly refresh changed git
|
|
1119
|
-
} else if (node.kind === "project" && dependencyUpdates.length > 0 && hasNpmLockfile(node.path)) {
|
|
1120
|
-
commands.push(rootWorkspaceInstall ? "npm install # refresh root workspace lockfile
|
|
1507
|
+
commands.push("npm install --workspaces=false # explicitly refresh changed git commit dependencies with --force; retry up to 5 times with 60s delay");
|
|
1508
|
+
} else if (node.kind === "project" && (dependencyUpdates.length > 0 || rootWorkspaceInstall && node.submoduleDependencies.length > 0) && hasNpmLockfile(node.path)) {
|
|
1509
|
+
commands.push(rootWorkspaceInstall ? "npm install --package-lock-only --ignore-scripts # refresh root workspace lockfile without installing git dependencies" : "npm install --workspaces=false # refresh project lockfile after internal dependency updates");
|
|
1121
1510
|
}
|
|
1122
1511
|
if (hasNpmLockfile(node.path) && (node.kind === "project" || plannedVersion || dependencyUpdates.length > 0 || node.submoduleDependencies.length > 0)) {
|
|
1123
1512
|
commands.push(rootWorkspaceInstall ? "npm ci --ignore-scripts --dry-run # validate root manifest, workspaces, and lockfile before commit" : "npm ci --ignore-scripts --dry-run --workspaces=false # validate deployment lockfile before commit");
|
|
@@ -1128,24 +1517,39 @@ function repoPlanCommands(node, options, plannedVersion, plannedDependencySpec,
|
|
|
1128
1517
|
commands.push(
|
|
1129
1518
|
remoteExists ? `git pull --rebase --recurse-submodules=no origin ${branch}` : `skip pull --rebase # origin/${branch} does not exist yet`
|
|
1130
1519
|
);
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1520
|
+
const verifyMode = options.verifyMode ?? "action-first";
|
|
1521
|
+
if (verifyMode === "skip") {
|
|
1522
|
+
commands.push(node.kind === "package" ? "skip package verification" : "skip project verification");
|
|
1523
|
+
} else if (hasScript(node, "verify:action") || hasScript(node, "verify:local") || hasScript(node, "verify")) {
|
|
1524
|
+
if (verifyMode === "local-only") {
|
|
1136
1525
|
commands.push("npm run verify:local");
|
|
1137
|
-
} else {
|
|
1526
|
+
} else if (hasScript(node, "verify:action")) {
|
|
1138
1527
|
commands.push("npm run verify:action # fallback to npm run verify:local on failure");
|
|
1528
|
+
} else if (hasScript(node, "verify:local")) {
|
|
1529
|
+
commands.push("npm run verify:local");
|
|
1530
|
+
} else {
|
|
1531
|
+
commands.push("npm run verify");
|
|
1139
1532
|
}
|
|
1140
|
-
|
|
1141
|
-
|
|
1533
|
+
} else if (manifestVerifyCommand(node, "local") || manifestVerifyCommand(node, "fast")) {
|
|
1534
|
+
const command = verifyMode === "local-only" ? manifestVerifyCommand(node, "local") ?? manifestVerifyCommand(node, "fast") : manifestVerifyCommand(node, "local") ?? manifestVerifyCommand(node, "fast");
|
|
1535
|
+
if (command) commands.push(`${command.command} ${command.args.join(" ")} # treeseed.package.yaml verification`);
|
|
1536
|
+
} else if (node.kind !== "package") {
|
|
1537
|
+
commands.push("skip verification # project repository has no Treeseed verify script");
|
|
1538
|
+
}
|
|
1539
|
+
if (node.kind === "package") {
|
|
1540
|
+
const plansTag = plannedVersion && node.branchMode === "package-release-main";
|
|
1541
|
+
if (plannedVersion && plansTag) {
|
|
1542
|
+
commands.push(`git tag -a ${plannedVersion} -m <release>`);
|
|
1142
1543
|
commands.push(remoteExists ? `git push origin ${branch} ${plannedVersion}` : `git push -u origin ${branch} ${plannedVersion}`);
|
|
1544
|
+
} else if (plannedVersion) {
|
|
1545
|
+
commands.push(remoteExists ? `git push origin ${branch}` : `git push -u origin ${branch}`);
|
|
1143
1546
|
if (plannedDependencySpec && node.branchMode === "package-dev-save") {
|
|
1144
|
-
commands.push(`
|
|
1547
|
+
commands.push(`npm install ${node.name}@${plannedDependencySpec} --package-lock-only --ignore-scripts --force # validate dependency commit reachability`);
|
|
1145
1548
|
}
|
|
1549
|
+
} else {
|
|
1550
|
+
commands.push(remoteExists ? `git push origin ${branch}` : `git push -u origin ${branch}`);
|
|
1146
1551
|
}
|
|
1147
1552
|
} else {
|
|
1148
|
-
commands.push("skip package verification # project repository");
|
|
1149
1553
|
commands.push(remoteExists ? `git push origin ${branch}` : `git push -u origin ${branch}`);
|
|
1150
1554
|
}
|
|
1151
1555
|
return commands;
|
|
@@ -1173,7 +1577,7 @@ function planRepositorySave(options) {
|
|
|
1173
1577
|
return dependency?.dirty || Boolean(dependency?.plannedVersion);
|
|
1174
1578
|
});
|
|
1175
1579
|
const dirty = hasMeaningfulChanges(node.path);
|
|
1176
|
-
const packageNeedsVersion = node
|
|
1580
|
+
const packageNeedsVersion = canManagePackageJsonVersion(node) && (dirty || dependencyChanged || submoduleChanged);
|
|
1177
1581
|
const currentVersion = typeof node.packageJson?.version === "string" ? node.packageJson.version : null;
|
|
1178
1582
|
const plannedVersion = packageNeedsVersion ? selectPackageVersion(node, options).version : null;
|
|
1179
1583
|
let plannedDependencySpec = null;
|
|
@@ -1183,7 +1587,8 @@ function planRepositorySave(options) {
|
|
|
1183
1587
|
version: plannedVersion,
|
|
1184
1588
|
branchMode: node.branchMode === "package-release-main" ? "package-release-main" : "package-dev-save",
|
|
1185
1589
|
remoteUrl: node.remoteUrl,
|
|
1186
|
-
|
|
1590
|
+
commitSha: headCommitOrPlanPlaceholder(node.path),
|
|
1591
|
+
devDependencyReferenceMode: options.devDependencyReferenceMode ?? "git-commit",
|
|
1187
1592
|
gitDependencyProtocol: options.gitDependencyProtocol ?? "preserve-origin"
|
|
1188
1593
|
});
|
|
1189
1594
|
plannedDependencySpec = reference.spec;
|
|
@@ -1195,7 +1600,7 @@ function planRepositorySave(options) {
|
|
|
1195
1600
|
const notes = [
|
|
1196
1601
|
`${branchModeLabel(node.branchMode)} on top-level ${options.branch}`,
|
|
1197
1602
|
...current && current !== branch ? [`current branch ${current} will be switched to ${branch}`] : [],
|
|
1198
|
-
...node.kind === "package" && plannedVersion?.includes("-dev.") ? ["
|
|
1603
|
+
...node.kind === "package" && plannedVersion?.includes("-dev.") ? ["development and staging dependency refs use the package commit SHA; no Git tag is created"] : []
|
|
1199
1604
|
];
|
|
1200
1605
|
const repoPlan = {
|
|
1201
1606
|
id: node.id,
|
|
@@ -1212,7 +1617,7 @@ function planRepositorySave(options) {
|
|
|
1212
1617
|
submoduleDependencies: node.submoduleDependencies,
|
|
1213
1618
|
currentVersion,
|
|
1214
1619
|
plannedVersion,
|
|
1215
|
-
plannedTag:
|
|
1620
|
+
plannedTag: plannedReferences.get(node.name)?.tagName ?? null,
|
|
1216
1621
|
plannedDependencySpec,
|
|
1217
1622
|
remoteUrl: node.remoteUrl,
|
|
1218
1623
|
commands: repoPlanCommands(node, options, plannedVersion, plannedDependencySpec, dependencyUpdates),
|
|
@@ -1240,7 +1645,7 @@ function planRepositorySave(options) {
|
|
|
1240
1645
|
mode,
|
|
1241
1646
|
branch: options.branch,
|
|
1242
1647
|
scope,
|
|
1243
|
-
devDependencyReferenceMode: options.devDependencyReferenceMode ?? "git-
|
|
1648
|
+
devDependencyReferenceMode: options.devDependencyReferenceMode ?? "git-commit",
|
|
1244
1649
|
gitDependencyProtocol: options.gitDependencyProtocol ?? "preserve-origin",
|
|
1245
1650
|
verifyMode: options.verifyMode ?? "action-first",
|
|
1246
1651
|
commitMessageMode: options.commitMessageMode ?? "auto",
|
|
@@ -1269,6 +1674,7 @@ async function refreshAndValidateRootWorkspaceLockfileForSave(options) {
|
|
|
1269
1674
|
packageJsonPath: packageJson ? packageJsonPath : null,
|
|
1270
1675
|
packageJson,
|
|
1271
1676
|
scripts: packageScripts(packageJson),
|
|
1677
|
+
manifestVerifyCommands: emptyManifestVerifyCommands(),
|
|
1272
1678
|
remoteUrl: originRemoteUrlSafe(repoDir),
|
|
1273
1679
|
dependencies: [],
|
|
1274
1680
|
dependents: [],
|
|
@@ -1297,13 +1703,15 @@ async function saveOneRepository(node, options, state) {
|
|
|
1297
1703
|
report.branch = node.branch;
|
|
1298
1704
|
refreshRepositoryNodePackageMetadata(node);
|
|
1299
1705
|
ensureWritableRemote(node, options);
|
|
1300
|
-
const dependencyUpdates = updateDependencyReferences(node, state.finalizedReferences);
|
|
1706
|
+
const dependencyUpdates = isRootWorkspaceRepository(node, options) ? [] : updateDependencyReferences(node, state.finalizedReferences);
|
|
1301
1707
|
const dependencyChanged = dependencyUpdates.length > 0;
|
|
1302
|
-
const
|
|
1708
|
+
const gitDependencyRefreshReferences = dependencyUpdates.map((update) => state.finalizedReferences.get(update.packageName)).filter((reference) => Boolean(reference) && reference.mode === "dev-git-commit");
|
|
1709
|
+
const lockfileGitDependenciesSynced = syncDirectGitDependencyLockfileEntries(node, options, gitDependencyRefreshReferences);
|
|
1710
|
+
const gitDependencyRefreshSpecs = lockfileGitDependenciesSynced ? [] : gitDependencyRefreshReferences.map((reference) => `${reference.packageName}@${reference.installSpec ?? reference.spec}`);
|
|
1303
1711
|
const submodulePointers = collectSubmodulePointerChanges(node, state.finalizedCommits);
|
|
1304
1712
|
const submodulesChanged = submodulePointers.length > 0;
|
|
1305
1713
|
const packageHasMeaningfulChanges = hasMeaningfulChanges(node.path);
|
|
1306
|
-
const packageNeedsVersion = node
|
|
1714
|
+
const packageNeedsVersion = canManagePackageJsonVersion(node) && (packageHasMeaningfulChanges || dependencyChanged || submodulesChanged || packageVersionTagConflictsWithHead(node, options));
|
|
1307
1715
|
let plannedVersion = null;
|
|
1308
1716
|
if (packageNeedsVersion) {
|
|
1309
1717
|
const selection = selectPackageVersion(node, options);
|
|
@@ -1317,18 +1725,18 @@ async function saveOneRepository(node, options, state) {
|
|
|
1317
1725
|
applyPackageVersion(node, plannedVersion);
|
|
1318
1726
|
}
|
|
1319
1727
|
node.plannedVersion = plannedVersion;
|
|
1320
|
-
node.plannedTag = plannedVersion;
|
|
1321
1728
|
report.version = plannedVersion;
|
|
1322
|
-
report.tagName = plannedVersion;
|
|
1323
1729
|
if (!selection.reused) {
|
|
1324
1730
|
emitProgress(options, node, "version", `Planned ${plannedVersion}.`);
|
|
1325
1731
|
}
|
|
1326
1732
|
const reference = finalizePackageReference(node, plannedVersion, options);
|
|
1733
|
+
node.plannedTag = reference.tagName;
|
|
1734
|
+
report.tagName = reference.tagName;
|
|
1327
1735
|
report.dependencySpec = reference.spec;
|
|
1328
1736
|
report.install = await runNpmInstallWithRetry(node, options, gitDependencyRefreshSpecs);
|
|
1329
1737
|
} else if (node.kind === "package") {
|
|
1330
1738
|
report.version = String(node.packageJson?.version ?? report.version ?? "");
|
|
1331
|
-
} else if (node.kind === "project" && dependencyChanged && hasNpmLockfile(node.path)) {
|
|
1739
|
+
} else if (node.kind === "project" && (dependencyChanged || node.path === options.root && submodulesChanged) && hasNpmLockfile(node.path)) {
|
|
1332
1740
|
report.install = await runNpmInstallWithRetry(node, options, gitDependencyRefreshSpecs);
|
|
1333
1741
|
}
|
|
1334
1742
|
if (hasNpmLockfile(node.path) && (node.kind === "project" || packageNeedsVersion || dependencyChanged || submodulesChanged)) {
|
|
@@ -1351,14 +1759,9 @@ async function saveOneRepository(node, options, state) {
|
|
|
1351
1759
|
return report;
|
|
1352
1760
|
}
|
|
1353
1761
|
}
|
|
1354
|
-
if (node.
|
|
1762
|
+
if (node.kind === "project" || node.kind === "package" && !canManagePackageJsonVersion(node)) {
|
|
1355
1763
|
const rebase2 = pullRebaseFromOrigin(node, options, branch);
|
|
1356
|
-
|
|
1357
|
-
report.pushed = push.pushed;
|
|
1358
|
-
report.publishWait = {
|
|
1359
|
-
...rebase2,
|
|
1360
|
-
...push
|
|
1361
|
-
};
|
|
1764
|
+
await finishRepositorySavePublish(node, options, state, report, { branch, rebase: rebase2 });
|
|
1362
1765
|
report.commitSha = headCommit(node.path);
|
|
1363
1766
|
}
|
|
1364
1767
|
state.finalizedCommits.set(node.relativePath, report.commitSha);
|
|
@@ -1376,14 +1779,9 @@ async function saveOneRepository(node, options, state) {
|
|
|
1376
1779
|
return report;
|
|
1377
1780
|
}
|
|
1378
1781
|
}
|
|
1379
|
-
if (node.
|
|
1782
|
+
if (node.kind === "project" || node.kind === "package" && !canManagePackageJsonVersion(node)) {
|
|
1380
1783
|
const rebase2 = pullRebaseFromOrigin(node, options, branch);
|
|
1381
|
-
|
|
1382
|
-
report.pushed = push.pushed;
|
|
1383
|
-
report.publishWait = {
|
|
1384
|
-
...rebase2,
|
|
1385
|
-
...push
|
|
1386
|
-
};
|
|
1784
|
+
await finishRepositorySavePublish(node, options, state, report, { branch, rebase: rebase2 });
|
|
1387
1785
|
report.commitSha = headCommit(node.path);
|
|
1388
1786
|
}
|
|
1389
1787
|
state.finalizedCommits.set(node.relativePath, report.commitSha);
|
|
@@ -1421,14 +1819,9 @@ async function saveOneRepository(node, options, state) {
|
|
|
1421
1819
|
return report;
|
|
1422
1820
|
}
|
|
1423
1821
|
}
|
|
1424
|
-
if (node.
|
|
1822
|
+
if (node.kind === "project" || node.kind === "package" && !canManagePackageJsonVersion(node)) {
|
|
1425
1823
|
const rebase2 = pullRebaseFromOrigin(node, options, branch);
|
|
1426
|
-
|
|
1427
|
-
report.pushed = push.pushed;
|
|
1428
|
-
report.publishWait = {
|
|
1429
|
-
...rebase2,
|
|
1430
|
-
...push
|
|
1431
|
-
};
|
|
1824
|
+
await finishRepositorySavePublish(node, options, state, report, { branch, rebase: rebase2 });
|
|
1432
1825
|
report.commitSha = headCommit(node.path);
|
|
1433
1826
|
}
|
|
1434
1827
|
state.finalizedCommits.set(node.relativePath, report.commitSha);
|
|
@@ -1437,35 +1830,31 @@ async function saveOneRepository(node, options, state) {
|
|
|
1437
1830
|
report.committed = true;
|
|
1438
1831
|
const rebase = pullRebaseFromOrigin(node, options, branch);
|
|
1439
1832
|
const verifyMode = options.verifyMode ?? "action-first";
|
|
1833
|
+
if (node.kind === "project" && node.path === options.root && Array.isArray(node.packageJson?.workspaces)) {
|
|
1834
|
+
const linkReport = ensureLocalWorkspaceLinks(options.root);
|
|
1835
|
+
const restoredLinks = Array.isArray(linkReport.created) ? linkReport.created.length : 0;
|
|
1836
|
+
if (restoredLinks > 0) {
|
|
1837
|
+
emitProgress(options, node, "install", `Restored ${restoredLinks} local workspace package link${restoredLinks === 1 ? "" : "s"} before project verification.`);
|
|
1838
|
+
}
|
|
1839
|
+
}
|
|
1440
1840
|
if (node.kind === "package") {
|
|
1441
1841
|
ensureRemoteAccessBeforeVerification(node, options, state);
|
|
1442
1842
|
}
|
|
1443
1843
|
report.verification = await runRepoVerification(node, options, verifyMode);
|
|
1444
1844
|
report.verified = report.verification.status === "passed";
|
|
1445
|
-
if (node
|
|
1845
|
+
if (canManagePackageJsonVersion(node)) {
|
|
1446
1846
|
const version = plannedVersion ?? String(readJson(resolve(node.path, "package.json")).version ?? report.version ?? "");
|
|
1447
|
-
const tagMessage = ensurePackageTagReady(node, options, version, branch, options.workflowRunId);
|
|
1448
|
-
report.tagName = version;
|
|
1449
|
-
report.version = version;
|
|
1450
|
-
report.devTagMetadata = tagMessage?.includes("treeseed-dev-tag: true") ? tagMessage : null;
|
|
1451
1847
|
const reference = finalizePackageReference(node, version, options);
|
|
1452
|
-
const
|
|
1453
|
-
|
|
1848
|
+
const tagMessage = reference.tagName ? ensurePackageTagReady(node, options, reference.tagName, branch, options.workflowRunId) : null;
|
|
1849
|
+
void tagMessage;
|
|
1850
|
+
report.tagName = reference.tagName;
|
|
1851
|
+
report.version = version;
|
|
1454
1852
|
report.dependencySpec = reference.spec;
|
|
1455
1853
|
state.finalizedVersions.set(node.name, version);
|
|
1456
1854
|
state.finalizedReferences.set(node.name, reference);
|
|
1457
|
-
report
|
|
1458
|
-
report.publishWait = {
|
|
1459
|
-
...rebase,
|
|
1460
|
-
...push
|
|
1461
|
-
};
|
|
1855
|
+
await finishRepositorySavePublish(node, options, state, report, { branch, rebase, reference, tagName: reference.tagName });
|
|
1462
1856
|
} else {
|
|
1463
|
-
|
|
1464
|
-
report.pushed = push.pushed;
|
|
1465
|
-
report.publishWait = {
|
|
1466
|
-
...rebase,
|
|
1467
|
-
...push
|
|
1468
|
-
};
|
|
1857
|
+
await finishRepositorySavePublish(node, options, state, report, { branch, rebase });
|
|
1469
1858
|
}
|
|
1470
1859
|
report.commitSha = headCommit(node.path);
|
|
1471
1860
|
report.skippedReason = null;
|
|
@@ -1490,10 +1879,12 @@ async function runRepositorySaveOrchestrator(options) {
|
|
|
1490
1879
|
finalizedCommits: /* @__PURE__ */ new Map(),
|
|
1491
1880
|
reports: new Map(nodes.map((node) => [node.id, createReport(node)])),
|
|
1492
1881
|
remoteAccessChecked: /* @__PURE__ */ new Set(),
|
|
1493
|
-
workflowGates: []
|
|
1882
|
+
workflowGates: [],
|
|
1883
|
+
deferredPushes: []
|
|
1494
1884
|
};
|
|
1885
|
+
const concurrency = repositorySaveConcurrency(options);
|
|
1495
1886
|
for (const [index, wave] of waves.entries()) {
|
|
1496
|
-
await runLimited(wave,
|
|
1887
|
+
await runLimited(wave, concurrency, async (node) => {
|
|
1497
1888
|
try {
|
|
1498
1889
|
await saveOneRepository(node, options, state);
|
|
1499
1890
|
} catch (error) {
|
|
@@ -1554,6 +1945,7 @@ async function runRepositorySaveOrchestrator(options) {
|
|
|
1554
1945
|
state.workflowGates.push(...waveGates);
|
|
1555
1946
|
}
|
|
1556
1947
|
}
|
|
1948
|
+
await publishDeferredRepositoryPushes(options, state);
|
|
1557
1949
|
const rootNode = nodes.find((node) => node.id === ".") ?? allNodes.find((node) => node.id === ".");
|
|
1558
1950
|
const rootReport = rootNode ? state.reports.get(rootNode.id) ?? createReport(rootNode) : createReport({
|
|
1559
1951
|
id: ".",
|