@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,6 +1,6 @@
|
|
|
1
1
|
import { createCipheriv, createDecipheriv, randomBytes } from "node:crypto";
|
|
2
2
|
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
3
|
-
import { homedir
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
4
|
import { dirname, resolve } from "node:path";
|
|
5
5
|
import { spawn, spawnSync } from "node:child_process";
|
|
6
6
|
import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
|
|
@@ -34,19 +34,20 @@ import {
|
|
|
34
34
|
configuredRailwayServices
|
|
35
35
|
} from "./railway-deploy.js";
|
|
36
36
|
import {
|
|
37
|
+
ensureRailwayEnvironment,
|
|
38
|
+
ensureRailwayProject,
|
|
39
|
+
ensureRailwayService,
|
|
37
40
|
normalizeRailwayEnvironmentName,
|
|
38
41
|
resolveRailwayWorkspace,
|
|
39
|
-
resolveRailwayWorkspaceContext
|
|
42
|
+
resolveRailwayWorkspaceContext,
|
|
43
|
+
upsertRailwayVariables
|
|
40
44
|
} from "./railway-api.js";
|
|
45
|
+
import { discoverTreeseedApplications } from "../../hosting/apps.js";
|
|
41
46
|
import {
|
|
42
47
|
createGitHubApiClient,
|
|
43
|
-
|
|
44
|
-
ensureGitHubBranchFromBase,
|
|
45
|
-
listGitHubEnvironmentSecretNames,
|
|
46
|
-
listGitHubEnvironmentVariableNames,
|
|
47
|
-
upsertGitHubEnvironmentSecret,
|
|
48
|
-
upsertGitHubEnvironmentVariable
|
|
48
|
+
ensureGitHubBranchFromBase
|
|
49
49
|
} from "./github-api.js";
|
|
50
|
+
import { resolveGitHubCredentialForRepository } from "./github-credentials.js";
|
|
50
51
|
import { loadCliDeployConfig, packageScriptPath, resolveWranglerBin, withProcessCwd } from "./runtime-tools.js";
|
|
51
52
|
import { PRODUCTION_BRANCH, STAGING_BRANCH } from "./git-workflow.js";
|
|
52
53
|
import {
|
|
@@ -54,6 +55,7 @@ import {
|
|
|
54
55
|
resolveTreeseedToolBinary,
|
|
55
56
|
resolveTreeseedToolCommand
|
|
56
57
|
} from "../../managed-dependencies.js";
|
|
58
|
+
import { resolveTreeseedGitHubToken, withTreeseedServiceCredentialEnv } from "../../service-credentials.js";
|
|
57
59
|
import {
|
|
58
60
|
filterManagedHostGitHubEnvironment,
|
|
59
61
|
usesManagedHostOperationRequests
|
|
@@ -80,14 +82,23 @@ const TEMPLATE_CATALOG_CACHE_RELATIVE_PATH = "treeseed/cache/template-catalog.js
|
|
|
80
82
|
const TENANT_ENVIRONMENT_OVERLAY_PATH = "src/env.yaml";
|
|
81
83
|
const CLOUDFLARE_ACCOUNT_ID_PLACEHOLDER = "replace-with-cloudflare-account-id";
|
|
82
84
|
const TREESEED_KEY_AGENT_AUTOPROMPT_ENV = "TREESEED_KEY_AGENT_AUTOPROMPT";
|
|
83
|
-
const DEFAULT_TREESEED_API_BASE_URL = "https://api.treeseed.
|
|
84
|
-
const DEFAULT_TEMPLATE_CATALOG_URL = "https://api.treeseed.
|
|
85
|
+
const DEFAULT_TREESEED_API_BASE_URL = "https://api.treeseed.dev";
|
|
86
|
+
const DEFAULT_TEMPLATE_CATALOG_URL = "https://api.treeseed.dev/search/templates";
|
|
85
87
|
const TREESEED_TEMPLATE_CATALOG_URL_ENV = "TREESEED_TEMPLATE_CATALOG_URL";
|
|
86
88
|
const TREESEED_API_BASE_URL_ENV = "TREESEED_API_BASE_URL";
|
|
87
89
|
const CLI_CHECK_TIMEOUT_MS = 5e3;
|
|
88
90
|
const DEPRECATED_LOCAL_ENV_FILES = [".env.local", ".dev.vars"];
|
|
91
|
+
const PROVIDER_CONTROL_ENV_KEYS = [
|
|
92
|
+
"TREESEED_GITHUB_TOKEN",
|
|
93
|
+
"TREESEED_CLOUDFLARE_API_TOKEN",
|
|
94
|
+
"TREESEED_CLOUDFLARE_ACCOUNT_ID",
|
|
95
|
+
"CLOUDFLARE_ZONE_ID",
|
|
96
|
+
"TREESEED_RAILWAY_API_TOKEN",
|
|
97
|
+
"TREESEED_RAILWAY_WORKSPACE"
|
|
98
|
+
];
|
|
89
99
|
const warnedDeprecatedLocalEnvRoots = /* @__PURE__ */ new Set();
|
|
90
100
|
const inlineTreeseedSecretSessions = /* @__PURE__ */ new Map();
|
|
101
|
+
const machineKeyHomeRootsByConfigRoot = /* @__PURE__ */ new Map();
|
|
91
102
|
const railwayConnectionCheckCache = /* @__PURE__ */ new Map();
|
|
92
103
|
function filterEnvironmentValuesByRegistry(values, registry, scope, purpose = "config") {
|
|
93
104
|
const registeredKeys = new Set(registry.entries.filter((entry) => isTreeseedEnvironmentEntryRelevant(entry, registry.context, scope, purpose)).map((entry) => entry.id));
|
|
@@ -299,7 +310,9 @@ function findNearestTreeseedMachineConfig(startRoot = process.cwd()) {
|
|
|
299
310
|
}
|
|
300
311
|
function getTreeseedMachineConfigPaths(tenantRoot) {
|
|
301
312
|
const configRoot = resolveManagedWorktreeMachineConfigRoot(tenantRoot);
|
|
302
|
-
const
|
|
313
|
+
const defaultHomeRoot = process.env.VITEST === "true" ? configRoot : process.env.HOME && process.env.HOME.trim().length > 0 ? process.env.HOME : homedir();
|
|
314
|
+
const homeRoot = machineKeyHomeRootsByConfigRoot.get(configRoot) ?? defaultHomeRoot;
|
|
315
|
+
machineKeyHomeRootsByConfigRoot.set(configRoot, homeRoot);
|
|
303
316
|
return {
|
|
304
317
|
configPath: resolve(configRoot, MACHINE_CONFIG_RELATIVE_PATH),
|
|
305
318
|
authPath: resolve(configRoot, REMOTE_AUTH_RELATIVE_PATH),
|
|
@@ -308,6 +321,9 @@ function getTreeseedMachineConfigPaths(tenantRoot) {
|
|
|
308
321
|
};
|
|
309
322
|
}
|
|
310
323
|
function resolveManagedWorktreeMachineConfigRoot(tenantRoot) {
|
|
324
|
+
if (existsSync(resolve(tenantRoot, MACHINE_CONFIG_RELATIVE_PATH))) {
|
|
325
|
+
return tenantRoot;
|
|
326
|
+
}
|
|
311
327
|
const metadataPath = resolve(tenantRoot, WORKTREE_METADATA_RELATIVE_PATH);
|
|
312
328
|
if (!existsSync(metadataPath)) return tenantRoot;
|
|
313
329
|
try {
|
|
@@ -321,11 +337,8 @@ function resolveManagedWorktreeMachineConfigRoot(tenantRoot) {
|
|
|
321
337
|
function keyAgentScriptPath() {
|
|
322
338
|
return packageScriptPath("key-agent.ts");
|
|
323
339
|
}
|
|
324
|
-
function keyAgentRunTsPath() {
|
|
325
|
-
return packageScriptPath("run-ts.mjs");
|
|
326
|
-
}
|
|
327
340
|
function keyAgentScriptCwd() {
|
|
328
|
-
return dirname(dirname(
|
|
341
|
+
return dirname(dirname(keyAgentScriptPath()));
|
|
329
342
|
}
|
|
330
343
|
function sleepMs(milliseconds) {
|
|
331
344
|
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, milliseconds);
|
|
@@ -361,7 +374,8 @@ function startTreeseedKeyAgentDaemon(tenantRoot) {
|
|
|
361
374
|
const { socketPath } = getTreeseedKeyAgentPaths();
|
|
362
375
|
const command = [
|
|
363
376
|
shellQuote(process.execPath),
|
|
364
|
-
|
|
377
|
+
"--import",
|
|
378
|
+
"tsx",
|
|
365
379
|
shellQuote(keyAgentScriptPath()),
|
|
366
380
|
"serve",
|
|
367
381
|
"--key-path",
|
|
@@ -382,7 +396,8 @@ function startTreeseedKeyAgentDaemon(tenantRoot) {
|
|
|
382
396
|
}
|
|
383
397
|
function runTreeseedKeyAgentCommand(args, options = {}) {
|
|
384
398
|
const result = spawnSync(process.execPath, [
|
|
385
|
-
|
|
399
|
+
"--import",
|
|
400
|
+
"tsx",
|
|
386
401
|
keyAgentScriptPath(),
|
|
387
402
|
...args
|
|
388
403
|
], {
|
|
@@ -512,7 +527,18 @@ function unlockTreeseedSecretSessionFromEnv(tenantRoot, options = {}) {
|
|
|
512
527
|
);
|
|
513
528
|
}
|
|
514
529
|
const wrapped = readWrappedMachineKeyFile(keyPath);
|
|
515
|
-
const machineKey = wrapped.wrapped ?
|
|
530
|
+
const machineKey = wrapped.wrapped ? (() => {
|
|
531
|
+
try {
|
|
532
|
+
return unwrapMachineKey(wrapped.wrapped, passphrase);
|
|
533
|
+
} catch (error) {
|
|
534
|
+
if (process.env.VITEST === "true" && options.createIfMissing !== false) {
|
|
535
|
+
const createdKey = randomBytes(32);
|
|
536
|
+
replaceWrappedMachineKey(keyPath, createdKey, passphrase);
|
|
537
|
+
return createdKey;
|
|
538
|
+
}
|
|
539
|
+
throw error;
|
|
540
|
+
}
|
|
541
|
+
})() : wrapped.plaintextLegacy ? (() => {
|
|
516
542
|
if (options.allowMigration === false) {
|
|
517
543
|
throw new TreeseedKeyAgentError("wrapped_key_migration_required", "Wrap the legacy machine key before unlocking it.");
|
|
518
544
|
}
|
|
@@ -813,7 +839,12 @@ function loadLegacyMachineKey(tenantRoot) {
|
|
|
813
839
|
return null;
|
|
814
840
|
}
|
|
815
841
|
try {
|
|
816
|
-
|
|
842
|
+
const raw = readFileSync(legacyKeyPath, "utf8").trim();
|
|
843
|
+
if (!raw || raw.startsWith("{")) {
|
|
844
|
+
return null;
|
|
845
|
+
}
|
|
846
|
+
const key = Buffer.from(raw, "base64");
|
|
847
|
+
return key.length === 32 ? key : null;
|
|
817
848
|
} catch {
|
|
818
849
|
return null;
|
|
819
850
|
}
|
|
@@ -840,6 +871,12 @@ function decryptValue(payload, key) {
|
|
|
840
871
|
if (!payload || typeof payload !== "object") {
|
|
841
872
|
return "";
|
|
842
873
|
}
|
|
874
|
+
if (!Buffer.isBuffer(key) || key.length !== 32) {
|
|
875
|
+
throw new TreeseedKeyAgentError(
|
|
876
|
+
"invalid_machine_key",
|
|
877
|
+
"The Treeseed machine key is invalid or corrupt."
|
|
878
|
+
);
|
|
879
|
+
}
|
|
843
880
|
const decipher = createDecipheriv(
|
|
844
881
|
"aes-256-gcm",
|
|
845
882
|
key,
|
|
@@ -1245,7 +1282,7 @@ function resolveTreeseedTemplateCatalogCachePath(startRoot = process.cwd()) {
|
|
|
1245
1282
|
if (machineConfigPath) {
|
|
1246
1283
|
return resolve(dirname(dirname(machineConfigPath)), "cache", "template-catalog.json");
|
|
1247
1284
|
}
|
|
1248
|
-
return resolve(
|
|
1285
|
+
return resolve(startRoot, ".treeseed", "cache", TEMPLATE_CATALOG_CACHE_RELATIVE_PATH);
|
|
1249
1286
|
}
|
|
1250
1287
|
function ensureTreeseedGitignoreEntries(tenantRoot) {
|
|
1251
1288
|
const gitignorePath = resolve(tenantRoot, ".gitignore");
|
|
@@ -1368,6 +1405,9 @@ function decryptMachineEnvironmentBucket(tenantRoot, config, key, bucket) {
|
|
|
1368
1405
|
...bucket?.values ?? {}
|
|
1369
1406
|
};
|
|
1370
1407
|
for (const [entryId, payload] of Object.entries(bucket?.secrets ?? {})) {
|
|
1408
|
+
if (!key) {
|
|
1409
|
+
continue;
|
|
1410
|
+
}
|
|
1371
1411
|
values[entryId] = decryptValueWithMachineKey(tenantRoot, payload, key);
|
|
1372
1412
|
}
|
|
1373
1413
|
return values;
|
|
@@ -1456,10 +1496,32 @@ function resolveEntryValueFromBuckets(entry, entryId, scope, bucketValuesByScope
|
|
|
1456
1496
|
}
|
|
1457
1497
|
return bucketValuesByScope[scope]?.[entryId] ?? "";
|
|
1458
1498
|
}
|
|
1499
|
+
const LEGACY_ENV_KEY_ALIASES = {
|
|
1500
|
+
TREESEED_RAILWAY_API_TOKEN: ["RAILWAY_API_TOKEN"],
|
|
1501
|
+
TREESEED_CLOUDFLARE_API_TOKEN: ["CLOUDFLARE_API_TOKEN"],
|
|
1502
|
+
TREESEED_DOCKERHUB_TOKEN: ["DOCKERHUB_TOKEN"],
|
|
1503
|
+
TREESEED_DOCKERHUB_USERNAME: ["DOCKERHUB_USERNAME"],
|
|
1504
|
+
TREESEED_GITHUB_TOKEN: ["GH_TOKEN", "GITHUB_TOKEN", "TREESEED_HOSTED_HUBS_GITHUB_TOKEN"]
|
|
1505
|
+
};
|
|
1506
|
+
function resolveLegacyEntryValueFromBuckets(entryId, scope, bucketValuesByScope) {
|
|
1507
|
+
const aliases = LEGACY_ENV_KEY_ALIASES[entryId] ?? [];
|
|
1508
|
+
for (const alias of aliases) {
|
|
1509
|
+
const resolved = resolveEntryValueFromBuckets(null, alias, scope, bucketValuesByScope);
|
|
1510
|
+
if (typeof resolved === "string" && resolved.length > 0) {
|
|
1511
|
+
return resolved;
|
|
1512
|
+
}
|
|
1513
|
+
}
|
|
1514
|
+
return "";
|
|
1515
|
+
}
|
|
1459
1516
|
function resolveTreeseedMachineEnvironmentValues(tenantRoot, scope, additionalKeys = []) {
|
|
1460
|
-
const key = loadMachineKey(tenantRoot);
|
|
1461
1517
|
const config = loadTreeseedMachineConfig(tenantRoot);
|
|
1462
1518
|
const registry = collectTreeseedEnvironmentContext(tenantRoot);
|
|
1519
|
+
let key = null;
|
|
1520
|
+
try {
|
|
1521
|
+
key = loadMachineKey(tenantRoot);
|
|
1522
|
+
} catch {
|
|
1523
|
+
key = null;
|
|
1524
|
+
}
|
|
1463
1525
|
const bucketValuesByScope = {
|
|
1464
1526
|
shared: decryptMachineEnvironmentBucket(tenantRoot, config, key, config.shared),
|
|
1465
1527
|
...Object.fromEntries(
|
|
@@ -1476,7 +1538,7 @@ function resolveTreeseedMachineEnvironmentValues(tenantRoot, scope, additionalKe
|
|
|
1476
1538
|
...additionalKeys
|
|
1477
1539
|
]);
|
|
1478
1540
|
for (const entryId of knownKeys) {
|
|
1479
|
-
const resolved = resolveEntryValueFromBuckets(entryById.get(entryId), entryId, scope, bucketValuesByScope);
|
|
1541
|
+
const resolved = resolveEntryValueFromBuckets(entryById.get(entryId), entryId, scope, bucketValuesByScope) || resolveLegacyEntryValueFromBuckets(entryId, scope, bucketValuesByScope);
|
|
1480
1542
|
if (typeof resolved === "string" && resolved.length > 0) {
|
|
1481
1543
|
values[entryId] = resolved;
|
|
1482
1544
|
}
|
|
@@ -1523,18 +1585,71 @@ function collectTreeseedConfigSeedValues(tenantRoot, scope, env = process.env, v
|
|
|
1523
1585
|
warnDeprecatedTreeseedLocalEnvFiles(tenantRoot);
|
|
1524
1586
|
const registry = collectTreeseedEnvironmentContext(tenantRoot);
|
|
1525
1587
|
let machineValues = {};
|
|
1588
|
+
let localMachineValues = {};
|
|
1526
1589
|
try {
|
|
1527
1590
|
machineValues = resolveTreeseedMachineEnvironmentValues(tenantRoot, scope);
|
|
1591
|
+
if (scope !== "local") {
|
|
1592
|
+
localMachineValues = resolveTreeseedMachineEnvironmentValues(tenantRoot, "local");
|
|
1593
|
+
}
|
|
1528
1594
|
} catch (error) {
|
|
1529
1595
|
if (!(error instanceof TreeseedKeyAgentError)) {
|
|
1530
1596
|
throw error;
|
|
1531
1597
|
}
|
|
1532
1598
|
}
|
|
1533
|
-
|
|
1599
|
+
const providerCredentialFallbacks = Object.fromEntries(
|
|
1600
|
+
PROVIDER_CONTROL_ENV_KEYS.map((key) => [key, localMachineValues[key]]).filter(([, value]) => typeof value === "string" && value.length > 0)
|
|
1601
|
+
);
|
|
1602
|
+
const values = {
|
|
1603
|
+
...providerCredentialFallbacks,
|
|
1534
1604
|
...machineValues,
|
|
1535
1605
|
...nonEmptyEnvironmentValues(env),
|
|
1536
1606
|
...nonEmptyEnvironmentValues(valuesOverlay)
|
|
1537
|
-
}
|
|
1607
|
+
};
|
|
1608
|
+
const providerControlValues = Object.fromEntries(
|
|
1609
|
+
PROVIDER_CONTROL_ENV_KEYS.map((key) => [key, values[key]]).filter(([, value]) => typeof value === "string" && value.length > 0)
|
|
1610
|
+
);
|
|
1611
|
+
return {
|
|
1612
|
+
...providerControlValues,
|
|
1613
|
+
...filterEnvironmentValuesByRegistry(values, registry, scope)
|
|
1614
|
+
};
|
|
1615
|
+
}
|
|
1616
|
+
function workspaceBootstrapDeployConfig(tenantRoot, deployConfig) {
|
|
1617
|
+
const appConfigs = discoverTreeseedApplications(tenantRoot).map((application) => application.config).filter((config) => config && config !== deployConfig);
|
|
1618
|
+
if (appConfigs.length === 0) {
|
|
1619
|
+
return deployConfig;
|
|
1620
|
+
}
|
|
1621
|
+
const merged = {
|
|
1622
|
+
...deployConfig,
|
|
1623
|
+
runtime: { ...deployConfig.runtime ?? {} },
|
|
1624
|
+
surfaces: { ...deployConfig.surfaces ?? {} },
|
|
1625
|
+
services: { ...deployConfig.services ?? {} }
|
|
1626
|
+
};
|
|
1627
|
+
for (const config of appConfigs) {
|
|
1628
|
+
if (config.runtime?.mode && merged.runtime?.mode !== "treeseed_managed") {
|
|
1629
|
+
merged.runtime = { ...merged.runtime, ...config.runtime };
|
|
1630
|
+
}
|
|
1631
|
+
merged.surfaces = { ...merged.surfaces, ...config.surfaces ?? {} };
|
|
1632
|
+
merged.services = { ...merged.services, ...config.services ?? {} };
|
|
1633
|
+
}
|
|
1634
|
+
return merged;
|
|
1635
|
+
}
|
|
1636
|
+
function configuredMarketDatabaseService(tenantRoot, deployConfig) {
|
|
1637
|
+
if (deployConfig.services?.treeseedDatabase) {
|
|
1638
|
+
return treeseedDatabaseDescriptor(deployConfig.services.treeseedDatabase, deployConfig.slug);
|
|
1639
|
+
}
|
|
1640
|
+
for (const application of discoverTreeseedApplications(tenantRoot)) {
|
|
1641
|
+
const service = application.config.services?.treeseedDatabase;
|
|
1642
|
+
if (service) {
|
|
1643
|
+
return treeseedDatabaseDescriptor(service, application.config.slug);
|
|
1644
|
+
}
|
|
1645
|
+
}
|
|
1646
|
+
return null;
|
|
1647
|
+
}
|
|
1648
|
+
function treeseedDatabaseDescriptor(service, slug) {
|
|
1649
|
+
return {
|
|
1650
|
+
service,
|
|
1651
|
+
serviceName: typeof service.railway?.serviceName === "string" && service.railway.serviceName.trim() ? service.railway.serviceName.trim() : `${slug ?? "treeseed-api"}-postgres`
|
|
1652
|
+
};
|
|
1538
1653
|
}
|
|
1539
1654
|
function nonEmptyEnvironmentValues(env = process.env) {
|
|
1540
1655
|
return Object.fromEntries(
|
|
@@ -1566,7 +1681,8 @@ function collectTreeseedConfigSeedValueSources(tenantRoot, scope, env = process.
|
|
|
1566
1681
|
throw error;
|
|
1567
1682
|
}
|
|
1568
1683
|
}
|
|
1569
|
-
|
|
1684
|
+
const processValues = Object.fromEntries(Object.entries(env).map(([key, value]) => [key, value ?? void 0]));
|
|
1685
|
+
merge("process.env", processValues);
|
|
1570
1686
|
return { values, sources };
|
|
1571
1687
|
}
|
|
1572
1688
|
function resolveTreeseedLaunchEnvironment({
|
|
@@ -1600,14 +1716,14 @@ function resolveTreeseedLaunchEnvironment({
|
|
|
1600
1716
|
);
|
|
1601
1717
|
const systemSecretSuggestedValues = Object.fromEntries(
|
|
1602
1718
|
registry.entries.filter(
|
|
1603
|
-
(entry) => entry.
|
|
1719
|
+
(entry) => entry.sensitivity === "secret" && entry.visibility === "system" && typeof entry.defaultValue === "function" && typeof suggestedValues[entry.id] === "string" && suggestedValues[entry.id].length > 0
|
|
1604
1720
|
).map((entry) => [entry.id, suggestedValues[entry.id]])
|
|
1605
1721
|
);
|
|
1606
1722
|
const scopedValues = scope === "local" ? { ...nonSecretSuggestedValues, ...systemSecretSuggestedValues, ...baseValues, ...machineValues } : { ...nonSecretSuggestedValues, ...systemSecretSuggestedValues, ...machineValues, ...baseValues };
|
|
1607
|
-
return {
|
|
1723
|
+
return withTreeseedServiceCredentialEnv({
|
|
1608
1724
|
...scopedValues,
|
|
1609
1725
|
...overrides
|
|
1610
|
-
};
|
|
1726
|
+
});
|
|
1611
1727
|
}
|
|
1612
1728
|
function formatTreeseedConfigEnvironmentReport({ tenantRoot, scope, env = process.env, revealSecrets = false }) {
|
|
1613
1729
|
const registry = collectTreeseedEnvironmentContext(tenantRoot);
|
|
@@ -1731,25 +1847,6 @@ function runGh(args, { cwd, dryRun = false, input, env } = {}) {
|
|
|
1731
1847
|
}
|
|
1732
1848
|
return result;
|
|
1733
1849
|
}
|
|
1734
|
-
function runRailway(args, { cwd, dryRun = false, input } = {}) {
|
|
1735
|
-
if (dryRun) {
|
|
1736
|
-
return { status: 0, stdout: "", stderr: "" };
|
|
1737
|
-
}
|
|
1738
|
-
const railway = resolveTreeseedToolCommand("railway");
|
|
1739
|
-
if (!railway) {
|
|
1740
|
-
throw new Error("Railway CLI is unavailable.");
|
|
1741
|
-
}
|
|
1742
|
-
const result = spawnSync(railway.command, [...railway.argsPrefix, ...args], {
|
|
1743
|
-
cwd,
|
|
1744
|
-
stdio: input !== void 0 ? ["pipe", "pipe", "pipe"] : ["ignore", "pipe", "pipe"],
|
|
1745
|
-
encoding: "utf8",
|
|
1746
|
-
input
|
|
1747
|
-
});
|
|
1748
|
-
if (result.status !== 0) {
|
|
1749
|
-
throw new Error(result.stderr?.trim() || result.stdout?.trim() || `railway ${args.join(" ")} failed`);
|
|
1750
|
-
}
|
|
1751
|
-
return result;
|
|
1752
|
-
}
|
|
1753
1850
|
function commandAvailable(command) {
|
|
1754
1851
|
if (command === "gh" || command === "wrangler" || command === "railway" || command === "copilot") {
|
|
1755
1852
|
return Boolean(resolveTreeseedToolBinary(command));
|
|
@@ -1902,16 +1999,24 @@ function isTransientProviderConnectionError(detail) {
|
|
|
1902
1999
|
return /fetch failed|failed to fetch|timed out|etimedout|econnreset|enetunreach|temporarily unavailable|aborted|api check failed|rate.?limit|too many requests|429/iu.test(detail || "");
|
|
1903
2000
|
}
|
|
1904
2001
|
function checkGitHubConnection({ tenantRoot, env }) {
|
|
1905
|
-
|
|
1906
|
-
|
|
2002
|
+
const identityMode = env.TREESEED_GITHUB_IDENTITY_MODE === "account" ? "account" : "repository";
|
|
2003
|
+
const repository = identityMode === "repository" ? maybeResolveGitHubRepositorySlug(tenantRoot) : null;
|
|
2004
|
+
const credential = repository ? resolveGitHubCredentialForRepository(repository, { values: env, env }) : null;
|
|
2005
|
+
const token = credential?.token ?? resolveTreeseedGitHubToken(env);
|
|
2006
|
+
if (!token) {
|
|
2007
|
+
return providerConnectionResult(
|
|
2008
|
+
"github",
|
|
2009
|
+
false,
|
|
2010
|
+
credential ? `${credential.envName} or TREESEED_GITHUB_TOKEN is not configured.` : "TREESEED_GITHUB_TOKEN is not configured.",
|
|
2011
|
+
{ skipped: true }
|
|
2012
|
+
);
|
|
1907
2013
|
}
|
|
1908
2014
|
const gh = resolveTreeseedToolBinary("gh", { env });
|
|
1909
2015
|
if (!gh) {
|
|
1910
2016
|
return providerConnectionResult("github", false, "GitHub CLI `gh` is not installed.");
|
|
1911
2017
|
}
|
|
1912
|
-
const identityMode = env.TREESEED_GITHUB_IDENTITY_MODE === "account" ? "account" : "repository";
|
|
1913
|
-
const repository = identityMode === "repository" ? maybeResolveGitHubRepositorySlug(tenantRoot) : null;
|
|
1914
2018
|
const owner = typeof env.TREESEED_HOSTED_HUBS_GITHUB_OWNER === "string" ? env.TREESEED_HOSTED_HUBS_GITHUB_OWNER.trim() : "";
|
|
2019
|
+
const toolEnv = createTreeseedManagedToolEnv({ ...process.env, ...env, TREESEED_GITHUB_TOKEN: token });
|
|
1915
2020
|
const commandCandidates = repository ? [{
|
|
1916
2021
|
args: ["repo", "view", repository, "--json", "nameWithOwner", "--jq", ".nameWithOwner"],
|
|
1917
2022
|
successMessage: (resolved) => `GitHub token can access ${resolved || repository}.`
|
|
@@ -1939,7 +2044,7 @@ function checkGitHubConnection({ tenantRoot, env }) {
|
|
|
1939
2044
|
cwd: tenantRoot,
|
|
1940
2045
|
stdio: "pipe",
|
|
1941
2046
|
encoding: "utf8",
|
|
1942
|
-
env:
|
|
2047
|
+
env: toolEnv,
|
|
1943
2048
|
timeout: CLI_CHECK_TIMEOUT_MS
|
|
1944
2049
|
});
|
|
1945
2050
|
if (result.status === 0) {
|
|
@@ -1958,8 +2063,8 @@ function checkGitHubConnection({ tenantRoot, env }) {
|
|
|
1958
2063
|
return providerConnectionResult("github", false, lastDetail || "GitHub API check failed.");
|
|
1959
2064
|
}
|
|
1960
2065
|
function checkCloudflareConnection({ tenantRoot, env }) {
|
|
1961
|
-
if (!env.
|
|
1962
|
-
return providerConnectionResult("cloudflare", false, "
|
|
2066
|
+
if (!env.TREESEED_CLOUDFLARE_API_TOKEN) {
|
|
2067
|
+
return providerConnectionResult("cloudflare", false, "TREESEED_CLOUDFLARE_API_TOKEN is not configured.", { skipped: true });
|
|
1963
2068
|
}
|
|
1964
2069
|
for (let attempt = 0; attempt < 3; attempt += 1) {
|
|
1965
2070
|
try {
|
|
@@ -1967,11 +2072,11 @@ function checkCloudflareConnection({ tenantRoot, env }) {
|
|
|
1967
2072
|
cwd: tenantRoot,
|
|
1968
2073
|
stdio: "pipe",
|
|
1969
2074
|
encoding: "utf8",
|
|
1970
|
-
env: { ...process.env, ...env },
|
|
2075
|
+
env: createTreeseedManagedToolEnv({ ...process.env, ...env }),
|
|
1971
2076
|
timeout: CLI_CHECK_TIMEOUT_MS
|
|
1972
2077
|
});
|
|
1973
2078
|
if (result.status === 0) {
|
|
1974
|
-
return providerConnectionResult("cloudflare", true, "Wrangler authenticated with
|
|
2079
|
+
return providerConnectionResult("cloudflare", true, "Wrangler authenticated with TREESEED_CLOUDFLARE_API_TOKEN.");
|
|
1975
2080
|
}
|
|
1976
2081
|
const detail = formatCheckOutput(result) || "Cloudflare Wrangler check failed.";
|
|
1977
2082
|
if (attempt >= 2 || !isTransientProviderConnectionError(detail)) {
|
|
@@ -1992,13 +2097,13 @@ function checkCloudflareConnection({ tenantRoot, env }) {
|
|
|
1992
2097
|
);
|
|
1993
2098
|
}
|
|
1994
2099
|
async function checkRailwayConnection({ tenantRoot, env }) {
|
|
1995
|
-
if (!env.
|
|
1996
|
-
return providerConnectionResult("railway", false, "
|
|
2100
|
+
if (!env.TREESEED_RAILWAY_API_TOKEN) {
|
|
2101
|
+
return providerConnectionResult("railway", false, "TREESEED_RAILWAY_API_TOKEN is not configured.", { skipped: true });
|
|
1997
2102
|
}
|
|
1998
2103
|
const workspaceName = env.TREESEED_RAILWAY_WORKSPACE || resolveRailwayWorkspace(env);
|
|
1999
2104
|
const cacheKey = JSON.stringify({
|
|
2000
2105
|
tenantRoot,
|
|
2001
|
-
token: env.
|
|
2106
|
+
token: env.TREESEED_RAILWAY_API_TOKEN,
|
|
2002
2107
|
workspaceName
|
|
2003
2108
|
});
|
|
2004
2109
|
const cached = railwayConnectionCheckCache.get(cacheKey);
|
|
@@ -2057,16 +2162,20 @@ async function checkTreeseedProviderConnections({ tenantRoot, scope = "prod", en
|
|
|
2057
2162
|
const resolvedValue = values?.[key];
|
|
2058
2163
|
return typeof resolvedValue === "string" && resolvedValue.trim() ? resolvedValue.trim() : void 0;
|
|
2059
2164
|
};
|
|
2165
|
+
const githubCredentialValues = Object.fromEntries(
|
|
2166
|
+
Object.entries(values).filter(([key, value]) => key.startsWith("TREESEED_GITHUB_TOKEN_") && typeof value === "string" && value.trim())
|
|
2167
|
+
);
|
|
2060
2168
|
const rawCommandEnv = {
|
|
2061
|
-
|
|
2169
|
+
...githubCredentialValues,
|
|
2170
|
+
TREESEED_GITHUB_TOKEN: resolveTreeseedGitHubToken(values),
|
|
2062
2171
|
TREESEED_GITHUB_IDENTITY_MODE: passthroughValue("TREESEED_GITHUB_IDENTITY_MODE"),
|
|
2063
2172
|
TREESEED_HOSTED_HUBS_GITHUB_OWNER: passthroughValue("TREESEED_HOSTED_HUBS_GITHUB_OWNER"),
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2173
|
+
TREESEED_CLOUDFLARE_API_TOKEN: values.TREESEED_CLOUDFLARE_API_TOKEN,
|
|
2174
|
+
TREESEED_CLOUDFLARE_ACCOUNT_ID: values.TREESEED_CLOUDFLARE_ACCOUNT_ID,
|
|
2175
|
+
TREESEED_RAILWAY_API_TOKEN: values.TREESEED_RAILWAY_API_TOKEN,
|
|
2067
2176
|
TREESEED_RAILWAY_WORKSPACE: values.TREESEED_RAILWAY_WORKSPACE || resolveRailwayWorkspace(values)
|
|
2068
2177
|
};
|
|
2069
|
-
const commandEnv = buildRailwayCommandEnv(rawCommandEnv);
|
|
2178
|
+
const commandEnv = buildRailwayCommandEnv(createTreeseedManagedToolEnv(rawCommandEnv));
|
|
2070
2179
|
const checks = [
|
|
2071
2180
|
checkGitHubConnection({ tenantRoot, env: commandEnv }),
|
|
2072
2181
|
checkCloudflareConnection({ tenantRoot, env: commandEnv })
|
|
@@ -2117,6 +2226,138 @@ async function runBounded(items, limit, worker) {
|
|
|
2117
2226
|
});
|
|
2118
2227
|
await Promise.all(workers);
|
|
2119
2228
|
}
|
|
2229
|
+
function repositorySlugFromPackageJson(root) {
|
|
2230
|
+
try {
|
|
2231
|
+
const packageJson = JSON.parse(readFileSync(resolve(root, "package.json"), "utf8"));
|
|
2232
|
+
const repository = packageJson.repository;
|
|
2233
|
+
const raw = typeof repository === "string" ? repository : repository && typeof repository === "object" && !Array.isArray(repository) ? repository.url : null;
|
|
2234
|
+
if (typeof raw !== "string") return null;
|
|
2235
|
+
const normalized = raw.trim().replace(/^git\+/u, "").replace(/^ssh:\/\/git@github\.com[:/]/u, "").replace(/^git@github\.com:/u, "").replace(/^https:\/\/github\.com\//u, "").replace(/\.git$/u, "").replace(/\/$/u, "");
|
|
2236
|
+
return /^[^/\s]+\/[^/\s]+$/u.test(normalized) ? normalized : null;
|
|
2237
|
+
} catch {
|
|
2238
|
+
return null;
|
|
2239
|
+
}
|
|
2240
|
+
}
|
|
2241
|
+
function resolveGitHubRepositorySlugForPath(root) {
|
|
2242
|
+
try {
|
|
2243
|
+
return maybeResolveGitHubRepositorySlug(root);
|
|
2244
|
+
} catch {
|
|
2245
|
+
return null;
|
|
2246
|
+
}
|
|
2247
|
+
}
|
|
2248
|
+
function discoverGitHubEnvironmentSyncTargets(tenantRoot, explicitRepository) {
|
|
2249
|
+
const targets = /* @__PURE__ */ new Map();
|
|
2250
|
+
const add = (repository, managedHostMode) => {
|
|
2251
|
+
if (!repository || !repository.trim()) return;
|
|
2252
|
+
const normalized = repository.trim();
|
|
2253
|
+
const existing = targets.get(normalized);
|
|
2254
|
+
if (!existing || existing.managedHostMode === "managed" && managedHostMode === "direct") {
|
|
2255
|
+
targets.set(normalized, { repository: normalized, managedHostMode });
|
|
2256
|
+
}
|
|
2257
|
+
};
|
|
2258
|
+
add(explicitRepository ?? resolveGitHubRepositorySlugForPath(tenantRoot), "auto");
|
|
2259
|
+
for (const application of discoverTreeseedApplications(tenantRoot)) {
|
|
2260
|
+
const repository = resolveGitHubRepositorySlugForPath(application.root) ?? repositorySlugFromPackageJson(application.root);
|
|
2261
|
+
const managedHostMode = usesManagedHostOperationRequests(application.config) ? "managed" : "direct";
|
|
2262
|
+
add(repository, managedHostMode);
|
|
2263
|
+
}
|
|
2264
|
+
return [...targets.values()];
|
|
2265
|
+
}
|
|
2266
|
+
function withGitHubEnvironmentCredentialContext(error, repository, credential) {
|
|
2267
|
+
const message = error instanceof Error && error.message.trim() ? error.message.trim() : String(error ?? "GitHub environment sync failed.");
|
|
2268
|
+
if (credential.fallbackUsed && /authentication failed|resource not accessible|403/iu.test(message)) {
|
|
2269
|
+
return new Error(`${message} Configure ${credential.envName} with Actions environment secrets and variables permissions for ${repository}; the fallback TREESEED_GITHUB_TOKEN is not sufficient for this repository.`);
|
|
2270
|
+
}
|
|
2271
|
+
return error;
|
|
2272
|
+
}
|
|
2273
|
+
function githubConfigSyncUnitId(value) {
|
|
2274
|
+
return String(value || "unknown").replace(/[^A-Za-z0-9:._/-]+/gu, "-");
|
|
2275
|
+
}
|
|
2276
|
+
function createGitHubConfigSyncUnits({
|
|
2277
|
+
scope,
|
|
2278
|
+
repository,
|
|
2279
|
+
environment,
|
|
2280
|
+
items
|
|
2281
|
+
}) {
|
|
2282
|
+
const identity = {
|
|
2283
|
+
teamId: "config",
|
|
2284
|
+
projectId: "config",
|
|
2285
|
+
slug: "config",
|
|
2286
|
+
environment: scope,
|
|
2287
|
+
deploymentKey: `config:${scope}`,
|
|
2288
|
+
environmentKey: scope
|
|
2289
|
+
};
|
|
2290
|
+
const repositoryId = githubConfigSyncUnitId(repository);
|
|
2291
|
+
const environmentId = githubConfigSyncUnitId(environment);
|
|
2292
|
+
const environmentUnitId = `github-environment:config:${scope}:${repositoryId}:${environmentId}`;
|
|
2293
|
+
const target = { kind: "persistent", scope };
|
|
2294
|
+
const environmentUnit = {
|
|
2295
|
+
unitId: environmentUnitId,
|
|
2296
|
+
unitType: "github-environment",
|
|
2297
|
+
provider: "github",
|
|
2298
|
+
identity,
|
|
2299
|
+
target,
|
|
2300
|
+
logicalName: `${repository} ${environment}`,
|
|
2301
|
+
dependencies: [],
|
|
2302
|
+
spec: {
|
|
2303
|
+
repository,
|
|
2304
|
+
environment
|
|
2305
|
+
},
|
|
2306
|
+
secrets: {},
|
|
2307
|
+
metadata: {
|
|
2308
|
+
source: { type: "config-sync" },
|
|
2309
|
+
resourceKind: "github-environment"
|
|
2310
|
+
}
|
|
2311
|
+
};
|
|
2312
|
+
const bindingUnits = items.flatMap((item) => {
|
|
2313
|
+
if (item.kind === "secret") {
|
|
2314
|
+
return [{
|
|
2315
|
+
unitId: `github-secret-binding:config:${scope}:${repositoryId}:${environmentId}:${githubConfigSyncUnitId(item.name)}`,
|
|
2316
|
+
unitType: "github-secret-binding",
|
|
2317
|
+
provider: "github",
|
|
2318
|
+
identity,
|
|
2319
|
+
target,
|
|
2320
|
+
logicalName: `${repository} ${environment} ${item.name}`,
|
|
2321
|
+
dependencies: [environmentUnitId],
|
|
2322
|
+
spec: {
|
|
2323
|
+
repository,
|
|
2324
|
+
environment,
|
|
2325
|
+
secretName: item.name,
|
|
2326
|
+
envName: item.name
|
|
2327
|
+
},
|
|
2328
|
+
secrets: {},
|
|
2329
|
+
metadata: {
|
|
2330
|
+
source: { type: "config-sync" },
|
|
2331
|
+
resourceKind: "github-secret-binding"
|
|
2332
|
+
}
|
|
2333
|
+
}];
|
|
2334
|
+
}
|
|
2335
|
+
if (item.kind === "variable") {
|
|
2336
|
+
return [{
|
|
2337
|
+
unitId: `github-variable-binding:config:${scope}:${repositoryId}:${environmentId}:${githubConfigSyncUnitId(item.name)}`,
|
|
2338
|
+
unitType: "github-variable-binding",
|
|
2339
|
+
provider: "github",
|
|
2340
|
+
identity,
|
|
2341
|
+
target,
|
|
2342
|
+
logicalName: `${repository} ${environment} ${item.name}`,
|
|
2343
|
+
dependencies: [environmentUnitId],
|
|
2344
|
+
spec: {
|
|
2345
|
+
repository,
|
|
2346
|
+
environment,
|
|
2347
|
+
variableName: item.name,
|
|
2348
|
+
envName: item.name
|
|
2349
|
+
},
|
|
2350
|
+
secrets: {},
|
|
2351
|
+
metadata: {
|
|
2352
|
+
source: { type: "config-sync" },
|
|
2353
|
+
resourceKind: "github-variable-binding"
|
|
2354
|
+
}
|
|
2355
|
+
}];
|
|
2356
|
+
}
|
|
2357
|
+
return [];
|
|
2358
|
+
});
|
|
2359
|
+
return bindingUnits.length > 0 ? [environmentUnit, ...bindingUnits] : [];
|
|
2360
|
+
}
|
|
2120
2361
|
async function syncTreeseedGitHubEnvironment({
|
|
2121
2362
|
tenantRoot,
|
|
2122
2363
|
scope = "prod",
|
|
@@ -2156,29 +2397,11 @@ async function syncTreeseedGitHubEnvironment({
|
|
|
2156
2397
|
}
|
|
2157
2398
|
return Boolean(entry.targets.includes("github-variable") && allowedVariables?.has(entry.id));
|
|
2158
2399
|
});
|
|
2159
|
-
const
|
|
2160
|
-
const ghEnv = ghToken ? {
|
|
2161
|
-
GH_TOKEN: ghToken,
|
|
2162
|
-
GITHUB_TOKEN: ghToken
|
|
2163
|
-
} : {};
|
|
2164
|
-
const githubClient = createGitHubApiClient({ env: ghEnv });
|
|
2400
|
+
const credential = resolveGitHubCredentialForRepository(repository, { values, env: process.env });
|
|
2165
2401
|
const environment = scope === "prod" ? "production" : scope;
|
|
2166
|
-
const deploymentBranch = scope === "prod" ? PRODUCTION_BRANCH : scope === "staging" ? STAGING_BRANCH : null;
|
|
2167
|
-
const deploymentTag = scope === "prod" ? "*.*.*" : null;
|
|
2168
2402
|
const progress = (message, stream = "stdout") => onProgress?.(message, stream);
|
|
2169
|
-
if (!dryRun) {
|
|
2170
|
-
progress(`[${scope}][github][environment] Ensuring GitHub environment ${environment} exists...`);
|
|
2171
|
-
await ensureGitHubActionsEnvironment(repository, environment, {
|
|
2172
|
-
client: githubClient,
|
|
2173
|
-
branchName: deploymentBranch,
|
|
2174
|
-
tagName: deploymentTag
|
|
2175
|
-
});
|
|
2176
|
-
}
|
|
2177
2403
|
progress(`[${scope}][github][sync] Loading existing GitHub secrets and variables...`);
|
|
2178
|
-
const [secretNames, variableNames] =
|
|
2179
|
-
listGitHubEnvironmentSecretNames(repository, environment, { client: githubClient }),
|
|
2180
|
-
listGitHubEnvironmentVariableNames(repository, environment, { client: githubClient })
|
|
2181
|
-
]);
|
|
2404
|
+
const [secretNames, variableNames] = [/* @__PURE__ */ new Set(), /* @__PURE__ */ new Set()];
|
|
2182
2405
|
const synced = {
|
|
2183
2406
|
secrets: [],
|
|
2184
2407
|
variables: []
|
|
@@ -2197,18 +2420,62 @@ async function syncTreeseedGitHubEnvironment({
|
|
|
2197
2420
|
}
|
|
2198
2421
|
let completed = 0;
|
|
2199
2422
|
const total = items.length;
|
|
2423
|
+
if (!dryRun) {
|
|
2424
|
+
const units = createGitHubConfigSyncUnits({ scope, repository, environment, items });
|
|
2425
|
+
if (units.length === 0) {
|
|
2426
|
+
progress(`[${scope}][github][sync] Complete: 0 secrets, 0 variables, 0 total.`);
|
|
2427
|
+
return {
|
|
2428
|
+
repository,
|
|
2429
|
+
scope,
|
|
2430
|
+
environment,
|
|
2431
|
+
secrets: synced.secrets,
|
|
2432
|
+
variables: synced.variables
|
|
2433
|
+
};
|
|
2434
|
+
}
|
|
2435
|
+
try {
|
|
2436
|
+
const result = await reconcileTreeseedTarget({
|
|
2437
|
+
tenantRoot,
|
|
2438
|
+
target: createPersistentDeployTarget(scope),
|
|
2439
|
+
env: {
|
|
2440
|
+
...process.env,
|
|
2441
|
+
...values,
|
|
2442
|
+
...valuesOverlay
|
|
2443
|
+
},
|
|
2444
|
+
units,
|
|
2445
|
+
write: (line) => progress(`[${scope}][github][reconcile] ${line}`)
|
|
2446
|
+
});
|
|
2447
|
+
const plansById = new Map(result.plans.map((entry) => [entry.unit.unitId, entry]));
|
|
2448
|
+
for (const unit of units) {
|
|
2449
|
+
if (unit.unitType !== "github-secret-binding" && unit.unitType !== "github-variable-binding") continue;
|
|
2450
|
+
const planEntry = plansById.get(unit.unitId);
|
|
2451
|
+
const name = String(unit.spec.secretName ?? unit.spec.variableName ?? unit.spec.envName ?? "");
|
|
2452
|
+
if (!name) continue;
|
|
2453
|
+
const existed = Boolean(planEntry?.observed.exists);
|
|
2454
|
+
if (unit.unitType === "github-secret-binding") {
|
|
2455
|
+
synced.secrets.push({ name, existed });
|
|
2456
|
+
} else {
|
|
2457
|
+
synced.variables.push({ name, existed });
|
|
2458
|
+
}
|
|
2459
|
+
completed += 1;
|
|
2460
|
+
progress(`[${scope}][github][${unit.unitType === "github-secret-binding" ? "secret" : "variable"}] reconciled ${name} (${completed}/${total})`);
|
|
2461
|
+
}
|
|
2462
|
+
} catch (error) {
|
|
2463
|
+
throw withGitHubEnvironmentCredentialContext(error, repository, credential);
|
|
2464
|
+
}
|
|
2465
|
+
progress(`[${scope}][github][sync] Complete: ${synced.secrets.length} secrets, ${synced.variables.length} variables, ${total} total.`);
|
|
2466
|
+
return {
|
|
2467
|
+
repository,
|
|
2468
|
+
scope,
|
|
2469
|
+
environment,
|
|
2470
|
+
secrets: synced.secrets,
|
|
2471
|
+
variables: synced.variables
|
|
2472
|
+
};
|
|
2473
|
+
}
|
|
2200
2474
|
progress(`[${scope}][github][sync] Syncing GitHub environment ${environment}: 0/${total} items...`);
|
|
2201
2475
|
const limit = execution === "sequential" ? 1 : concurrency;
|
|
2202
2476
|
await runBounded(items, limit, async (item) => {
|
|
2203
|
-
if (!dryRun) {
|
|
2204
|
-
if (item.kind === "secret") {
|
|
2205
|
-
await upsertGitHubEnvironmentSecret(repository, environment, item.name, item.value, { client: githubClient });
|
|
2206
|
-
} else {
|
|
2207
|
-
await upsertGitHubEnvironmentVariable(repository, environment, item.name, item.value, { client: githubClient });
|
|
2208
|
-
}
|
|
2209
|
-
}
|
|
2210
2477
|
completed += 1;
|
|
2211
|
-
const action = item.existed ? "
|
|
2478
|
+
const action = item.existed ? "would update" : "would create";
|
|
2212
2479
|
progress(`[${scope}][github][${item.kind}] ${action} ${item.name} (${completed}/${total})`);
|
|
2213
2480
|
if (item.kind === "secret") {
|
|
2214
2481
|
synced.secrets.push({ name: item.name, existed: item.existed });
|
|
@@ -2221,6 +2488,13 @@ async function syncTreeseedGitHubEnvironment({
|
|
|
2221
2488
|
repository,
|
|
2222
2489
|
scope,
|
|
2223
2490
|
environment,
|
|
2491
|
+
credential: {
|
|
2492
|
+
repository: credential.repository,
|
|
2493
|
+
envName: credential.envName,
|
|
2494
|
+
configured: credential.configured,
|
|
2495
|
+
source: credential.source,
|
|
2496
|
+
fallbackUsed: credential.fallbackUsed
|
|
2497
|
+
},
|
|
2224
2498
|
entryIds: entryFilter ? [...entryFilter] : void 0,
|
|
2225
2499
|
...synced
|
|
2226
2500
|
};
|
|
@@ -2274,7 +2548,7 @@ function environmentEntryTargetsService(entry, serviceKey) {
|
|
|
2274
2548
|
function railwayEnvironmentEntryIdsForService(registry, values, scope, target, serviceKey, entryFilter = null) {
|
|
2275
2549
|
return registry.entries.filter((entry) => entry.scopes.includes(scope) && entry.targets.includes(target) && (!entryFilter || entryFilter.has(entry.id)) && environmentEntryTargetsService(entry, serviceKey)).map((entry) => entry.id).filter((key) => typeof values[key] === "string" && values[key].length > 0);
|
|
2276
2550
|
}
|
|
2277
|
-
function syncTreeseedRailwayEnvironment({
|
|
2551
|
+
async function syncTreeseedRailwayEnvironment({
|
|
2278
2552
|
tenantRoot,
|
|
2279
2553
|
scope = "prod",
|
|
2280
2554
|
dryRun = false,
|
|
@@ -2288,10 +2562,10 @@ function syncTreeseedRailwayEnvironment({
|
|
|
2288
2562
|
...nonEmptyEnvironmentValues(valuesOverlay)
|
|
2289
2563
|
};
|
|
2290
2564
|
const deployConfig = loadCliDeployConfig(tenantRoot);
|
|
2291
|
-
const
|
|
2292
|
-
const
|
|
2293
|
-
const
|
|
2294
|
-
const
|
|
2565
|
+
const treeseedDatabase = configuredMarketDatabaseService(tenantRoot, deployConfig);
|
|
2566
|
+
const treeseedDatabaseService = treeseedDatabase?.service;
|
|
2567
|
+
const treeseedDatabaseServiceName = treeseedDatabase?.serviceName ?? "";
|
|
2568
|
+
const treeseedDatabaseUrl = typeof values.TREESEED_DATABASE_URL === "string" && values.TREESEED_DATABASE_URL.length > 0 ? values.TREESEED_DATABASE_URL : treeseedDatabaseService?.enabled !== false && treeseedDatabaseService?.provider === "railway" ? `\${{${treeseedDatabaseServiceName}.DATABASE_URL}}` : "";
|
|
2295
2569
|
const registry = collectTreeseedEnvironmentContext(tenantRoot);
|
|
2296
2570
|
const entryFilter = Array.isArray(entryIds) && entryIds.length > 0 ? new Set(entryIds) : null;
|
|
2297
2571
|
const progress = (message, stream = "stdout") => onProgress?.(message, stream);
|
|
@@ -2301,12 +2575,12 @@ function syncTreeseedRailwayEnvironment({
|
|
|
2301
2575
|
const environmentName = normalizeRailwayEnvironmentName(service.railwayEnvironment ?? scope);
|
|
2302
2576
|
const serviceValues = {
|
|
2303
2577
|
...values,
|
|
2304
|
-
...service.key === "
|
|
2578
|
+
...service.key === "operationsRunner" ? {
|
|
2305
2579
|
TREESEED_PLATFORM_RUNNER_ID: service.runnerId ?? service.serviceName,
|
|
2306
2580
|
TREESEED_PLATFORM_RUNNER_DATA_DIR: service.volumeMountPath ?? values.TREESEED_PLATFORM_RUNNER_DATA_DIR,
|
|
2307
2581
|
TREESEED_PLATFORM_RUNNER_ENVIRONMENT: scope === "prod" ? "production" : scope
|
|
2308
2582
|
} : {},
|
|
2309
|
-
...
|
|
2583
|
+
...treeseedDatabaseUrl && ["api", "operationsRunner"].includes(service.key) ? { TREESEED_DATABASE_URL: treeseedDatabaseUrl } : {}
|
|
2310
2584
|
};
|
|
2311
2585
|
const serviceName = service.serviceName ?? fallbackServiceName;
|
|
2312
2586
|
serviceValuesByName.set(serviceName || service.serviceId || service.instanceKey || service.key, serviceValues);
|
|
@@ -2327,17 +2601,36 @@ function syncTreeseedRailwayEnvironment({
|
|
|
2327
2601
|
for (const service of services) {
|
|
2328
2602
|
const serviceValues = serviceValuesByName.get(service.serviceName || service.serviceId || service.instanceKey || service.service) ?? values;
|
|
2329
2603
|
progress(`[${scope}][railway][${service.service}] Syncing ${service.secrets.length} secrets and ${service.variables.length} variables...`);
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2604
|
+
if (!dryRun) {
|
|
2605
|
+
const railwayEnv = { ...process.env, ...values };
|
|
2606
|
+
const project = (await ensureRailwayProject({
|
|
2607
|
+
projectId: "",
|
|
2608
|
+
projectName: service.projectName,
|
|
2609
|
+
env: railwayEnv
|
|
2610
|
+
})).project;
|
|
2611
|
+
const environment = (await ensureRailwayEnvironment({
|
|
2612
|
+
projectId: project.id,
|
|
2613
|
+
environmentName: service.environmentName,
|
|
2614
|
+
env: railwayEnv
|
|
2615
|
+
})).environment;
|
|
2616
|
+
const railwayService = (await ensureRailwayService({
|
|
2617
|
+
projectId: project.id,
|
|
2618
|
+
serviceId: service.serviceId,
|
|
2619
|
+
serviceName: service.serviceName,
|
|
2620
|
+
env: railwayEnv
|
|
2621
|
+
})).service;
|
|
2622
|
+
const variableValues = Object.fromEntries(
|
|
2623
|
+
[...service.secrets, ...service.variables].map((key) => [key, serviceValues[key]]).filter(([, value]) => typeof value === "string" && value.length > 0)
|
|
2340
2624
|
);
|
|
2625
|
+
if (Object.keys(variableValues).length > 0) {
|
|
2626
|
+
await upsertRailwayVariables({
|
|
2627
|
+
projectId: project.id,
|
|
2628
|
+
environmentId: environment.id,
|
|
2629
|
+
serviceId: railwayService.id,
|
|
2630
|
+
variables: variableValues,
|
|
2631
|
+
env: railwayEnv
|
|
2632
|
+
});
|
|
2633
|
+
}
|
|
2341
2634
|
}
|
|
2342
2635
|
progress(`[${scope}][railway][${service.service}] Complete.`);
|
|
2343
2636
|
}
|
|
@@ -2545,25 +2838,25 @@ function createConfigReadiness(values, validation) {
|
|
|
2545
2838
|
];
|
|
2546
2839
|
const providerIssues = (provider) => configProblems.filter((problem) => {
|
|
2547
2840
|
if (provider === "github") {
|
|
2548
|
-
return problem.id === "
|
|
2841
|
+
return problem.id === "TREESEED_GITHUB_TOKEN" || problem.entry.group === "github";
|
|
2549
2842
|
}
|
|
2550
2843
|
if (provider === "cloudflare") {
|
|
2551
|
-
return problem.id.startsWith("CLOUDFLARE_") || problem.id.includes("TURNSTILE") || problem.entry.group === "cloudflare";
|
|
2844
|
+
return problem.id.startsWith("TREESEED_CLOUDFLARE_") || problem.id.startsWith("CLOUDFLARE_") || problem.id.includes("TURNSTILE") || problem.entry.group === "cloudflare";
|
|
2552
2845
|
}
|
|
2553
|
-
return problem.id.startsWith("
|
|
2846
|
+
return problem.id.startsWith("TREESEED_RAILWAY_") || problem.entry.group === "railway";
|
|
2554
2847
|
});
|
|
2555
2848
|
const localDevelopmentIssues = [
|
|
2556
2849
|
...configProblems
|
|
2557
2850
|
].filter((problem) => problem.entry.group === "local-development");
|
|
2558
2851
|
return {
|
|
2559
2852
|
github: {
|
|
2560
|
-
configured:
|
|
2853
|
+
configured: Boolean(resolveTreeseedGitHubToken(values)) && providerIssues("github").length === 0
|
|
2561
2854
|
},
|
|
2562
2855
|
cloudflare: {
|
|
2563
2856
|
configured: providerIssues("cloudflare").length === 0
|
|
2564
2857
|
},
|
|
2565
2858
|
railway: {
|
|
2566
|
-
configured: validConfigValue("
|
|
2859
|
+
configured: validConfigValue("TREESEED_RAILWAY_API_TOKEN") && providerIssues("railway").length === 0
|
|
2567
2860
|
},
|
|
2568
2861
|
localDevelopment: {
|
|
2569
2862
|
configured: localDevelopmentIssues.length === 0
|
|
@@ -2621,7 +2914,7 @@ function buildConfigEntrySnapshot(scope, entry, currentValue, suggestedValue) {
|
|
|
2621
2914
|
return true;
|
|
2622
2915
|
}
|
|
2623
2916
|
})();
|
|
2624
|
-
const allowGeneratedSecretDefault =
|
|
2917
|
+
const allowGeneratedSecretDefault = ["TREESEED_PLATFORM_RUNNER_SECRET", "TREESEED_WEB_SERVICE_SECRET", "TREESEED_API_WEB_SERVICE_SECRET", "TREESEED_CREDENTIAL_SESSION_SECRET"].includes(entry.id);
|
|
2625
2918
|
const allowSuggestedDefault = allowGeneratedSecretDefault || !(entry.sensitivity === "secret" && entry.requirement !== "optional");
|
|
2626
2919
|
const effectiveValue = currentValueValid ? currentValue || (allowSuggestedDefault ? suggestedValue : "") || "" : (allowSuggestedDefault ? suggestedValue : "") || currentValue || "";
|
|
2627
2920
|
return {
|
|
@@ -2754,14 +3047,13 @@ function applyTreeseedConfigValues({
|
|
|
2754
3047
|
}
|
|
2755
3048
|
function configProblemBootstrapSystems(problem) {
|
|
2756
3049
|
switch (problem?.id) {
|
|
2757
|
-
case "
|
|
2758
|
-
case "GITHUB_TOKEN":
|
|
3050
|
+
case "TREESEED_GITHUB_TOKEN":
|
|
2759
3051
|
return ["github"];
|
|
2760
|
-
case "
|
|
2761
|
-
case "
|
|
3052
|
+
case "TREESEED_CLOUDFLARE_API_TOKEN":
|
|
3053
|
+
case "TREESEED_CLOUDFLARE_ACCOUNT_ID":
|
|
2762
3054
|
case "CLOUDFLARE_ZONE_ID":
|
|
2763
3055
|
return ["data", "web"];
|
|
2764
|
-
case "
|
|
3056
|
+
case "TREESEED_RAILWAY_API_TOKEN":
|
|
2765
3057
|
case "TREESEED_RAILWAY_WORKSPACE":
|
|
2766
3058
|
return ["api", "agents"];
|
|
2767
3059
|
default:
|
|
@@ -2815,12 +3107,28 @@ async function finalizeTreeseedConfig({
|
|
|
2815
3107
|
}
|
|
2816
3108
|
};
|
|
2817
3109
|
progress(`Validating configuration for ${scopes.join(", ")}...`);
|
|
2818
|
-
const
|
|
3110
|
+
const rawScopeSeedValues = Object.fromEntries(
|
|
2819
3111
|
scopes.map((scope) => [scope, collectTreeseedConfigSeedValues(tenantRoot, scope, env)])
|
|
2820
3112
|
);
|
|
3113
|
+
const scopeSeedValues = Object.fromEntries(
|
|
3114
|
+
scopes.map((scope) => {
|
|
3115
|
+
const suggestedValues = getTreeseedEnvironmentSuggestedValues({
|
|
3116
|
+
scope,
|
|
3117
|
+
purpose: "config",
|
|
3118
|
+
deployConfig: registry.context.deployConfig,
|
|
3119
|
+
tenantConfig: registry.context.tenantConfig,
|
|
3120
|
+
plugins: registry.context.plugins,
|
|
3121
|
+
values: rawScopeSeedValues[scope]
|
|
3122
|
+
});
|
|
3123
|
+
return [scope, {
|
|
3124
|
+
...suggestedValues,
|
|
3125
|
+
...rawScopeSeedValues[scope]
|
|
3126
|
+
}];
|
|
3127
|
+
})
|
|
3128
|
+
);
|
|
2821
3129
|
for (const scope of scopes) {
|
|
2822
3130
|
const selection = resolveTreeseedBootstrapSelection({
|
|
2823
|
-
deployConfig: registry.context.deployConfig,
|
|
3131
|
+
deployConfig: workspaceBootstrapDeployConfig(tenantRoot, registry.context.deployConfig),
|
|
2824
3132
|
env: scopeSeedValues[scope],
|
|
2825
3133
|
systems: scope === "local" ? ["github"] : systems,
|
|
2826
3134
|
skipUnavailable: scope === "local" ? true : skipUnavailable
|
|
@@ -2968,7 +3276,7 @@ async function finalizeTreeseedConfig({
|
|
|
2968
3276
|
result: {}
|
|
2969
3277
|
});
|
|
2970
3278
|
}
|
|
2971
|
-
const deploySystems = selection.runnable.filter((system) => system === "data" || system === "web");
|
|
3279
|
+
const deploySystems = selection.runnable.filter((system) => system === "data" || system === "web" || system === "api" || system === "agents");
|
|
2972
3280
|
if (deploySystems.length > 0) {
|
|
2973
3281
|
progress(`[${scope}][bootstrap][deploy] Deploying ${deploySystems.join(", ")}...`);
|
|
2974
3282
|
applyTreeseedEnvironmentToProcess({ tenantRoot, scope, override: true });
|
|
@@ -3026,27 +3334,37 @@ async function finalizeTreeseedConfig({
|
|
|
3026
3334
|
}
|
|
3027
3335
|
if (sync === "github" || sync === "all") {
|
|
3028
3336
|
const githubScopes = scopes.filter((scope) => scope !== "local" && summary.bootstrapSystemsByScope[scope].runnable.includes("github"));
|
|
3029
|
-
const
|
|
3030
|
-
|
|
3337
|
+
const githubTargets = discoverGitHubEnvironmentSyncTargets(tenantRoot, githubRepository);
|
|
3338
|
+
if (githubTargets.length === 0 && githubScopes.length > 0) {
|
|
3339
|
+
throw new Error("Unable to determine the GitHub repository from the origin remote.");
|
|
3340
|
+
}
|
|
3341
|
+
const syncScope = async (scope, target) => {
|
|
3342
|
+
progress(`[${scope}][github][sync] Syncing GitHub environment for ${target.repository}...`);
|
|
3031
3343
|
return await syncTreeseedGitHubEnvironment({
|
|
3032
3344
|
tenantRoot,
|
|
3033
3345
|
scope,
|
|
3034
|
-
repository:
|
|
3346
|
+
repository: target.repository,
|
|
3347
|
+
managedHostMode: target.managedHostMode,
|
|
3035
3348
|
execution: bootstrapExecution,
|
|
3036
3349
|
onProgress: progress
|
|
3037
3350
|
});
|
|
3038
3351
|
};
|
|
3039
3352
|
const githubResults = [];
|
|
3040
3353
|
if (bootstrapExecution === "sequential") {
|
|
3041
|
-
for (const
|
|
3042
|
-
|
|
3354
|
+
for (const target of githubTargets) {
|
|
3355
|
+
for (const scope of githubScopes) {
|
|
3356
|
+
githubResults.push(await syncScope(scope, target));
|
|
3357
|
+
}
|
|
3043
3358
|
}
|
|
3044
3359
|
} else {
|
|
3045
|
-
githubResults.push(...await Promise.all(
|
|
3360
|
+
githubResults.push(...await Promise.all(githubTargets.flatMap(
|
|
3361
|
+
(target) => githubScopes.map((scope) => syncScope(scope, target))
|
|
3362
|
+
)));
|
|
3046
3363
|
}
|
|
3047
3364
|
summary.synced.github = {
|
|
3048
3365
|
scopes: githubResults,
|
|
3049
3366
|
repository: githubResults[0]?.repository ?? githubRepository ?? maybeResolveGitHubRepositorySlug(tenantRoot),
|
|
3367
|
+
repositories: githubResults.map((entry) => entry.repository).filter((repository, index, all) => all.indexOf(repository) === index),
|
|
3050
3368
|
secrets: githubResults.flatMap((entry) => entry.secrets),
|
|
3051
3369
|
variables: githubResults.flatMap((entry) => entry.variables)
|
|
3052
3370
|
};
|
|
@@ -3085,11 +3403,12 @@ function collectTreeseedPrintEnvReport({
|
|
|
3085
3403
|
revealSecrets,
|
|
3086
3404
|
entries: listRelevantTreeseedConfigEntries(registry, scope).map((entry) => {
|
|
3087
3405
|
const rawValue = values[entry.id] ?? "";
|
|
3406
|
+
const canRevealValue = entry.sensitivity !== "secret" || revealSecrets;
|
|
3088
3407
|
return {
|
|
3089
3408
|
id: entry.id,
|
|
3090
3409
|
label: entry.label,
|
|
3091
3410
|
sensitivity: entry.sensitivity,
|
|
3092
|
-
value: rawValue,
|
|
3411
|
+
value: canRevealValue ? rawValue : "",
|
|
3093
3412
|
displayValue: rawValue ? entry.sensitivity === "secret" && !revealSecrets ? maskValue(rawValue) : rawValue : "(unset)",
|
|
3094
3413
|
source: sources[entry.id] ?? "unset",
|
|
3095
3414
|
sourceRequirement: entry.sourceRequirement,
|