@gfdelarue/testkit 0.4.4 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +752 -462
- package/bin/testkit-windows-owner-arm64.exe +0 -0
- package/bin/testkit-windows-owner-x64.exe +0 -0
- package/dist/app/bugs/categories.js +1 -1
- package/dist/app/bugs/ci-report.js +2 -2
- package/dist/app/bugs/ci-summary.js +3 -3
- package/dist/app/bugs/draft.js +4 -4
- package/dist/app/bugs/facts.js +2 -2
- package/dist/app/bugs/file.js +1 -1
- package/dist/app/bugs/gate.js +1 -1
- package/dist/app/bugs/guide.js +3 -3
- package/dist/app/bugs/issue.js +4 -4
- package/dist/app/bugs/known-failures.js +1 -1
- package/dist/app/bugs/record.js +2 -2
- package/dist/app/bugs/run-reading.js +1 -1
- package/dist/app/bugs/supplied-reproduce.js +1 -0
- package/dist/app/campaigns/campaign.js +1 -1
- package/dist/app/cleanup/index.js +1 -1
- package/dist/app/db-schema/prepare.js +1 -1
- package/dist/app/destroy/index.js +1 -1
- package/dist/app/discover/index.js +2 -2
- package/dist/app/doctor/index.js +1 -1
- package/dist/app/environments/config-driven.js +1 -0
- package/dist/app/environments/environment-file.js +1 -0
- package/dist/app/environments/file-setup.js +1 -0
- package/dist/app/environments/routing.js +1 -0
- package/dist/app/environments/static-values.js +1 -0
- package/dist/app/environments/supplied-input.js +1 -0
- package/dist/app/environments/supplied.js +1 -0
- package/dist/app/environments/task-databases.js +2 -0
- package/dist/app/file-selection.js +1 -1
- package/dist/app/inspect/artifacts.js +1 -1
- package/dist/app/inspect/index.js +1 -1
- package/dist/app/lint/index.js +1 -1
- package/dist/app/lint/native.js +1 -1
- package/dist/app/lint/options.js +1 -1
- package/dist/app/lint/rules/data.js +1 -1
- package/dist/app/lint/rules/engine-imports.js +1 -1
- package/dist/app/lint/rules/syntax.js +1 -1
- package/dist/app/lint/rules/unit.js +1 -1
- package/dist/app/lint/shared.js +1 -1
- package/dist/app/package-inspection.js +1 -1
- package/dist/app/reports/files.js +1 -0
- package/dist/app/reports/prepare.js +2 -0
- package/dist/app/reports/publish.js +1 -0
- package/dist/app/run/caller-redaction.js +1 -0
- package/dist/app/run/engine-evidence-persistence.js +1 -1
- package/dist/app/run/engine-execution-failures.js +1 -1
- package/dist/app/run/engine-execution-reporting.js +1 -1
- package/dist/app/run/engine-execution.js +1 -1
- package/dist/app/run/engine-orchestration.js +1 -1
- package/dist/app/run/environment.js +1 -0
- package/dist/app/run/failure-details.js +1 -1
- package/dist/app/run/live-run.js +1 -1
- package/dist/app/run/orchestrator.js +1 -1
- package/dist/app/run/planning.js +1 -1
- package/dist/app/run/request.js +1 -1
- package/dist/app/run/results.js +1 -1
- package/dist/app/run/run-events.js +1 -1
- package/dist/app/run/run-finalization.js +1 -1
- package/dist/app/run/runtime-fixtures.js +1 -1
- package/dist/app/run/scheduler/estimates.js +1 -1
- package/dist/app/run/scheduler/identity.js +1 -1
- package/dist/app/run/scheduler/index.js +1 -1
- package/dist/app/run/scheduler/locks.js +1 -0
- package/dist/app/run/selection.js +1 -1
- package/dist/app/run/setup/runtime-node-setup-protocol.js +1 -1
- package/dist/app/run/setup/runtime-node-setup-worker.js +1 -1
- package/dist/app/run/setup/runtime-node-setup.js +2 -2
- package/dist/app/run/task-batches.js +1 -1
- package/dist/app/run/task-leases.js +1 -0
- package/dist/app/run/worker-loop.js +1 -1
- package/dist/app/status/runs.js +1 -1
- package/dist/app/tracker/index.js +1 -1
- package/dist/app/typecheck/index.js +4 -4
- package/dist/cli/command-catalog.js +1 -1
- package/dist/cli/command-flags.js +1 -1
- package/dist/cli/command-registry.js +1 -1
- package/dist/cli/commands/artifacts.js +2 -2
- package/dist/cli/commands/bug/file.js +2 -2
- package/dist/cli/commands/bug/record.js +2 -2
- package/dist/cli/commands/discover.js +1 -1
- package/dist/cli/commands/report/prepare.js +5 -0
- package/dist/cli/commands/report/publish.js +2 -0
- package/dist/cli/commands/run.js +2 -2
- package/dist/cli/commands/typecheck.js +1 -1
- package/dist/cli/commands/workspace.js +1 -1
- package/dist/cli/framework/errors.js +1 -1
- package/dist/cli/framework/execute.js +7 -6
- package/dist/cli/framework/parser.js +1 -1
- package/dist/cli/json-errors.js +1 -1
- package/dist/cli/operations/run/operation.js +2 -2
- package/dist/cli/renderers/bug/text.js +1 -1
- package/dist/cli/renderers/discover/report.js +1 -1
- package/dist/cli/renderers/doctor/text.js +1 -1
- package/dist/cli/renderers/run/events.js +2 -2
- package/dist/cli/renderers/run/formatting.js +1 -1
- package/dist/cli/renderers/run/status.js +1 -1
- package/dist/cli/renderers/run/text-reporter.js +24 -22
- package/dist/cli/terminal/colors.js +1 -1
- package/dist/cli/terminal/layout.js +2 -2
- package/dist/config/authoring/http-methods.js +1 -1
- package/dist/config/authoring/index.js +1 -1
- package/dist/config/authoring/preset-env.js +1 -1
- package/dist/config/loader/config-loader.js +1 -1
- package/dist/config/loader/database.js +1 -1
- package/dist/config/loader/decode-execution.js +1 -1
- package/dist/config/loader/dependencies.js +1 -1
- package/dist/config/loader/discover-tests.js +1 -1
- package/dist/config/loader/discovery-summary.js +1 -1
- package/dist/config/loader/discovery.js +2 -2
- package/dist/config/loader/env.js +1 -1
- package/dist/config/loader/execution-model.js +1 -1
- package/dist/config/loader/file-metadata.js +1 -1
- package/dist/config/loader/groups.js +1 -0
- package/dist/config/loader/index.js +1 -1
- package/dist/config/loader/load.js +1 -1
- package/dist/config/loader/managed-configs.js +1 -1
- package/dist/config/loader/owned-discovery.js +1 -0
- package/dist/config/loader/path-policy.js +1 -1
- package/dist/config/loader/runtime-isolation.js +1 -1
- package/dist/config/loader/runtime.js +1 -1
- package/dist/config/loader/skip-config.js +1 -1
- package/dist/config/loader/task-policy.js +1 -0
- package/dist/config/loader/test-selection.js +1 -1
- package/dist/config/loader/validation.js +1 -1
- package/dist/database/activity-gate.js +1 -1
- package/dist/database/admin.js +2 -2
- package/dist/database/bindings.js +1 -0
- package/dist/database/cleanup.js +1 -1
- package/dist/database/docker-metadata.js +3 -3
- package/dist/database/docker.js +3 -3
- package/dist/database/index.js +1 -1
- package/dist/database/lifecycle-cleanup.js +1 -1
- package/dist/database/local-postgres.js +1 -1
- package/dist/database/naming.js +1 -1
- package/dist/database/postgres/connection-check.js +1 -0
- package/dist/database/postgres/protocol.js +2 -0
- package/dist/database/schema-operations.js +1 -1
- package/dist/database/schema-source.js +3 -3
- package/dist/database/source-schema-env.js +1 -0
- package/dist/database/source-url.js +2 -2
- package/dist/database/state-files.js +1 -1
- package/dist/database/state.js +1 -1
- package/dist/database/steps.js +3 -3
- package/dist/domain/file-timeout.js +1 -1
- package/dist/domain/identifiers.js +1 -1
- package/dist/domain/operation-display.js +1 -1
- package/dist/domain/retired-test-types.js +1 -0
- package/dist/domain/runtime-isolation-contract.js +1 -1
- package/dist/domain/suite-selection.js +1 -1
- package/dist/domain/test-outcomes.js +1 -1
- package/dist/domain/test-types.js +1 -1
- package/dist/engines/adapters/evidence-files.js +1 -1
- package/dist/engines/adapters/evidence-identity.js +1 -1
- package/dist/engines/adapters/execution.js +1 -1
- package/dist/engines/adapters/json-bounds.js +2 -0
- package/dist/engines/adapters/native-report.js +1 -1
- package/dist/engines/api/execution-scope.js +1 -1
- package/dist/engines/api/execution.js +1 -1
- package/dist/engines/api/index.js +1 -1
- package/dist/engines/api/runtime-artifact.js +1 -1
- package/dist/engines/bundle-cache.js +1 -1
- package/dist/engines/catalog.js +1 -1
- package/dist/engines/contracts/environment-values.js +1 -0
- package/dist/engines/contracts/fixture-manifest.js +1 -1
- package/dist/engines/definitions.js +1 -1
- package/dist/engines/environment/handles.js +1 -0
- package/dist/engines/environment/index.js +1 -0
- package/dist/engines/factory.js +1 -1
- package/dist/engines/installations/node-vitest.js +1 -1
- package/dist/engines/installations/package-resolution.js +1 -1
- package/dist/engines/installations/playwright-resolution-child.js +1 -1
- package/dist/engines/installations/playwright.js +1 -1
- package/dist/engines/managed-module-resolution-policy-input.js +1 -1
- package/dist/engines/managed-module-resolution-policy.js +1 -1
- package/dist/engines/managed-module-resolution.js +2 -2
- package/dist/engines/manager.js +1 -1
- package/dist/engines/node-vitest/adapter/adapter.js +1 -1
- package/dist/engines/node-vitest/adapter/driver.js +2 -0
- package/dist/engines/node-vitest/adapter/evidence.js +2 -2
- package/dist/engines/node-vitest/adapter/failure-details.js +4 -2
- package/dist/engines/node-vitest/adapter/reporter.js +1 -1
- package/dist/engines/node-vitest/adapter/workspace.js +31 -192
- package/dist/engines/node-vitest/inventory/index.js +2 -0
- package/dist/engines/node-vitest/inventory/list-files.js +3 -0
- package/dist/engines/node-vitest/runtime/contract/index.js +1 -1
- package/dist/engines/node-vitest/runtime/data/http.js +1 -1
- package/dist/engines/node-vitest/runtime/data/index.js +1 -1
- package/dist/engines/node-vitest/runtime/data/report.js +5 -6
- package/dist/engines/node-vitest/runtime/data/scenario.js +2 -2
- package/dist/engines/node-vitest/runtime/runtime-input.js +1 -1
- package/dist/engines/node-vitest/selection.js +1 -0
- package/dist/engines/playwright/adapter/adapter.js +1 -1
- package/dist/engines/playwright/adapter/config.js +4 -4
- package/dist/engines/playwright/adapter/evidence-validation.js +1 -1
- package/dist/engines/playwright/adapter/evidence.js +1 -1
- package/dist/engines/playwright/adapter/reporter.js +1 -1
- package/dist/engines/playwright/runtime/config-file.js +1 -1
- package/dist/engines/playwright/runtime/config.js +1 -1
- package/dist/engines/playwright/runtime/runtime-input.js +43 -20
- package/dist/engines/runtime-input-file.js +1 -1
- package/dist/environment/lifecycle-artifacts.js +1 -1
- package/dist/environment/lifecycle-controller.js +1 -1
- package/dist/environment/lifecycle.js +1 -1
- package/dist/environment/ports.js +1 -0
- package/dist/environment/ready-environment.js +1 -1
- package/dist/environment/run-environment.js +1 -1
- package/dist/environment/run-stopping.js +1 -1
- package/dist/environment/runtime-contexts.js +1 -1
- package/dist/environment/runtime-manager.js +1 -1
- package/dist/environment/runtime-planning.js +1 -1
- package/dist/environment/runtime-preparation.js +1 -1
- package/dist/environment/services.js +3 -1
- package/dist/environment/state.js +1 -1
- package/dist/environment/template.js +1 -1
- package/dist/evidence/artifact-config.js +1 -1
- package/dist/evidence/artifact-validation.js +1 -1
- package/dist/evidence/artifacts.js +2 -2
- package/dist/evidence/bundles.js +1 -1
- package/dist/evidence/environment-record.js +1 -0
- package/dist/evidence/index.js +1 -1
- package/dist/evidence/logs.js +2 -2
- package/dist/evidence/operation-timings.js +1 -1
- package/dist/evidence/read-fields.js +1 -1
- package/dist/evidence/read-run.js +1 -1
- package/dist/evidence/reading.js +1 -1
- package/dist/evidence/redaction.js +4 -0
- package/dist/evidence/reporting.js +1 -1
- package/dist/evidence/run-model.js +1 -0
- package/dist/evidence/storage.js +2 -2
- package/dist/evidence/timing.js +1 -1
- package/dist/kernel/error-serialization.js +1 -1
- package/dist/kernel/redaction-targets.js +1 -0
- package/dist/kernel/redaction.js +4 -1
- package/dist/kernel/unknown-values.js +1 -1
- package/dist/process/environment.js +1 -1
- package/dist/process/execa-bundle.json +3 -3
- package/dist/process/files/json-file.js +1 -1
- package/dist/process/files/paths.js +1 -1
- package/dist/process/host/metadata.js +1 -1
- package/dist/process/host/platform.js +1 -1
- package/dist/process/host-process.js +1 -1
- package/dist/process/index.js +1 -1
- package/dist/process/lifecycle-fence.js +1 -1
- package/dist/process/locks.js +4 -4
- package/dist/process/port-listener.js +2 -0
- package/dist/process/process-group.js +1 -1
- package/dist/process/process-identity.js +1 -1
- package/dist/process/process.js +33 -33
- package/dist/process/readiness.js +1 -1
- package/dist/process/ready-deadline.js +1 -0
- package/dist/process/recovery.js +1 -1
- package/dist/process/runs/manifest.js +1 -1
- package/dist/process/runs/ownership.js +1 -1
- package/dist/process/runs/product-state.js +1 -1
- package/dist/process/runs/stop.js +1 -1
- package/dist/process/service-processes.js +1 -1
- package/dist/process/stoppable-settlement.js +1 -0
- package/dist/process/url-redaction.js +1 -0
- package/dist/process/windows-cli-owner.js +3 -3
- package/dist/process/windows-native.js +1 -1
- package/dist/repo/ci-environment.js +1 -1
- package/dist/repo/fingerprint-policy.js +1 -1
- package/dist/repo/managed-git.js +1 -1
- package/dist/repo/physical-tree.js +1 -1
- package/dist/repo/publish-directory.js +3 -0
- package/dist/repo/state.js +4 -4
- package/dist/steps/build-config.js +1 -1
- package/dist/steps/configured-step-testkit-modules.js +1 -1
- package/dist/steps/configured-steps.js +1 -1
- package/dist/steps/environment.js +1 -1
- package/dist/steps/index.js +1 -1
- package/dist/steps/run.js +2 -2
- package/dist/toolchains/archive.js +1 -1
- package/dist/toolchains/index.js +3 -3
- package/dist/toolchains/node-provisioning.js +2 -2
- package/dist/toolchains/semver.js +1 -1
- package/dist/toolchains/vitest/index.js +1 -1
- package/dist/tracker/redaction.js +1 -2
- package/dist/{config/runtime/build-assets.d.ts → types/config-build-assets.d.ts} +5 -3
- package/dist/{database/steps.d.ts → types/config-database-steps.d.ts} +7 -7
- package/dist/{config/runtime/next-runtime-tsconfig.d.ts → types/config-next-runtime-tsconfig.d.ts} +5 -3
- package/dist/types/config.d.ts +501 -0
- package/dist/types/drizzle.d.ts +13 -0
- package/dist/{config/runtime/env/index.d.ts → types/env.d.ts} +22 -20
- package/dist/types/environment.d.ts +40 -0
- package/dist/types/index.d.ts +21 -0
- package/dist/types/node-vitest-contract.d.ts +75 -0
- package/dist/types/node-vitest-data.d.ts +407 -0
- package/dist/types/playwright.d.ts +130 -0
- package/dist/types/tooling-vitest.d.ts +13 -0
- package/dist/types/workspace.d.ts +617 -0
- package/docs/bug-records.md +83 -81
- package/docs/engines.md +213 -0
- package/docs/test-types.md +35 -33
- package/package.json +22 -29
- package/testkit-config-schema.md +403 -171
- package/dist/app/bugs/areas.d.ts +0 -38
- package/dist/app/bugs/assessment.d.ts +0 -9
- package/dist/app/bugs/categories.d.ts +0 -41
- package/dist/app/bugs/ci-report.d.ts +0 -21
- package/dist/app/bugs/ci-summary.d.ts +0 -13
- package/dist/app/bugs/draft.d.ts +0 -70
- package/dist/app/bugs/facts.d.ts +0 -48
- package/dist/app/bugs/file.d.ts +0 -45
- package/dist/app/bugs/gate.d.ts +0 -22
- package/dist/app/bugs/guide.d.ts +0 -20
- package/dist/app/bugs/issue.d.ts +0 -18
- package/dist/app/bugs/known-failures.d.ts +0 -49
- package/dist/app/bugs/record.d.ts +0 -14
- package/dist/app/bugs/run-reading.d.ts +0 -51
- package/dist/app/bugs/store.d.ts +0 -34
- package/dist/app/campaigns/brief.d.ts +0 -7
- package/dist/app/campaigns/campaign.d.ts +0 -14
- package/dist/app/campaigns/index.d.ts +0 -38
- package/dist/app/campaigns/store.d.ts +0 -5
- package/dist/app/campaigns/summary.d.ts +0 -13
- package/dist/app/cleanup/index.d.ts +0 -52
- package/dist/app/db-schema/prepare.d.ts +0 -11
- package/dist/app/db-schema/refresh.d.ts +0 -17
- package/dist/app/db-schema/verify.d.ts +0 -11
- package/dist/app/destroy/index.d.ts +0 -16
- package/dist/app/discover/index.d.ts +0 -8
- package/dist/app/doctor/index.d.ts +0 -17
- package/dist/app/file-selection.d.ts +0 -1
- package/dist/app/inspect/artifacts.d.ts +0 -30
- package/dist/app/inspect/index.d.ts +0 -112
- package/dist/app/lint/index.d.ts +0 -28
- package/dist/app/lint/native.d.ts +0 -10
- package/dist/app/lint/options.d.ts +0 -67
- package/dist/app/lint/policy.d.ts +0 -21
- package/dist/app/lint/rules/data.d.ts +0 -3
- package/dist/app/lint/rules/engine-imports.d.ts +0 -3
- package/dist/app/lint/rules/syntax.d.ts +0 -4
- package/dist/app/lint/rules/unit.d.ts +0 -3
- package/dist/app/lint/shared.d.ts +0 -36
- package/dist/app/package-inspection.d.ts +0 -20
- package/dist/app/run/endpoint-readiness.d.ts +0 -43
- package/dist/app/run/endpoint-readiness.js +0 -1
- package/dist/app/run/engine-evidence-persistence.d.ts +0 -39
- package/dist/app/run/engine-execution-cleanup.d.ts +0 -8
- package/dist/app/run/engine-execution-cleanup.js +0 -1
- package/dist/app/run/engine-execution-failures.d.ts +0 -41
- package/dist/app/run/engine-execution-observer.d.ts +0 -21
- package/dist/app/run/engine-execution-reporting.d.ts +0 -17
- package/dist/app/run/engine-execution.d.ts +0 -63
- package/dist/app/run/engine-failure-stack.d.ts +0 -1
- package/dist/app/run/engine-orchestration.d.ts +0 -49
- package/dist/app/run/failure-details.d.ts +0 -37
- package/dist/app/run/live-run.d.ts +0 -27
- package/dist/app/run/operation-progress.d.ts +0 -13
- package/dist/app/run/orchestrator.d.ts +0 -68
- package/dist/app/run/planning-types.d.ts +0 -68
- package/dist/app/run/planning.d.ts +0 -15
- package/dist/app/run/playwright-configuration.d.ts +0 -2
- package/dist/app/run/playwright-configuration.js +0 -1
- package/dist/app/run/request.d.ts +0 -30
- package/dist/app/run/results.d.ts +0 -161
- package/dist/app/run/run-events.d.ts +0 -144
- package/dist/app/run/run-finalization.d.ts +0 -52
- package/dist/app/run/run-guards.d.ts +0 -3
- package/dist/app/run/runtime-failures.d.ts +0 -18
- package/dist/app/run/runtime-fixtures.d.ts +0 -2
- package/dist/app/run/runtime-task-types.d.ts +0 -20
- package/dist/app/run/scheduler/estimates.d.ts +0 -32
- package/dist/app/run/scheduler/identity.d.ts +0 -9
- package/dist/app/run/scheduler/index.d.ts +0 -124
- package/dist/app/run/scheduler/observations.d.ts +0 -20
- package/dist/app/run/selection.d.ts +0 -10
- package/dist/app/run/setup/runtime-node-setup-errors.d.ts +0 -13
- package/dist/app/run/setup/runtime-node-setup-protocol.d.ts +0 -85
- package/dist/app/run/setup/runtime-node-setup-worker.d.ts +0 -1
- package/dist/app/run/setup/runtime-node-setup.d.ts +0 -48
- package/dist/app/run/task-batches.d.ts +0 -23
- package/dist/app/run/worker-loop.d.ts +0 -57
- package/dist/app/setup/playwright.d.ts +0 -22
- package/dist/app/status/index.d.ts +0 -9
- package/dist/app/status/model.d.ts +0 -29
- package/dist/app/status/runs.d.ts +0 -99
- package/dist/app/stop/index.d.ts +0 -14
- package/dist/app/tracker/index.d.ts +0 -8
- package/dist/app/tracker/remote.d.ts +0 -13
- package/dist/app/tracker/token.d.ts +0 -7
- package/dist/app/typecheck/index.d.ts +0 -63
- package/dist/cli/command-catalog.d.ts +0 -137
- package/dist/cli/command-flags.d.ts +0 -19
- package/dist/cli/command-registry.d.ts +0 -3
- package/dist/cli/commands/artifacts.d.ts +0 -48
- package/dist/cli/commands/bug/file.d.ts +0 -16
- package/dist/cli/commands/bug/guide.d.ts +0 -5
- package/dist/cli/commands/bug/record.d.ts +0 -9
- package/dist/cli/commands/campaign/finish.d.ts +0 -10
- package/dist/cli/commands/campaign/start.d.ts +0 -7
- package/dist/cli/commands/campaign/status.d.ts +0 -13
- package/dist/cli/commands/ci/report.d.ts +0 -15
- package/dist/cli/commands/cleanup.d.ts +0 -13
- package/dist/cli/commands/db/schema/refresh.d.ts +0 -2
- package/dist/cli/commands/db/schema/verify.d.ts +0 -2
- package/dist/cli/commands/destroy.d.ts +0 -9
- package/dist/cli/commands/discover.d.ts +0 -2
- package/dist/cli/commands/doctor.d.ts +0 -2
- package/dist/cli/commands/guard/unsafe-entrypoint.d.ts +0 -2
- package/dist/cli/commands/lint.d.ts +0 -2
- package/dist/cli/commands/run/status.d.ts +0 -5
- package/dist/cli/commands/run/stop.d.ts +0 -7
- package/dist/cli/commands/run.d.ts +0 -9
- package/dist/cli/commands/setup/playwright.d.ts +0 -2
- package/dist/cli/commands/status.d.ts +0 -5
- package/dist/cli/commands/stop.d.ts +0 -12
- package/dist/cli/commands/typecheck.d.ts +0 -2
- package/dist/cli/commands/workspace.d.ts +0 -2
- package/dist/cli/entrypoint.d.ts +0 -1
- package/dist/cli/framework/command.d.ts +0 -21
- package/dist/cli/framework/definitions.d.ts +0 -100
- package/dist/cli/framework/errors.d.ts +0 -6
- package/dist/cli/framework/execute.d.ts +0 -14
- package/dist/cli/framework/help.d.ts +0 -11
- package/dist/cli/framework/index.d.ts +0 -3
- package/dist/cli/framework/parser.d.ts +0 -6
- package/dist/cli/index.d.ts +0 -4
- package/dist/cli/json-errors.d.ts +0 -3
- package/dist/cli/operations/db/schema/refresh/operation.d.ts +0 -7
- package/dist/cli/operations/db/schema/verify/operation.d.ts +0 -7
- package/dist/cli/operations/run/operation.d.ts +0 -24
- package/dist/cli/process-signal.d.ts +0 -1
- package/dist/cli/renderers/bug/text.d.ts +0 -8
- package/dist/cli/renderers/campaign/text.d.ts +0 -2
- package/dist/cli/renderers/ci/text.d.ts +0 -2
- package/dist/cli/renderers/cleanup/format.d.ts +0 -14
- package/dist/cli/renderers/db-schema/text.d.ts +0 -4
- package/dist/cli/renderers/destroy/text.d.ts +0 -4
- package/dist/cli/renderers/discover/report.d.ts +0 -7
- package/dist/cli/renderers/discover/text.d.ts +0 -3
- package/dist/cli/renderers/doctor/text.d.ts +0 -2
- package/dist/cli/renderers/lint/text.d.ts +0 -2
- package/dist/cli/renderers/run/events.d.ts +0 -8
- package/dist/cli/renderers/run/failure.d.ts +0 -8
- package/dist/cli/renderers/run/formatting.d.ts +0 -79
- package/dist/cli/renderers/run/status.d.ts +0 -6
- package/dist/cli/renderers/run/text-reporter.d.ts +0 -19
- package/dist/cli/renderers/status/text.d.ts +0 -2
- package/dist/cli/renderers/stop/text.d.ts +0 -7
- package/dist/cli/renderers/typecheck/text.d.ts +0 -2
- package/dist/cli/terminal/colors.d.ts +0 -10
- package/dist/cli/terminal/layout.d.ts +0 -11
- package/dist/cli/version-drift.d.ts +0 -25
- package/dist/config/authoring/build-config-contract.d.ts +0 -27
- package/dist/config/authoring/configured-step-contract.d.ts +0 -18
- package/dist/config/authoring/http-execution-contract.d.ts +0 -70
- package/dist/config/authoring/http-methods.d.ts +0 -18
- package/dist/config/authoring/index.d.ts +0 -381
- package/dist/config/authoring/preset-env.d.ts +0 -19
- package/dist/config/authoring/runtime.d.ts +0 -64
- package/dist/config/loader/bugs.d.ts +0 -15
- package/dist/config/loader/config-loader.d.ts +0 -9
- package/dist/config/loader/database-materialization.d.ts +0 -19
- package/dist/config/loader/database-roles.d.ts +0 -2
- package/dist/config/loader/database.d.ts +0 -55
- package/dist/config/loader/decode-discovery.d.ts +0 -5
- package/dist/config/loader/decode-execution.d.ts +0 -9
- package/dist/config/loader/dependencies.d.ts +0 -7
- package/dist/config/loader/discover-tests.d.ts +0 -111
- package/dist/config/loader/discovery-summary.d.ts +0 -29
- package/dist/config/loader/discovery.d.ts +0 -54
- package/dist/config/loader/env.d.ts +0 -4
- package/dist/config/loader/execution-model.d.ts +0 -16
- package/dist/config/loader/file-metadata.d.ts +0 -19
- package/dist/config/loader/index.d.ts +0 -10
- package/dist/config/loader/load.d.ts +0 -91
- package/dist/config/loader/managed-configs.d.ts +0 -23
- package/dist/config/loader/path-policy.d.ts +0 -9
- package/dist/config/loader/paths.d.ts +0 -5
- package/dist/config/loader/runtime-isolation.d.ts +0 -44
- package/dist/config/loader/runtime.d.ts +0 -25
- package/dist/config/loader/skip-config.d.ts +0 -44
- package/dist/config/loader/test-selection.d.ts +0 -15
- package/dist/config/loader/validation.d.ts +0 -16
- package/dist/config/loader/values.d.ts +0 -4
- package/dist/config/loader/values.js +0 -1
- package/dist/database/activity-gate.d.ts +0 -22
- package/dist/database/admin.d.ts +0 -31
- package/dist/database/cleanup.d.ts +0 -36
- package/dist/database/configured-steps.d.ts +0 -27
- package/dist/database/constants.d.ts +0 -11
- package/dist/database/docker-metadata.d.ts +0 -3
- package/dist/database/docker.d.ts +0 -65
- package/dist/database/drizzle/index.d.ts +0 -13
- package/dist/database/fingerprint.d.ts +0 -12
- package/dist/database/index.d.ts +0 -39
- package/dist/database/lifecycle-cleanup.d.ts +0 -7
- package/dist/database/local-postgres.d.ts +0 -71
- package/dist/database/naming.d.ts +0 -17
- package/dist/database/postgres/index.d.ts +0 -71
- package/dist/database/progress.d.ts +0 -6
- package/dist/database/roles.d.ts +0 -19
- package/dist/database/runtime-config.d.ts +0 -16
- package/dist/database/runtime-reservations.d.ts +0 -19
- package/dist/database/schema-operations.d.ts +0 -18
- package/dist/database/schema-source.d.ts +0 -96
- package/dist/database/source-refresh-lock.d.ts +0 -8
- package/dist/database/source-url.d.ts +0 -22
- package/dist/database/state-files.d.ts +0 -13
- package/dist/database/state.d.ts +0 -26
- package/dist/database/template-steps.d.ts +0 -39
- package/dist/domain/file-timeout.d.ts +0 -28
- package/dist/domain/identifiers.d.ts +0 -9
- package/dist/domain/operation-display.d.ts +0 -10
- package/dist/domain/operation-reason.d.ts +0 -5
- package/dist/domain/postgres-route.d.ts +0 -4
- package/dist/domain/runtime-identity.d.ts +0 -1
- package/dist/domain/runtime-isolation-contract.d.ts +0 -5
- package/dist/domain/service-name.d.ts +0 -2
- package/dist/domain/suite-selection.d.ts +0 -20
- package/dist/domain/test-outcomes.d.ts +0 -3
- package/dist/domain/test-types.d.ts +0 -16
- package/dist/engines/adapters/evidence-files.d.ts +0 -32
- package/dist/engines/adapters/evidence-identity.d.ts +0 -12
- package/dist/engines/adapters/execution.d.ts +0 -42
- package/dist/engines/adapters/native-report.d.ts +0 -25
- package/dist/engines/adapters/node-startup-cache.d.ts +0 -8
- package/dist/engines/adapters/workspace.d.ts +0 -4
- package/dist/engines/api/capabilities.d.ts +0 -31
- package/dist/engines/api/capabilities.js +0 -1
- package/dist/engines/api/evidence.d.ts +0 -38
- package/dist/engines/api/execution-observer.d.ts +0 -8
- package/dist/engines/api/execution-scope.d.ts +0 -17
- package/dist/engines/api/execution.d.ts +0 -101
- package/dist/engines/api/index.d.ts +0 -5
- package/dist/engines/api/k6-runtime-input.d.ts +0 -26
- package/dist/engines/api/k6-runtime-input.js +0 -1
- package/dist/engines/api/runtime-artifact.d.ts +0 -19
- package/dist/engines/bundle-cache.d.ts +0 -32
- package/dist/engines/catalog.d.ts +0 -27
- package/dist/engines/contracts/fixture-manifest.d.ts +0 -34
- package/dist/engines/contracts/json-bounds.d.ts +0 -36
- package/dist/engines/contracts/json-bounds.js +0 -2
- package/dist/engines/contracts/k6-repository-configuration.d.ts +0 -12
- package/dist/engines/contracts/k6-repository-configuration.js +0 -1
- package/dist/engines/contracts/test-context.d.ts +0 -15
- package/dist/engines/contracts/test-context.js +0 -1
- package/dist/engines/definitions.d.ts +0 -22
- package/dist/engines/factory.d.ts +0 -6
- package/dist/engines/generated-performance.d.ts +0 -1
- package/dist/engines/installation-catalog.d.ts +0 -27
- package/dist/engines/installation-catalog.js +0 -1
- package/dist/engines/installations/k6.d.ts +0 -98
- package/dist/engines/installations/k6.js +0 -1
- package/dist/engines/installations/node-vitest.d.ts +0 -33
- package/dist/engines/installations/package-requirements.d.ts +0 -28
- package/dist/engines/installations/package-resolution.d.ts +0 -51
- package/dist/engines/installations/playwright-resolution-child.d.ts +0 -1
- package/dist/engines/installations/playwright.d.ts +0 -75
- package/dist/engines/installations/types.d.ts +0 -10
- package/dist/engines/k6/adapter/bundle.d.ts +0 -25
- package/dist/engines/k6/adapter/bundle.js +0 -112
- package/dist/engines/k6/adapter/evidence.d.ts +0 -15
- package/dist/engines/k6/adapter/evidence.js +0 -4
- package/dist/engines/k6/adapter/executor.d.ts +0 -13
- package/dist/engines/k6/adapter/executor.js +0 -1
- package/dist/engines/k6/adapter/index.d.ts +0 -1
- package/dist/engines/k6/adapter/index.js +0 -1
- package/dist/engines/k6/adapter/input.d.ts +0 -21
- package/dist/engines/k6/adapter/input.js +0 -1
- package/dist/engines/k6/adapter/native-summary.d.ts +0 -11
- package/dist/engines/k6/adapter/native-summary.js +0 -1
- package/dist/engines/k6/adapter/repository-configuration.d.ts +0 -2
- package/dist/engines/k6/adapter/repository-configuration.js +0 -1
- package/dist/engines/k6/authoring-type-paths.d.ts +0 -3
- package/dist/engines/k6/authoring-type-paths.js +0 -1
- package/dist/engines/k6/runtime/ambient-types/bundle-manifest.json +0 -146
- package/dist/engines/k6/runtime/ambient-types/k6/LICENSE +0 -21
- package/dist/engines/k6/runtime/ambient-types/k6/browser/index.d.ts +0 -6332
- package/dist/engines/k6/runtime/ambient-types/k6/crypto/index.d.ts +0 -218
- package/dist/engines/k6/runtime/ambient-types/k6/data/index.d.ts +0 -16
- package/dist/engines/k6/runtime/ambient-types/k6/encoding/index.d.ts +0 -46
- package/dist/engines/k6/runtime/ambient-types/k6/execution/index.d.ts +0 -127
- package/dist/engines/k6/runtime/ambient-types/k6/experimental/csv/index.d.ts +0 -96
- package/dist/engines/k6/runtime/ambient-types/k6/experimental/fs/index.d.ts +0 -104
- package/dist/engines/k6/runtime/ambient-types/k6/experimental/redis/index.d.ts +0 -821
- package/dist/engines/k6/runtime/ambient-types/k6/experimental/streams/index.d.ts +0 -198
- package/dist/engines/k6/runtime/ambient-types/k6/global.d.ts +0 -83
- package/dist/engines/k6/runtime/ambient-types/k6/html/index.d.ts +0 -1325
- package/dist/engines/k6/runtime/ambient-types/k6/http/index.d.ts +0 -806
- package/dist/engines/k6/runtime/ambient-types/k6/index.d.ts +0 -126
- package/dist/engines/k6/runtime/ambient-types/k6/metrics/index.d.ts +0 -66
- package/dist/engines/k6/runtime/ambient-types/k6/net/grpc/index.d.ts +0 -247
- package/dist/engines/k6/runtime/ambient-types/k6/options/index.d.ts +0 -459
- package/dist/engines/k6/runtime/ambient-types/k6/package.json +0 -79
- package/dist/engines/k6/runtime/ambient-types/k6/secrets/index.d.ts +0 -36
- package/dist/engines/k6/runtime/ambient-types/k6/timers/index.d.ts +0 -47
- package/dist/engines/k6/runtime/ambient-types/k6/websockets/index.d.ts +0 -324
- package/dist/engines/k6/runtime/ambient-types/k6/ws/index.d.ts +0 -283
- package/dist/engines/k6/runtime/ambient-types/xk6-sql/LICENSE +0 -201
- package/dist/engines/k6/runtime/ambient-types/xk6-sql/index.d.ts +0 -397
- package/dist/engines/k6/runtime/ambient-types/xk6-sql/package.json +0 -15
- package/dist/engines/k6/runtime/artifacts.d.ts +0 -2
- package/dist/engines/k6/runtime/artifacts.js +0 -1
- package/dist/engines/k6/runtime/checks.d.ts +0 -17
- package/dist/engines/k6/runtime/checks.js +0 -1
- package/dist/engines/k6/runtime/dal-fixtures.d.ts +0 -24
- package/dist/engines/k6/runtime/dal-fixtures.js +0 -1
- package/dist/engines/k6/runtime/dal-suite.d.ts +0 -24
- package/dist/engines/k6/runtime/dal-suite.js +0 -1
- package/dist/engines/k6/runtime/dal.d.ts +0 -10
- package/dist/engines/k6/runtime/dal.js +0 -1
- package/dist/engines/k6/runtime/fixtures.d.ts +0 -3
- package/dist/engines/k6/runtime/fixtures.js +0 -1
- package/dist/engines/k6/runtime/http-assertions.d.ts +0 -19
- package/dist/engines/k6/runtime/http-assertions.js +0 -1
- package/dist/engines/k6/runtime/http-checks.d.ts +0 -19
- package/dist/engines/k6/runtime/http-checks.js +0 -1
- package/dist/engines/k6/runtime/http-suite-runtime.d.ts +0 -103
- package/dist/engines/k6/runtime/http-suite-runtime.js +0 -1
- package/dist/engines/k6/runtime/http.d.ts +0 -15
- package/dist/engines/k6/runtime/http.js +0 -1
- package/dist/engines/k6/runtime/index.d.ts +0 -11
- package/dist/engines/k6/runtime/index.js +0 -1
- package/dist/engines/k6/runtime/input.d.ts +0 -3
- package/dist/engines/k6/runtime/input.js +0 -1
- package/dist/engines/k6/runtime/k6-repository-configuration.d.ts +0 -9
- package/dist/engines/k6/runtime/k6-repository-configuration.js +0 -1
- package/dist/engines/k6/runtime/node-setup.d.ts +0 -13
- package/dist/engines/k6/runtime/node-setup.js +0 -1
- package/dist/engines/k6/runtime/runtime-globals.d.ts +0 -10
- package/dist/engines/k6/runtime/runtime.d.ts +0 -54
- package/dist/engines/k6/runtime/runtime.js +0 -1
- package/dist/engines/k6/runtime/shared/assertion-details.d.ts +0 -19
- package/dist/engines/k6/runtime/shared/assertion-details.js +0 -2
- package/dist/engines/k6/runtime/shared/db-normalization.d.ts +0 -19
- package/dist/engines/k6/runtime/shared/db-normalization.js +0 -1
- package/dist/engines/k6/runtime/shared/error-body.d.ts +0 -3
- package/dist/engines/k6/runtime/shared/error-body.js +0 -1
- package/dist/engines/k6/runtime/shared/file-data.d.ts +0 -1
- package/dist/engines/k6/runtime/shared/file-data.js +0 -1
- package/dist/engines/k6/runtime/shared/fixture-engine.d.ts +0 -8
- package/dist/engines/k6/runtime/shared/fixture-engine.js +0 -2
- package/dist/engines/k6/runtime/shared/http-check-plan.d.ts +0 -29
- package/dist/engines/k6/runtime/shared/http-check-plan.js +0 -1
- package/dist/engines/k6/runtime/shared/http-parsing.d.ts +0 -10
- package/dist/engines/k6/runtime/shared/http-parsing.js +0 -3
- package/dist/engines/k6/runtime/shared/ordering.d.ts +0 -2
- package/dist/engines/k6/runtime/shared/ordering.js +0 -1
- package/dist/engines/k6/runtime/shared/properties.d.ts +0 -1
- package/dist/engines/k6/runtime/shared/properties.js +0 -1
- package/dist/engines/k6/runtime/suite.d.ts +0 -4
- package/dist/engines/k6/runtime/suite.js +0 -1
- package/dist/engines/k6/runtime/types.d.ts +0 -244
- package/dist/engines/k6/runtime/types.js +0 -1
- package/dist/engines/k6/runtime/xk6-sql-driver-postgres.d.ts +0 -7
- package/dist/engines/k6/runtime/xk6-sql-driver-postgres.js +0 -1
- package/dist/engines/managed-module-resolution-policy-input.d.ts +0 -9
- package/dist/engines/managed-module-resolution-policy.d.ts +0 -25
- package/dist/engines/managed-module-resolution.d.ts +0 -13
- package/dist/engines/manager.d.ts +0 -25
- package/dist/engines/node-vitest/adapter/adapter.d.ts +0 -16
- package/dist/engines/node-vitest/adapter/consumer-typescript-paths.d.ts +0 -17
- package/dist/engines/node-vitest/adapter/consumer-typescript-paths.js +0 -3
- package/dist/engines/node-vitest/adapter/evidence.d.ts +0 -33
- package/dist/engines/node-vitest/adapter/failure-details.d.ts +0 -3
- package/dist/engines/node-vitest/adapter/index.d.ts +0 -1
- package/dist/engines/node-vitest/adapter/reporter.d.ts +0 -7
- package/dist/engines/node-vitest/adapter/resolution.d.ts +0 -12
- package/dist/engines/node-vitest/adapter/resolution.js +0 -1
- package/dist/engines/node-vitest/adapter/workspace.d.ts +0 -19
- package/dist/engines/node-vitest/runtime/contract/index.d.ts +0 -64
- package/dist/engines/node-vitest/runtime/data/http.d.ts +0 -4
- package/dist/engines/node-vitest/runtime/data/index.d.ts +0 -8
- package/dist/engines/node-vitest/runtime/data/primitives.d.ts +0 -1
- package/dist/engines/node-vitest/runtime/data/report.d.ts +0 -3
- package/dist/engines/node-vitest/runtime/data/runner.d.ts +0 -4
- package/dist/engines/node-vitest/runtime/data/scenario.d.ts +0 -12
- package/dist/engines/node-vitest/runtime/data/types.d.ts +0 -412
- package/dist/engines/node-vitest/runtime/runtime-input.d.ts +0 -64
- package/dist/engines/playwright/adapter/adapter.d.ts +0 -18
- package/dist/engines/playwright/adapter/attachments.d.ts +0 -26
- package/dist/engines/playwright/adapter/config.d.ts +0 -45
- package/dist/engines/playwright/adapter/evidence-validation.d.ts +0 -12
- package/dist/engines/playwright/adapter/evidence.d.ts +0 -32
- package/dist/engines/playwright/adapter/failure-details.d.ts +0 -2
- package/dist/engines/playwright/adapter/index.d.ts +0 -3
- package/dist/engines/playwright/adapter/reporter.d.ts +0 -12
- package/dist/engines/playwright/runtime/config-file.d.ts +0 -2
- package/dist/engines/playwright/runtime/config.d.ts +0 -24
- package/dist/engines/playwright/runtime/index.d.ts +0 -4
- package/dist/engines/playwright/runtime/runtime-input.d.ts +0 -36
- package/dist/engines/playwright/runtime/sandbox.d.ts +0 -84
- package/dist/engines/runtime-input-file.d.ts +0 -27
- package/dist/environment/lifecycle-artifacts.d.ts +0 -7
- package/dist/environment/lifecycle-controller.d.ts +0 -70
- package/dist/environment/lifecycle.d.ts +0 -29
- package/dist/environment/maintenance.d.ts +0 -68
- package/dist/environment/planning-types.d.ts +0 -35
- package/dist/environment/readiness.d.ts +0 -12
- package/dist/environment/readiness.js +0 -1
- package/dist/environment/ready-environment.d.ts +0 -19
- package/dist/environment/run-environment.d.ts +0 -38
- package/dist/environment/run-stopping.d.ts +0 -13
- package/dist/environment/runtime-contexts.d.ts +0 -33
- package/dist/environment/runtime-manager.d.ts +0 -95
- package/dist/environment/runtime-planning.d.ts +0 -16
- package/dist/environment/runtime-preparation.d.ts +0 -30
- package/dist/environment/runtime-service.d.ts +0 -18
- package/dist/environment/services.d.ts +0 -48
- package/dist/environment/state.d.ts +0 -18
- package/dist/environment/status-runtime.d.ts +0 -53
- package/dist/environment/template.d.ts +0 -180
- package/dist/evidence/artifact-config.d.ts +0 -14
- package/dist/evidence/artifact-validation.d.ts +0 -5
- package/dist/evidence/artifacts.d.ts +0 -75
- package/dist/evidence/bundles.d.ts +0 -27
- package/dist/evidence/ci-provenance.d.ts +0 -9
- package/dist/evidence/contracts.d.ts +0 -154
- package/dist/evidence/file-evidence.d.ts +0 -23
- package/dist/evidence/finalization.d.ts +0 -9
- package/dist/evidence/index.d.ts +0 -8
- package/dist/evidence/logs.d.ts +0 -31
- package/dist/evidence/operation-timings.d.ts +0 -60
- package/dist/evidence/read-bundle.d.ts +0 -4
- package/dist/evidence/read-fields.d.ts +0 -22
- package/dist/evidence/read-provenance.d.ts +0 -2
- package/dist/evidence/read-redaction.d.ts +0 -2
- package/dist/evidence/read-retention.d.ts +0 -2
- package/dist/evidence/read-run.d.ts +0 -2
- package/dist/evidence/reading.d.ts +0 -28
- package/dist/evidence/reporting-types.d.ts +0 -330
- package/dist/evidence/reporting.d.ts +0 -3
- package/dist/evidence/secure-file-copy.d.ts +0 -24
- package/dist/evidence/setup-progress.d.ts +0 -63
- package/dist/evidence/step-output.d.ts +0 -16
- package/dist/evidence/storage-inventory.d.ts +0 -27
- package/dist/evidence/storage.d.ts +0 -27
- package/dist/evidence/timing.d.ts +0 -23
- package/dist/file.d.ts +0 -11
- package/dist/index.d.ts +0 -4
- package/dist/kernel/error-serialization.d.ts +0 -38
- package/dist/kernel/redaction.d.ts +0 -2
- package/dist/kernel/unknown-values.d.ts +0 -6
- package/dist/kernel/work-metrics.d.ts +0 -6
- package/dist/process/capture-output.d.ts +0 -7
- package/dist/process/command-shell.d.ts +0 -1
- package/dist/process/environment-overlay.d.ts +0 -17
- package/dist/process/environment.d.ts +0 -33
- package/dist/process/files/contained-path.d.ts +0 -8
- package/dist/process/files/directory-status.d.ts +0 -14
- package/dist/process/files/dotenv.d.ts +0 -2
- package/dist/process/files/file-snapshot.d.ts +0 -34
- package/dist/process/files/json-file.d.ts +0 -12
- package/dist/process/files/paths.d.ts +0 -1
- package/dist/process/files/product-dir.d.ts +0 -1
- package/dist/process/files/temp-dir.d.ts +0 -11
- package/dist/process/host/metadata.d.ts +0 -6
- package/dist/process/host/platform.d.ts +0 -57
- package/dist/process/host-command.d.ts +0 -4
- package/dist/process/host-inspection-command.d.ts +0 -13
- package/dist/process/host-process.d.ts +0 -19
- package/dist/process/index.d.ts +0 -9
- package/dist/process/lifecycle-fence.d.ts +0 -11
- package/dist/process/locks.d.ts +0 -28
- package/dist/process/process-contracts.d.ts +0 -78
- package/dist/process/process-group.d.ts +0 -12
- package/dist/process/process-identity.d.ts +0 -27
- package/dist/process/process-limits.d.ts +0 -6
- package/dist/process/process.d.ts +0 -12
- package/dist/process/readiness.d.ts +0 -37
- package/dist/process/recovery.d.ts +0 -3
- package/dist/process/runs/inspection.d.ts +0 -5
- package/dist/process/runs/manifest.d.ts +0 -86
- package/dist/process/runs/ownership.d.ts +0 -11
- package/dist/process/runs/product-state.d.ts +0 -2
- package/dist/process/runs/schema.d.ts +0 -3
- package/dist/process/runs/stop.d.ts +0 -19
- package/dist/process/runtime-socket.d.ts +0 -4
- package/dist/process/service-processes.d.ts +0 -13
- package/dist/process/shutdown.d.ts +0 -10
- package/dist/process/windows-cli-owner.d.ts +0 -2
- package/dist/process/windows-native.d.ts +0 -6
- package/dist/process/windows-process-identity.d.ts +0 -4
- package/dist/repo/ci-environment.d.ts +0 -7
- package/dist/repo/fingerprint-policy.d.ts +0 -15
- package/dist/repo/git-path.d.ts +0 -2
- package/dist/repo/history.d.ts +0 -17
- package/dist/repo/managed-git.d.ts +0 -10
- package/dist/repo/metadata.d.ts +0 -3
- package/dist/repo/physical-tree.d.ts +0 -37
- package/dist/repo/remote.d.ts +0 -6
- package/dist/repo/state.d.ts +0 -26
- package/dist/repo/tree-listing.d.ts +0 -10
- package/dist/steps/build-config.d.ts +0 -35
- package/dist/steps/configured-step-testkit-modules.d.ts +0 -19
- package/dist/steps/configured-steps.d.ts +0 -51
- package/dist/steps/environment.d.ts +0 -84
- package/dist/steps/index.d.ts +0 -2
- package/dist/steps/module-runner.d.ts +0 -1
- package/dist/steps/run.d.ts +0 -36
- package/dist/toolchains/archive.d.ts +0 -53
- package/dist/toolchains/esbuild.d.ts +0 -9
- package/dist/toolchains/host-node-support.d.ts +0 -3
- package/dist/toolchains/index.d.ts +0 -114
- package/dist/toolchains/managed-node-releases.d.ts +0 -28
- package/dist/toolchains/node-cache.d.ts +0 -20
- package/dist/toolchains/node-integrity.d.ts +0 -18
- package/dist/toolchains/node-provisioning.d.ts +0 -29
- package/dist/toolchains/semver.d.ts +0 -13
- package/dist/toolchains/shared-operation.d.ts +0 -11
- package/dist/toolchains/timeouts.d.ts +0 -1
- package/dist/toolchains/vitest/index.d.ts +0 -13
- package/dist/tracker/gitea.d.ts +0 -14
- package/dist/tracker/github.d.ts +0 -14
- package/dist/tracker/http.d.ts +0 -33
- package/dist/tracker/index.d.ts +0 -4
- package/dist/tracker/redaction.d.ts +0 -4
- package/dist/tracker/requests.d.ts +0 -17
- package/dist/tracker/responses.d.ts +0 -24
- package/dist/tracker/types.d.ts +0 -51
- package/docs/engine-architecture.md +0 -654
- /package/dist/engines/{k6/runtime/runtime-globals.js → api/profiles.js} +0 -0
|
Binary file
|
|
Binary file
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export const BUG_FACTS_VERSION=1;function e(i,t,o=""){return{boundaryRule:o,definition:t,id:i}}export const BUG_CAUSES={field:"cause",question:"What kind of mistake is in the code?",assignmentRule:"A bug gets exactly one cause. When a bug holds several mistakes, classify the earliest one in the causal chain. Use `other` when none fits.",categories:[e("missing-validation","The code never checks an input or a state precondition that the domain rules require: range, format, existence, uniqueness, cross-field consistency, or lifecycle state. Includes a validator that exists and accepts invalid input.","Earliest mistake wins. If application code never tested the condition, it is `missing-validation` even when a database constraint or the runtime later throws and the caller sees
|
|
1
|
+
export const BUG_FACTS_VERSION=1;function e(i,t,o=""){return{boundaryRule:o,definition:t,id:i}}export const BUG_CAUSES={field:"cause",question:"What kind of mistake is in the code?",assignmentRule:"A bug gets exactly one cause. When a bug holds several mistakes, classify the earliest one in the causal chain. Use `other` when none fits.",categories:[e("missing-validation","The code never checks an input or a state precondition that the domain rules require: range, format, existence, uniqueness, cross-field consistency, or lifecycle state. Includes a validator that exists and accepts invalid input.","Earliest mistake wins. If application code never tested the condition, it is `missing-validation` even when a database constraint or the runtime later throws and the caller sees an unexpected error. If the unchecked value is null, absent, empty, zero, or a default, use `null-or-default-mishandling`."),e("mishandled-error","A failure was detected and signalled, and the handling is wrong: not caught, translated to the wrong error, swallowed, ignored by the UI, or followed by a wrong retry or recovery.","The failure must already be signalled by something that checked. If nothing in the application checked and a lower layer failed, it is `missing-validation`."),e("race-condition","Correctness depends on how overlapping operations interleave: check-then-act without a lock or constraint, a lost update, or a late asynchronous completion that overwrites newer state.","Needs two overlapping operations to reproduce. If one sequential flow reproduces it, it is `stale-state` or `missing-validation`."),e("unbounded-or-inefficient-work","Results are correct and the cost is unbounded or needlessly repeated: unpaginated reads, N+1 queries, a missing or redundant index, serial waits, or loading everything and then slicing.","Correct results at excessive cost. If the result is wrong, it is `incorrect-query-or-selection`."),e("incorrect-query-or-selection","The code identifies the wrong set of records: a missing or wrong predicate, unstable ordering, a truncated page treated as complete, duplicate rows from a join, or a lookup key that omits a distinguishing part.","A missing predicate is `missing-access-control` only when it separates actors or tenants with different rights. The right records with wrong arithmetic on them is `incorrect-logic`."),e("missing-access-control","A permission, tenant, ownership, or separation-of-duties check is absent or wrong.","Use it when the missing check is about who the actor is. A missing check about what the data or state is belongs in `missing-validation`."),e("null-or-default-mishandling","Null, absent, empty, zero, or default values are conflated or not handled: null treated as omitted, a zero or an empty collection treated as missing, a null dereference, a wrong fallback default, or a caller that omits an argument and silently gets the default.","Wins over `missing-validation` and `incorrect-logic` whenever the triggering value is null, absent, empty, zero, or a default."),e("stale-state","Held state, such as a cache, local UI state, a derived or denormalised value, or leftover fields, is not refreshed, reset, persisted, or tied to the right identity when the thing it mirrors changes.","If the omission leaves old values visible where current ones should be, it is `stale-state`. If the missing action leaves nothing stale, it is `omitted-step`. If it reproduces only with overlapping operations, it is `race-condition`."),e("interface-mismatch","Data is lost or misread where it crosses between representations or components. One component's mapping drops, overwrites, hardcodes, or mis-assigns fields, or two components that must agree disagree on shape, type, field names, allowed values, semantics, or which copy of the data is authoritative.","Use it when the values were right before the crossing. Wrong computation on values that arrived intact is `incorrect-logic`. A held copy that goes out of date after its source changes is `stale-state`. An omitted argument that falls back to a default is `null-or-default-mishandling`."),e("omitted-step","A required follow-on action is not performed on some path: an audit record, a notification, a dispatch, a finalisation, or an alternate route that bypasses the shared routine.","If the missing thing is a check, it is `missing-validation`. If its absence leaves old values on display, it is `stale-state`."),e("incorrect-logic","The algorithm, arithmetic, date or time handling, rounding, boundary, comparison, boolean condition, parsing, or order of operations is wrong.","The default for wrong logic on valid, present values. If the trigger is a null, empty, zero, or default value, use `null-or-default-mishandling`. If the fault is which records were chosen, use `incorrect-query-or-selection`."),e("other","No category above describes the mistake.")]},BUG_IMPACTS={field:"impact",question:"What is at stake for the business?",assignmentRule:"A bug gets exactly one impact. The list is in precedence order, and the first type that applies wins. Classify the impact the test demonstrated, not a downstream one you expect. Use `other` when none fits.",categories:[e("unauthorized-access","Someone can see or change something they are not entitled to, including getting past a separation-of-duties rule.","The actor lacks the right. If an entitled actor skips a mandated control or leaves no evidence, it is `audit-or-compliance-gap`."),e("financial-error","A monetary amount, rate, currency, limit, payment or settlement state, or a money-committing decision is wrong where it is stored, charged, paid, or decided.","A money figure that is only displayed wrongly, with the stored value and the decision intact, is `wrong-information-shown`."),e("audit-or-compliance-gap","Required audit evidence or attribution is missing, duplicated, or false, or a mandated control did not run.","Use it when the harm is to evidence or to a regulatory or policy control. A skipped ordinary process step is `workflow-breakdown`."),e("data-loss-or-corruption","Stored data, or work the user entered, is destroyed, overwritten, duplicated, or left invalid or inconsistent.","If the action silently did nothing and prior stored state is intact, it is `blocked-operation`."),e("workflow-breakdown","A business process, such as a workflow, task, schedule, notification, or gate, is skipped, stalled, duplicated, or advanced wrongly.","Use it when the process goes wrong after the triggering call returns. A single user action that fails in front of the user is `blocked-operation`."),e("availability-or-performance","The product is slow, unavailable, or exhausts resources in a way that affects more than the triggering call or grows with data volume.","One call that fails for one caller is `blocked-operation`."),e("blocked-operation","A legitimate action fails, returns an unusable or misleading error, or silently does not apply, with prior stored state intact.","The user was trying to do something and could not. If they were only reading and what they read was wrong, it is `wrong-information-shown`."),e("wrong-information-shown","Displayed or returned information is wrong, out of date, incomplete, or duplicated, with nothing stored wrongly.","Last in precedence. If the wrong value is also persisted, it is `data-loss-or-corruption`."),e("other","No type above describes what is at stake.")]},BUG_ESCAPES={field:"escape",question:"Why did the tests that existed before yours not catch the bug?",assignmentRule:"A bug gets exactly one reason. Judge the tests that were there before yours. Use `other` when none fits.",categories:[e("no-test","No existing test runs the faulty behaviour.","If any existing test reaches the faulty code path, use another reason."),e("untested-input","A test runs the behaviour and never with the input, state, or data volume that triggers the fault.","One sequential flow with the right input reproduces the bug. If it needs overlapping operations, it is `untested-interleaving`."),e("untested-interleaving","A test runs the behaviour in sequence, and the fault needs overlapping operations or a particular timing.","The triggering input is already covered, and only the overlap is missing."),e("wrong-assertion","A test runs the triggering case against the real code and passes, because its assertion is missing, too weak, or asserts the broken behaviour.","The faulty code ran in the test. If a stand-in ran in its place, it is `test-double`."),e("test-double","A test runs the triggering case against a test double or a fixture that hides the fault in the real component.","The real component would have failed the test."),e("other","No reason above applies.")]},BUG_SEVERITIES=["critical","high","medium","low"],BUG_CONFIDENCES=["high","low"],BUG_CATCHERS=["campaign","manual"];export function categoryIds(i){return i.categories.map(t=>t.id)}export function isOneOf(i,t){return typeof t=="string"&&i.some(o=>o===t)}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import k from"node:fs";import y from"node:path";import{readBugPolicy as
|
|
2
|
-
`),
|
|
1
|
+
import k from"node:fs";import y from"node:path";import{readBugPolicy as v}from"../../config/loader/bugs.js";import{loadTestkitConfig as g}from"../../config/loader/index.js";import{resolveCiProvenance as T}from"../../evidence/ci-provenance.js";import{loadLatestRun as h}from"../../evidence/reading.js";import{resolveTracker as w}from"../tracker/index.js";import{assessRun as q}from"./assessment.js";import{ciReportMarker as P,readCiContext as b,renderCiSummary as U}from"./ci-summary.js";import{describeRunOutcome as x}from"./known-failures.js";import{readRun as D}from"./run-reading.js";import{resolveBugCheckout as F}from"./store.js";const R="Testkit found no results for this commit";export async function reportCiRun(t){const r=b(t.context),e=await F(t),s=v((await g(e.productDir)).config),a={env:t.env,productDir:e.productDir};let u=null;const l=()=>(u??=w(a),u),{repository:m}=s,o=await q(B(e),m===null?l:()=>w({...a,repository:m})),n=x(o.outcome,s.knownFailures==="allow"),i=e.pullRequestHeadCommit??e.headCommit,c=T(t.env).runUrl,d=U({...o,commit:i,context:r,knownFailuresAllowed:s.knownFailures==="allow",runUrl:c,status:n}),C=I(t.env,d),p=await l();await p.setCommitStatus({...n,context:r,sha:i,targetUrl:c});const S=e.pullRequest===null?null:await p.upsertPullRequestComment({body:d,marker:P(r),pullRequest:e.pullRequest}),f=o.outcome.kind==="tests-failed"?o.outcome.classification:{known:[],new:[]};return{comment:S,commit:i,context:r,description:n.description,known:f.known,new:f.new,pullRequest:e.pullRequest,state:n.state,stepSummary:C,trackerProblem:o.trackerProblem,unreadableIssues:o.unreadableIssues}}function B(t){if(!k.existsSync(y.join(t.productDir,".testkit","results","latest.json")))return{kind:"run-failed",reason:R};const r=h(t.productDir);return r.git.commitSha!==t.headCommit?{kind:"run-failed",reason:R}:D(r,t.productPath)}function I(t,r){const e=t.GITHUB_STEP_SUMMARY?.trim()??"";return e.length===0?null:(k.appendFileSync(e,`${r}
|
|
2
|
+
`),e)}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import"./known-failures.js";import{redactBugText as T,redactRunResultText as I}from"../../tracker/redaction.js";export const DEFAULT_CI_CONTEXT="testkit";const k=/^[A-Za-z0-9][A-Za-z0-9 ._/:-]{0,59}$/u,p=12,l=50,b=10,d=160,w=/^https?:\/\/[^\s()<>]+$/u;export function readCiContext(e){if(e===void 0)return DEFAULT_CI_CONTEXT;if(!k.test(e)||e!==e.trim())throw new Error(`--context must be 1 to 60 characters, start with an ASCII letter or a digit, not end with a space, and hold only ASCII letters, digits, spaces, and the characters . _ / : and -. Received ${JSON.stringify(e)}.`);return e}export function ciReportMarker(e){return e===DEFAULT_CI_CONTEXT?"<!-- testkit-ci-report -->":`<!-- testkit-ci-report:${e} -->`}export function renderCiSummary(e){const{context:t,outcome:n}=e,r=[ciReportMarker(t),t===DEFAULT_CI_CONTEXT?"## Testkit":`## Testkit: ${t}`,E(e),`Commit \`${e.commit.slice(0,p)}\`.${h("CI run",e.runUrl," ",".")}`];if(n.kind==="tests-failed"){const{known:a,new:i}=n.classification;if(i.length>0&&r.push("### New failures",f(i.map(s=>`- ${c(s.file)}: ${$(s)}`))),a.length>0&&r.push("### Known failures",f(a.map(({failure:s,issue:o})=>`- ${c(s.file)}: ${$(s)}, ${g(o.issue,o.url)}`))),e.trackerProblem!==null&&r.push(`Testkit could not read the open bugs, so every failure counts as new. ${m(e.trackerProblem,400)}`),e.unreadableIssues.length>0){const s=e.unreadableIssues.slice(0,b).map(u=>g(u.number,u.url)),o=e.unreadableIssues.length-s.length;r.push(`Testkit cannot read the facts block of ${_(e.unreadableIssues.length,"open `testkit` issue")}, so ${e.unreadableIssues.length===1?"it matches":"they match"} no test: ${s.join(", ")}${o>0?`, and ${String(o)} more`:""}.`)}}return`${r.join(`
|
|
2
2
|
|
|
3
3
|
`)}
|
|
4
|
-
`}function
|
|
5
|
-
`)}function h(e,n
|
|
4
|
+
`}function E({knownFailuresAllowed:e,outcome:t,status:n}){return t.kind==="passed"?`${n.description}.`:t.kind==="run-failed"?`The run failed outside its tests. ${c(t.reason,400)}`:t.classification.new.length>0?`${n.description}.`:e?`${n.description}. Every failure is a known bug and \`bugs.knownFailures\` is \`"allow"\`, so the run passes.`:`${n.description}. Every failure is a known bug, and \`bugs.knownFailures\` is \`"fail"\`, so the run fails.`}function f(e){const t=e.length-l;return[...e.slice(0,l),...t>0?[`- and ${String(t)} more`]:[]].join(`
|
|
5
|
+
`)}function h(e,t,n="",r=""){return t!==null&&w.test(t)?`${n}[${e}](${t})${r}`:""}function $(e){return e.title===null?"failed without naming a test":c(e.title)}function g(e,t){const n=`#${String(e)}`;return h(n,t)||n}function _(e,t){return`${String(e)} ${t}${e===1?"":"s"}`}function c(e,t=d){return m(I(e),t)}function m(e,t=d){const n=Array.from(T(e.replace(/\s+/gu," ").trim())),r=n.length>t?`${n.slice(0,t-3).join("")}...`:n.join("");if(r.length===0)return"an empty name";const a=Math.max(0,...[...r.matchAll(/`+/gu)].map(s=>s[0].length)),i="`".repeat(a+1);return r.startsWith("`")||r.endsWith("`")?`${i} ${r} ${i}`:`${i}${r}${i}`}
|
package/dist/app/bugs/draft.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import G from"node:crypto";import
|
|
2
|
-
${n.map(
|
|
3
|
-
`)}`),this.name="BugRecordError",this.problems=n}}export function isCampaignId(t){return typeof t=="string"&&t.length<=CAMPAIGN_ID_MAX_LENGTH&&
|
|
4
|
-
${t.test.title}`).digest("hex");return`${e||"bug"}-${n.slice(0,8)}`}export function isBugDraftId(t){return typeof t=="string"&&/^[a-z0-9]+(?:-[a-z0-9]+)*-[0-9a-f]{8}$/u.test(t)}export function namesSameTest(t,e){return t.test.file===e.test.file&&t.test.title===e.test.title}function I(t,e,n){const
|
|
1
|
+
import G from"node:crypto";import A from"node:path";import{isPublicTestType as j}from"../../domain/identifiers.js";import{isUnknownRecord as g}from"../../kernel/unknown-values.js";import{BUG_CATCHERS as O,BUG_CAUSES as P,BUG_CONFIDENCES as C,BUG_ESCAPES as U,BUG_IMPACTS as F,BUG_SEVERITIES as R,categoryIds as _,isOneOf as E}from"./categories.js";import{BUG_FACTS_TEST_TYPES as z,decodeFaultLines as D,isCommitId as $}from"./facts.js";import{redactBugText as B}from"../../tracker/redaction.js";import{isTimestamp as w}from"../campaigns/campaign.js";export const BUG_DRAFT_SCHEMA_VERSION=1,BUG_TITLE_MAX_LENGTH=200,BUG_SECTION_MAX_LENGTH=12e3;const V=48,L=/^[a-z0-9]+(?:-[a-z0-9]+)*$/u;export const CAMPAIGN_ID_MAX_LENGTH=60;export class BugRecordError extends Error{problems;constructor(e,n){super(`${e}:
|
|
2
|
+
${n.map(s=>`- ${s}`).join(`
|
|
3
|
+
`)}`),this.name="BugRecordError",this.problems=n}}export function isCampaignId(t){return typeof t=="string"&&t.length<=CAMPAIGN_ID_MAX_LENGTH&&L.test(t)}export function testTypeOfFile(t){const e=/\.([a-z0-9]+)\.testkit\.ts$/u.exec(t)?.[1];return j(e)?e:null}function M(t){const e=/\.([a-z0-9]+)\.testkit\.ts$/u.exec(t)?.[1];return z.find(n=>n===e)??null}export function toRepositoryPath(t,e){const n=e.replaceAll("\\","/");if(n.startsWith("/")||/^[a-z]:/iu.test(n))return null;const s=A.posix.normalize(A.posix.join(t,n));return s==="."||s===".."||s.startsWith("../")?null:s}export function toProductPath(t,e){return t===""?e:A.posix.relative(t,e)}export function readBugReport(t,e){if(!g(t))throw new BugRecordError("The bug record is invalid",["it must be a JSON object"]);const n=[],s=[],u=I(t,n,{path:r=>toRepositoryPath(e,r),text:(r,d)=>{const a=B(r);return a!==r&&s.push(d),a}});if(n.length>0)throw new BugRecordError("The bug record is invalid",n);return{redactedFields:s,report:u}}export function createBugDraft(t,e){const n=testTypeOfFile(t.test.file);return{schemaVersion:BUG_DRAFT_SCHEMA_VERSION,id:bugDraftId(t),recordedAt:e.recordedAt.toISOString(),recordedCommit:e.recordedCommit,productPath:e.productPath,caughtBy:e.campaign===null?"manual":"campaign",...e.campaign===null?{}:{campaign:e.campaign},...n===null?{}:{testType:n},...e.vitest===void 0?{}:{vitest:e.vitest},...t}}export function requireOneVitestProject(t,e,n){if(e.length<2||n.project!==null)return;const s=e.map(({project:u})=>JSON.stringify(u)).join(", ");throw new Error(`test.file ${t} runs in the Vitest projects ${s}. Name the one whose run fails with --vitest-project.`)}export function readBugDraft(t){const e="The bug draft is unreadable";if(!g(t))throw new BugRecordError(e,["it must be a JSON object"]);if(t.schemaVersion!==BUG_DRAFT_SCHEMA_VERSION)throw new BugRecordError(e,[`unknown schemaVersion ${JSON.stringify(t.schemaVersion)}`]);const n=[],s=(p,b,y,x)=>b(p)?p:(n.push(x),y),u=I(t,n,{path:p=>toRepositoryPath("",p),text:p=>p}),r=M(u.test.file);t.testType!==(r??void 0)&&n.push(r===null?"testType must be absent for a test file without a type":"testType does not match test.file");const d=s(t.caughtBy,J,"manual","caughtBy must be campaign or manual"),a=s(t.campaign,k,void 0,"campaign must be a campaign id");d==="campaign"!=(a!==void 0)&&n.push("campaign must be present when caughtBy is campaign and absent otherwise");const T={schemaVersion:BUG_DRAFT_SCHEMA_VERSION,id:s(t.id,isBugDraftId,"","id is not a draft id"),recordedAt:s(t.recordedAt,w,"","recordedAt must be a timestamp"),recordedCommit:s(t.recordedCommit,$,"","recordedCommit must be a full commit id"),productPath:s(t.productPath,N,"","productPath must be a string"),caughtBy:d,...a===void 0?{}:{campaign:a},...r===null?{}:{testType:r},...t.vitest===void 0?{}:{vitest:s(t.vitest,X,{},"vitest must hold runner, config and project text")},...u,...t.filed===void 0?{}:{filed:H(t.filed,n)}};if(n.length>0)throw new BugRecordError(e,n);return T}export function bugDraftId(t){const e=t.title.normalize("NFKD").replace(/\p{M}+/gu,"").toLowerCase().replace(/[^a-z0-9]+/gu,"-").slice(0,V).replace(/^-+|-+$/gu,""),n=G.createHash("sha256").update(`${t.test.file}
|
|
4
|
+
${t.test.title}`).digest("hex");return`${e||"bug"}-${n.slice(0,8)}`}export function isBugDraftId(t){return typeof t=="string"&&/^[a-z0-9]+(?:-[a-z0-9]+)*-[0-9a-f]{8}$/u.test(t)}export function namesSameTest(t,e){return t.test.file===e.test.file&&t.test.title===e.test.title}function I(t,e,n){const s=(i,o,c,f)=>{const m=i[o];if(typeof m!="string"||m.trim().length===0)return e.push(`${c} must be a non-empty string`),"";const h=m.trim(),l=h.length>f?h:n.text(h,c);return l.length>f&&e.push(`${c} must be at most ${String(f)} characters`),l},u=(i,o,c)=>{const f=i[o],m=typeof f=="string"?f.trim():"",h=m.length>0?n.path(m):null;return h===null?e.push(`${c} must be a path inside the repository`):[m,h].some(l=>B(l)!==l)&&e.push(`${c} is a path that holds text Testkit redacts as a secret`),h??""},r=(i,o,c)=>E(i,o)?o:(e.push(`${c} must be one of ${i.join(", ")}`),i[0]),d=i=>{const o=t[i];return g(o)?o:(e.push(`${i} must be an object`),{})},a=(i,o,c)=>{const f=s(i,o,c,BUG_TITLE_MAX_LENGTH);return/[\r\n]/u.test(f)&&e.push(`${c} must be one line`),f},T=a(t,"title","title"),p=d("test"),b=d("fault"),y=d("confidence"),x=u(p,"file","test.file");let S=[1,1];try{S=D(b.lines)}catch(i){e.push(i instanceof Error?i.message:"fault.lines is invalid")}return{title:T,severity:r(R,t.severity,"severity"),expected:s(t,"expected","expected",BUG_SECTION_MAX_LENGTH),authority:s(t,"authority","authority",BUG_SECTION_MAX_LENGTH),observed:s(t,"observed","observed",BUG_SECTION_MAX_LENGTH),rootCause:s(t,"rootCause","rootCause",BUG_SECTION_MAX_LENGTH),test:{file:x,title:a(p,"title","test.title")},fault:{lines:S,path:u(b,"path","fault.path")},cause:r(_(P),t.cause,"cause"),impact:r(_(F),t.impact,"impact"),confidence:{cause:r(C,y.cause,"confidence.cause"),impact:r(C,y.impact,"confidence.impact")},escape:r(_(U),t.escape,"escape")}}function H(t,e){return g(t)&&w(t.filedAt)&&$(t.foundAt)&&typeof t.number=="number"&&Number.isSafeInteger(t.number)&&t.number>=1&&typeof t.url=="string"?{filedAt:t.filedAt,foundAt:t.foundAt,number:t.number,url:t.url}:(e.push("filed must hold filedAt, foundAt, number, and url"),{filedAt:"",foundAt:"",number:0,url:""})}function k(t){return t===void 0||isCampaignId(t)}function J(t){return E(O,t)}function X(t){return g(t)&&Object.values(t).every(N)}function N(t){return typeof t=="string"}
|
package/dist/app/bugs/facts.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{isAreaId as
|
|
2
|
-
`)}export function readFactsBlock(e){const t=e.lastIndexOf(FACTS_START_MARKER);if(t===-1)return{status:"missing"};const
|
|
1
|
+
import{isAreaId as w}from"../../config/loader/bugs.js";import{isUnknownRecord as m}from"../../kernel/unknown-values.js";import{BUG_CATCHERS as E,BUG_CAUSES as S,BUG_CONFIDENCES as p,BUG_ESCAPES as b,BUG_FACTS_VERSION as h,BUG_IMPACTS as T,categoryIds as s,isOneOf as A}from"./categories.js";export const FACTS_START_MARKER="<!-- testkit-facts:start -->",FACTS_END_MARKER="<!-- testkit-facts:end -->";const B=/^(?:[0-9a-f]{40}|[0-9a-f]{64})$/u;export const BUG_FACTS_TEST_TYPES=Object.freeze(["ui","e2e","int","contract","data","dal","load"]);export function renderFactsBlock(e){return["<details>","<summary>Testkit facts</summary>","",FACTS_START_MARKER,"","```json",JSON.stringify(l(e),null,2),"```","",FACTS_END_MARKER,"","</details>"].join(`
|
|
2
|
+
`)}export function readFactsBlock(e){const t=e.lastIndexOf(FACTS_START_MARKER);if(t===-1)return{status:"missing"};const r=t+FACTS_START_MARKER.length,n=e.indexOf(FACTS_END_MARKER,r);if(n===-1)return{status:"invalid",reason:"the facts block has no end marker"};const d=/```[^\n]*\r?\n([\s\S]*?)\r?\n[ \t]*```/u.exec(e.slice(r,n));if(d===null)return{status:"invalid",reason:"the facts block has no fenced code block"};let u;try{u=JSON.parse(d[1])}catch{return{status:"invalid",reason:"the facts block is not valid JSON"}}try{return{facts:_(u),status:"ok"}}catch(f){return{status:"invalid",reason:f instanceof Error?f.message:"the facts block is invalid"}}}export function isCommitId(e){return typeof e=="string"&&B.test(e)}function _(e){if(!m(e))throw new Error("the facts block is not a JSON object");if(e.v!==h)throw new Error(`unknown facts version ${JSON.stringify(e.v)}`);const t=c(e.confidence,"confidence"),r=c(e.test,"test");return l({v:h,cause:o(s(S),e.cause,"cause"),impact:o(s(T),e.impact,"impact"),confidence:{cause:o(p,t.cause,"confidence.cause"),impact:o(p,t.impact,"confidence.impact")},escape:i(e.escape,n=>o(s(b),n,"escape")),caughtBy:o(E,e.caughtBy,"caughtBy"),campaign:i(e.campaign,n=>a(n,"campaign")),testType:i(e.testType,n=>o(BUG_FACTS_TEST_TYPES,n,"testType")),test:{file:a(r.file,"test.file"),title:i(r.title,n=>a(n,"test.title"))},foundAt:y(e.foundAt,"foundAt"),fault:i(e.fault,k),area:i(e.area,O),introducedBy:i(e.introducedBy,n=>y(n,"introducedBy")),introducedMethod:i(e.introducedMethod,n=>o(["blame"],n,"introducedMethod"))})}function k(e){const t=c(e,"fault");return{lines:i(t.lines,decodeFaultLines),path:a(t.path,"fault.path")}}export function decodeFaultLines(e){if(!Array.isArray(e)||e.length!==2)throw new Error("fault.lines must be [start, end]");const t=e,[r,n]=t;if(!g(r)||!g(n)||r>n)throw new Error("fault.lines must be two line numbers counted from 1, with start no greater than end");return[r,n]}function O(e){const t=c(e,"area");if(!w(t.id))throw new Error("area.id is not an area id");const r=t.share;if(typeof r!="number"||!Number.isFinite(r)||r<0||r>1)throw new Error("area.share must be a number from 0 to 1");return{id:t.id,name:a(t.name,"area.name"),share:r}}function l(e){return{v:e.v,cause:e.cause,impact:e.impact,confidence:{cause:e.confidence.cause,impact:e.confidence.impact},...e.escape===void 0?{}:{escape:e.escape},caughtBy:e.caughtBy,...e.campaign===void 0?{}:{campaign:e.campaign},...e.testType===void 0?{}:{testType:e.testType},test:{file:e.test.file,...e.test.title===void 0?{}:{title:e.test.title}},foundAt:e.foundAt,...e.fault===void 0?{}:{fault:{path:e.fault.path,...e.fault.lines===void 0?{}:{lines:e.fault.lines}}},...e.area===void 0?{}:{area:{id:e.area.id,name:e.area.name,share:e.area.share}},...e.introducedBy===void 0?{}:{introducedBy:e.introducedBy},...e.introducedMethod===void 0?{}:{introducedMethod:e.introducedMethod}}}function i(e,t){return e===void 0?void 0:t(e)}function c(e,t){if(!m(e))throw new Error(`${t} must be an object`);return e}function a(e,t){if(typeof e!="string"||e.trim().length===0)throw new Error(`${t} must be a non-empty string`);return e}function o(e,t,r){if(!A(e,t))throw new Error(`${r} must be one of ${e.join(", ")}`);return t}function y(e,t){if(!isCommitId(e))throw new Error(`${t} must be a full lowercase commit id`);return e}function g(e){return typeof e=="number"&&Number.isSafeInteger(e)&&e>=1}
|
package/dist/app/bugs/file.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import
|
|
1
|
+
import b from"node:fs";import p from"node:path";import{readAreaMap as C,readBugPolicy as O}from"../../config/loader/bugs.js";import{loadTestkitConfig as D}from"../../config/loader/index.js";import{findIntroducingCommit as j,listRemoteRefsContaining as x,listUncommittedTrackedFiles as B}from"../../repo/history.js";import{listCommitFiles as N}from"../../repo/tree-listing.js";import{resolveTracker as _}from"../tracker/index.js";import{isTypedTestFile as P}from"../../domain/identifiers.js";import{rejectRetiredTestFile as L}from"../../domain/retired-test-types.js";import{listPlainVitestFiles as M,resolveVitestSelection as J}from"../../engines/catalog.js";import{resolveFaultArea as q}from"./areas.js";import{requireOneVitestProject as K,toProductPath as g}from"./draft.js";import{FACTS_END_MARKER as U,FACTS_START_MARKER as V,readFactsBlock as W,renderFactsBlock as T}from"./facts.js";import{bugFacts as G,bugLabels as H,renderBugIssue as Q,reproduceCommand as y,TESTKIT_LABEL as z}from"./issue.js";import{findKnownTest as X,readKnownTests as Y}from"./known-failures.js";import{holdsRedaction as Z,redactBugText as w}from"../../tracker/redaction.js";import{readEnvironmentFile as E}from"../environments/environment-file.js";import{resolveSuppliedInput as k,suppliedBindings as tt}from"../environments/supplied-input.js";import{suppliedReproduceArgs as et}from"./supplied-reproduce.js";import{bugDraftFile as rt,displayPath as v,readStoredDrafts as it,resolveBugCheckout as st,writeJsonFile as ot}from"./store.js";const nt=12,R=10;export async function prepareBugFiling(t){const i=et(t.supplied??{}),e=await st(t),{draft:r,file:s}=lt(e,t.id);if(r.filed!==void 0)return{draft:r,issue:{number:r.filed.number,url:r.filed.url},status:"already-filed"};L(r.test.file),requireNoSecretInCommand(r),t.supplied!==void 0&&at(t.supplied,e,t.env);const o=I(e.headCommit),a=await N(e.repoRoot,e.headCommit);for(const c of[r.test.file,r.fault.path])if(!a.some(m=>m.path===c))throw new Error(`${c} is not in commit ${o}. Commit it and push the commit, then run this again.`);const l=(await B(e.repoRoot)).filter(c=>!ut(e,c));if(l.length>0)throw new Error(`Tracked files have uncommitted changes: ${ft(l)}. The issue says that the test fails at ${o}, so commit or discard the changes first.`);if((await x(e.repoRoot,e.headCommit)).length===0)throw new Error(`No remote branch contains commit ${o}. Push it, then run this again. The issue points readers to the test at that commit.`);const{config:u}=await D(e.productDir),d=dt(q(C(u),a,r.fault.path),r.fault.path),n=await j(e.repoRoot,e.headCommit,r.fault.path,r.fault.lines),f=await _({env:t.env,productDir:e.productDir,repository:O(u).repository??void 0});return F(await S(f),r.test),{checkout:e,draft:r,draftFile:s,filing:{area:d,foundAt:e.headCommit,introducedBy:n.status==="found"?n.commit:null},reproduceArgs:i,status:"ready",testFile:p.join(e.productDir,g(e.productPath,r.test.file)),tracker:f}}export async function bugRerun(t,i,e={},r=process.env){const{checkout:s,draft:o}=t,a=Object.entries(i).filter(([h,A])=>h.startsWith("vitest-")&&typeof A=="string"),l={...o.vitest,...Object.fromEntries(a)},u=Object.keys(l).length===0?o:{...o,vitest:l};requireNoSecretInCommand(u);const d=e.environmentFile,n=k(e,d===void 0?null:E(d,s.cwd),r),f=J(l,s.productDir,r),c=g(s.productPath,o.test.file),m=P(c)?[]:await M(s.productDir,{...f,host:{...f.host,...tt(n)}}),$=m.filter(h=>h.file===c);return K(o.test.file,$,f),{files:{...r,...n.env}.TESTKIT_REQUIRE_COMPLETE_SUITE==="1"&&$.length>0?[...new Set(m.map(({file:h})=>p.join(s.productDir,h)))]:[t.testFile],ready:{...t,draft:u}}}export async function fileBug(t,i,e={}){const{checkout:r,draft:s,filing:o,reproduceArgs:a,tracker:l}=t,u=requireRecordedFailure(s,i,I(r.headCommit),a);F(await S(l),u);const d=renderReadableBugIssue(s,o,a);await l.ensureLabels(H(s.severity,o.area));const n=await l.createIssue(d),f={...s,filed:{filedAt:(e.at??new Date).toISOString(),foundAt:o.foundAt,number:n.number,url:n.url}};return ot(t.draftFile,f),{area:o.area,covers:"test",draft:f,introducedBy:o.introducedBy,issue:{number:n.number,url:n.url},path:v(r,t.draftFile)}}export function renderReadableBugIssue(t,i,e=[]){const r=Q(t,i,e),s=W(r.body),o=T(G(t,i));if(s.status==="ok"&&T(s.facts)===o)return r;throw new Error(`Testkit cannot read back the facts of the issue it would file, so it files nothing. This happens when test.title, test.file, fault.path, or the area's name holds ${V} or ${U}. Rename the test, the file, or the area, then record the bug again.`)}export function requireNoSecretInCommand(t){const i=y(t);if(w(i)!==i)throw new Error("The command that reproduces this bug holds text that Testkit redacts as a secret, and an issue carries that command. The text is in the path of the product directory, in the test's path from that directory, or in a --vitest-config or --vitest-project selector. Rename what holds it, commit and push the change, then record the bug again.")}function at(t,i,e){const r=t.environmentFile;if(r!==void 0&&!p.isAbsolute(r)&&b.realpathSync.native(i.cwd)!==b.realpathSync.native(i.repoRoot))throw new Error(`The issue's reproduce command runs from the repository root, but --environment-file ${r} is relative to ${i.cwd}. Run testkit bug file from ${i.repoRoot}, or pass the file's absolute path.`);k(t,r===void 0?null:E(r,i.cwd),e)}export function requireRecordedFailure(t,i,e,r=[]){const{file:s,title:o}=t.test,a=`\`${y(t,r)}\``;if(i.kind==="passed")throw new Error(`${s} passed at ${e}, so Testkit has no failure to file. ${a} must fail.`);if(i.kind==="run-failed")throw new Error(`${a} failed outside its tests at ${e}: ${i.reason.replace(/\.?$/u,".")} Testkit files a bug when the test itself fails.`);const l=i.failures.filter(n=>n.file===s);if(l.length===0)throw new Error(`${a} failed at ${e}, but ${s} is not among the files that failed.`);const u=l.flatMap(n=>n.title===null?[]:[n.title]),d=u.filter(n=>!/[\r\n]/u.test(n)&&!Z(n)&&w(n)===n);if(d.includes(o)){if(l.some(n=>n.title===o&&n.ambiguous===!0))throw new Error(`${s} has more than one test titled ${JSON.stringify(o)} at ${e}. An issue names its test by file and title, so it could not say which of them failed. Give each test in the file its own title, commit and push the change, then record the bug again.`);return{file:s,title:o}}if(u.length>0){const n=u.length-d.length;throw new Error([`${s} failed at ${e}, but not under the title ${JSON.stringify(o)}.`,...d.length===0?[]:[`Testkit reported ${d.map(f=>JSON.stringify(f)).join(", ")}. Set test.title to the title Testkit reports, then record the bug again.`],...n===0?[]:[`Testkit ${d.length===0?"":"also "}reported ${n===1?"1 title that spans lines or holds":`${String(n)} titles that span lines or hold`} text it redacts as a secret. It files no bug under such a title. Rename the test, or label the assertion, so that its title is one line and holds no such text.`]].join(" "))}throw new Error(`${s} failed at ${e} without reaching a result, so Testkit cannot tell that ${JSON.stringify(o)} failed. A file fails this way when it crashes, times out, or does not load. Make the test fail on its assertion, then run this again.`)}async function S(t){return Y(await t.listOpenIssues(z)).tests}function F(t,i){const e=X(t,i);if(e===null)return;const r=`Open issue #${String(e.issue)}`;throw new Error(e.title===null?`${r} already covers the whole file ${i.file}: ${e.url}. While it is open, Testkit files no other bug for that file.`:`${r} already covers this test: ${e.url}. Testkit keeps one open bug for each test.`)}function lt(t,i){const e=it(t.productDir),r=e.drafts.find(a=>a.draft.id===i);if(r!==void 0)return r;const s=e.unreadable.find(a=>a.file===rt(t.productDir,i));if(s!==void 0)throw new Error(`Testkit cannot read ${v(t,s.file)}: ${s.problem}. Record the bug again with \`testkit bug record\`.`);const o=e.drafts.filter(a=>a.draft.filed===void 0).map(a=>a.draft.id);throw new Error(o.length===0?`No bug draft has the id ${JSON.stringify(i)}, and this checkout has no unfiled draft. Record the bug with \`testkit bug record\` first.`:`No bug draft has the id ${JSON.stringify(i)}. Unfiled drafts: ${o.join(", ")}.`)}function dt(t,i){if(t.status==="no-map")return null;const e="Fix `areas` in testkit.config.ts, commit and push the change, then run this again.";if(t.status==="resolved"){const{area:r}=t;if(w(r.name)===r.name)return r;throw new Error(`areas.${r.id}.name holds text that Testkit redacts as a secret, and an issue carries its area's name. ${e}`)}throw new Error(t.status==="unclaimed"?`No area claims ${i}. Every bug needs its fault in one area. ${e}`:`The areas ${t.areas.join(" and ")} both claim ${i}. A file belongs to one area. ${e}`)}function ut(t,i){return g(t.productPath,i).startsWith(".testkit/")}function ft(t){const i=t.length-R;return`${t.slice(0,R).join(", ")}${i>0?`, and ${String(i)} more`:""}`}function I(t){return t.slice(0,nt)}
|
package/dist/app/bugs/gate.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{readBugPolicy as
|
|
1
|
+
import{readBugPolicy as d}from"../../config/loader/bugs.js";import{loadTestkitConfig as m}from"../../config/loader/index.js";import{resolveTracker as p}from"../tracker/index.js";import{assessRun as w}from"./assessment.js";import{readRunArtifact as k}from"./run-reading.js";import{resolveBugCheckout as g}from"./store.js";const h=1;export async function loadBugPolicy(o){return d((await m(o)).config)}export async function applyKnownFailures(o){const{env:e,exitCode:r,policy:t,productDir:n}=o,i={exitCode:r,knownFailures:null};if(t.knownFailures!=="allow"||r!==h||o.failedOutsideTests)return i;const l=await g({dir:n,env:e}).catch(()=>null),u=k(o.run,l?.productPath??""),{outcome:a,trackerProblem:f}=await w(u,()=>p({env:e,productDir:n,repository:t.repository??void 0}));if(a.kind!=="tests-failed")return i;const{known:s,new:c}=a.classification;return{exitCode:c.length===0&&s.length>0?0:r,knownFailures:{known:s,new:c,trackerProblem:f}}}
|
package/dist/app/bugs/guide.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import{BUG_CAUSES as
|
|
1
|
+
import{BUG_CAUSES as i,BUG_CONFIDENCES as u,BUG_ESCAPES as a,BUG_IMPACTS as s,BUG_SEVERITIES as o}from"./categories.js";import{BUG_TITLE_MAX_LENGTH as r}from"./draft.js";import{SEVERITY_LABELS as h}from"./issue.js";export const BUG_RECORD_EXAMPLE={title:"A refund pays out twice when two requests overlap",severity:"high",expected:"A refund pays out once.",authority:'`docs/refunds.md`, "Refunds are idempotent on the order id".',observed:"Two overlapping refund requests for one order both pay out.",rootCause:"`refund()` reads the order's refund state and writes the payout without a lock.",test:{file:"src/checkout/__testkit__/refund.contract.testkit.ts",title:"a refund pays out once"},fault:{path:"src/checkout/refunds.ts",lines:[41,58]},cause:"race-condition",impact:"financial-error",confidence:{cause:"high",impact:"high"},escape:"no-test"};const c=e=>e.map(t=>`\`${t}\``).join(", "),d=e=>`One of ${c(u)}. How sure you are of the ${e}.`,n=e=>({meaning:`One id from the ${e.field} list below.`,name:e.field});export const BUG_GUIDE={fields:[{name:"title",meaning:`One line of at most ${String(r)} characters that names the broken behaviour. It becomes the issue title.`},{name:"severity",meaning:`One of ${c(o)}. The severities are defined below.`},{name:"expected",meaning:"What the product should do."},{name:"authority",meaning:"The source that says so: documentation, a specification, an API contract, or the code's own stated intent. Name it and quote the part that applies."},{name:"observed",meaning:"What the product does instead."},{name:"rootCause",meaning:"Why the code behaves this way."},{name:"test.file",meaning:"The Testkit test file that fails because of the bug."},{name:"test.title",meaning:`The failure's title. It is one line of at most ${String(r)} characters.`},{name:"fault.path",meaning:"The source file that holds the mistake."},{name:"fault.lines",meaning:"The first and last faulty line as `[start, end]`, counted from 1. One faulty line is `[41, 41]`."},n(i),n(s),{name:"confidence.cause",meaning:d("cause")},{name:"confidence.impact",meaning:d("impact")},n(a)],rules:["Write `test.file` and `fault.path` relative to the product directory, the directory that holds `testkit.config.ts`.","`test.title` must be the failure's title exactly as Testkit reports it. In a Vitest or Playwright file, that is the names of the `describe` blocks around the test and the test's own name, joined by single spaces. When `testkit bug file` rejects the title, its message lists the titles a bug record can use.","Keep credentials, tokens, and passwords out of the record. Testkit redacts the secrets it recognises before it stores the record and again before it files the issue. It files no bug under a failure's title that holds text it redacts, so rename such a test or label such an assertion first."],example:BUG_RECORD_EXAMPLE,severities:o.map(e=>({definition:h[e].description,id:e})),categoryLists:[i,s,a]};export function renderBugGuide(e){return["## Bug record","Write one JSON object for each confirmed bug. Every field is required.",e.fields.map(t=>`- \`${t.name}\`: ${t.meaning}`).join(`
|
|
2
2
|
`),...e.rules,"Example:",["```json",JSON.stringify(e.example,null,2),"```"].join(`
|
|
3
3
|
`),"## Severities",e.severities.map(t=>`- \`${t.id}\`: ${t.definition}`).join(`
|
|
4
|
-
`),...e.categoryLists.flatMap(
|
|
4
|
+
`),...e.categoryLists.flatMap(l)].join(`
|
|
5
5
|
|
|
6
|
-
`)}function
|
|
6
|
+
`)}function l(e){return[`## ${e.field.charAt(0).toUpperCase()}${e.field.slice(1)}`,`The \`${e.field}\` field answers one question. ${e.question}`,e.assignmentRule,e.categories.map(t=>[`- \`${t.id}\`: ${t.definition}`,...t.boundaryRule===""?[]:[` Boundary rule: ${t.boundaryRule}`]].join(`
|
|
7
7
|
`)).join(`
|
|
8
8
|
`)]}
|
package/dist/app/bugs/issue.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import{toProductPath as
|
|
2
|
-
`),[
|
|
3
|
-
`),p(bugFacts(o,t
|
|
1
|
+
import{toProductPath as l}from"./draft.js";import{renderFactsBlock as p}from"./facts.js";import{redactBugText as n}from"../../tracker/redaction.js";export const TESTKIT_LABEL="testkit",SEVERITY_LABEL_PREFIX="severity:",AREA_LABEL_PREFIX="area:";const d={color:"0f766e",description:"Filed by Testkit with a regression test.",name:TESTKIT_LABEL};export const SEVERITY_LABELS={critical:{color:"9f1239",description:"The product is unsafe to run or to trust."},high:{color:"e11d48",description:"A core behaviour is broken with no acceptable workaround."},medium:{color:"d97706",description:"A behaviour is broken and a workaround exists, or the reach is limited."},low:{color:"4d7c0f",description:"A minor defect with little consequence."}};const m="475569";export function bugLabels(e,t){return[d,{...SEVERITY_LABELS[e],name:`${SEVERITY_LABEL_PREFIX}${e}`},...t===null?[]:[{color:m,description:t.name,name:`${AREA_LABEL_PREFIX}${t.id}`}]]}export function bugFacts(e,t){return{v:1,cause:e.cause,impact:e.impact,confidence:e.confidence,escape:e.escape,caughtBy:e.caughtBy,...e.campaign===void 0?{}:{campaign:e.campaign},...e.testType===void 0?{}:{testType:e.testType},test:e.test,foundAt:t.foundAt,fault:e.fault,...t.area===null?{}:{area:t.area},...t.introducedBy===null?{}:{introducedBy:t.introducedBy,introducedMethod:"blame"}}}export function renderBugIssue(e,t,r=[]){const o=h(e),[i,c]=o.fault.lines,u=i===c?`line ${String(i)}`:`lines ${String(i)} to ${String(c)}`;return{body:`${["## Expected behaviour",o.expected,"## Authority",o.authority,"## Observed behaviour",o.observed,"## Root cause",o.rootCause,"## Reproduce",["```sh",reproduceCommand(o,r),"```"].join(`
|
|
2
|
+
`),[`Test: \`${o.test.file}\`, "${o.test.title}".`,`Found at \`${t.foundAt}\`.`,`Fault: \`${o.fault.path}\`, ${u}.`].join(`
|
|
3
|
+
`),p(bugFacts(o,t))].join(`
|
|
4
4
|
|
|
5
5
|
`)}
|
|
6
|
-
`,labels:bugLabels(o.severity,t.area).map(
|
|
6
|
+
`,labels:bugLabels(o.severity,t.area).map(a=>a.name),title:o.title}}function h(e){return{...e,title:n(e.title),expected:n(e.expected),authority:n(e.authority),observed:n(e.observed),rootCause:n(e.rootCause),test:{file:e.test.file,title:n(e.test.title)}}}export function reproduceCommand(e,t=[]){const r=l(e.productPath,e.test.file),o=e.productPath===""?`npx testkit run --file ${s(r)}`:`npx testkit run --dir ${s(e.productPath)} --file ${s(r)}`,i=Object.entries(e.vitest??{}).flatMap(([c,u])=>[`--${c}`,u]);return[o,...[...i,...t].map(s)].join(" ")}function s(e){return/^[\w./@:+=-]+$/u.test(e)?e:`'${e.replaceAll("'","'\\''")}'`}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{readFactsBlock as o}from"./facts.js";import{redactRunResultText as u}from"../../tracker/redaction.js";export const COMMIT_STATUS_DESCRIPTION_MAX_LENGTH=140;export function readKnownTests(n){const
|
|
1
|
+
import{readFactsBlock as o}from"./facts.js";import{redactRunResultText as u}from"../../tracker/redaction.js";export const COMMIT_STATUS_DESCRIPTION_MAX_LENGTH=140;export function readKnownTests(n){const t=[],i=[];for(const e of n){const s=o(e.body);if(s.status==="ok"){const{file:r,title:l}=s.facts.test;t.push({file:r,issue:e.number,title:l??null,url:e.url})}else{const r=s.status==="missing"?"the issue has no facts block":s.reason;i.push({number:e.number,reason:r,url:e.url})}}return{tests:t,unreadable:i}}export function findKnownTest(n,t){const i=n.filter(s=>s.file===t.file),e=i.find(s=>s.title===null)??null;return t.title===null?null:i.find(s=>s.title===t.title)??e}export function classifyFailures(n,t){const i=[],e=[];for(const s of n){const r=t===null?null:findKnownTest(t,s);r===null?e.push(s):i.push({failure:s,issue:r})}return{known:i,new:e}}export function describeRunOutcome(n,t){if(n.kind==="passed")return{description:`${n.passedFiles===1?"1 file":`${String(n.passedFiles)} files`} passed`,state:"success"};if(n.kind==="run-failed"){const s=u(n.reason);return{description:c(`run failed: ${s}`),state:"failure"}}const i=n.classification.known.length,e=n.classification.new.length;return{description:`${String(i+e)} failed: ${String(e)} new, ${String(i)} known`,state:e===0&&t?"success":"failure"}}function c(n){return n.length<=COMMIT_STATUS_DESCRIPTION_MAX_LENGTH?n:`${n.slice(0,COMMIT_STATUS_DESCRIPTION_MAX_LENGTH-3)}...`}
|
package/dist/app/bugs/record.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import
|
|
2
|
-
Run \`testkit bug guide\` to see the record format.`,{cause:
|
|
1
|
+
import d from"node:fs";import h from"node:path";import{text as b}from"node:stream/consumers";import{loadTestkitConfig as D}from"../../config/loader/index.js";import{discoverOwnedTests as k}from"../../config/loader/owned-discovery.js";import{isTypedTestFile as T}from"../../domain/identifiers.js";import{resolveVitestSelection as E}from"../../engines/catalog.js";import{posixPath as P}from"../../process/files/paths.js";import{findActiveCampaign as S,readCampaigns as F}from"../campaigns/store.js";import{BugRecordError as $,createBugDraft as x,namesSameTest as C,readBugReport as R,requireOneVitestProject as j,toProductPath as B}from"./draft.js";import{bugDraftFile as O,displayPath as y,displayUnreadableDrafts as J,readStoredDrafts as N,resolveBugCheckout as A,writeJsonFile as I}from"./store.js";export async function recordBug(o){const e=await A(o),{redactedFields:i,report:t}=U(await q(e.cwd,o.file),e.productPath);for(const[r,g]of[["test.file",t.test.file],["fault.path",t.fault.path]])if(d.statSync(h.join(e.repoRoot,g),{throwIfNoEntry:!1})?.isFile()!==!0)throw new Error(`${r} resolves to ${g} from the repository root, and no file is there. Write the path relative to the product directory.`);const{config:a}=await D(e.productDir),c=E(o.vitest??{},e.productDir),f=B(e.productPath,t.test.file),l=await k(e.productDir,a,{plain:!T(f),selection:c}),m=l.problems.at(0);if(m!==void 0)throw new Error(m);if(!l.project.files.some(r=>r.filePath===f))throw new Error(`test.file resolves to ${t.test.file}, and Testkit does not discover a test there. Run \`testkit discover\` to list the tests it runs.`);j(t.test.file,l.plainFiles.filter(({file:r})=>r===f),c);const n=x(t,{campaign:S(F(e.productDir))?.id??null,productPath:e.productPath,recordedAt:o.at??new Date,recordedCommit:e.headCommit,vitest:V(o.vitest??{},e.productDir,c)}),u=N(e.productDir),p=u.drafts.filter(r=>C(r.draft,n)),w=p.find(r=>r.draft.filed!==void 0)?.draft.filed;if(w!==void 0)throw new Error(`This test already has a filed bug: ${w.url}. Testkit keeps one bug for each test.`);const s=O(e.productDir,n.id),v=u.unreadable.find(r=>r.file===s);if(v!==void 0)throw new Error(`${y(e,s)} exists and Testkit cannot read it: ${v.problem}. Fix or delete the file, then run this again.`);I(s,n);for(const r of p)r.file!==s&&d.rmSync(r.file,{force:!0});return{draft:n,path:y(e,s),redactedFields:i,replaced:p.length>0,unreadableDrafts:J(e,u.unreadable)}}function V({"vitest-project":o,"vitest-runner":e},i,{config:t}){const a={...e===void 0?{}:{"vitest-runner":e},...t===null?{}:{"vitest-config":P(h.relative(d.realpathSync(i),t))},...o===void 0?{}:{"vitest-project":o}};return Object.keys(a).length===0?void 0:a}async function q(o,e){if(e==="-")return{source:"standard input",text:await b(process.stdin)};try{return{source:e,text:d.readFileSync(h.resolve(o,e),"utf8")}}catch(i){throw new Error(`Testkit cannot read the bug record file ${e}.`,{cause:i})}}function U(o,e){let i;try{i=JSON.parse(o.text)}catch(t){throw new Error(`The bug record in ${o.source} is not valid JSON.`,{cause:t})}try{return R(i,e)}catch(t){throw t instanceof $?new Error(`${t.message}
|
|
2
|
+
Run \`testkit bug guide\` to see the record format.`,{cause:t}):t}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const
|
|
1
|
+
import{runModel as p}from"../../evidence/index.js";import{isUnknownRecord as f}from"../../kernel/unknown-values.js";const k=new Set(["engine-failure","playwright-other-file-spec","vitest-error"]),h=1;export function readRunArtifact(e,r){return readRun(p(e),r)}export function readRun(e,r){if(e.finalizationFailure!==null)return u(e.finalizationFailure.message);if(e.run.status==="interrupted")return u("the run was interrupted");const{cleanup:n,publication:o}=e.archive;if(o?.status==="failed"&&o.required)return u("Testkit could not publish the run's results");if(n?.status==="failed")return u("Testkit could not clean up after the run");const i=e.groups.flatMap(t=>t.errors).at(0);if(i!==void 0)return u(i);const s=e.groups.flatMap(t=>t.suites.flatMap(d=>d.files));if(s.some(t=>t.infraFailed===!0||t.blockedByRuntime===!0))return u("test infrastructure failure");if(s.some(t=>t.status==="not_run"))return u("one or more required test files did not run");if(s.some(t=>t.status==="skipped"))return u("one or more selected test files were skipped");const a=s.find(t=>t.status!=="passed"&&t.status!=="failed");if(a!==void 0)return u(`${a.path} ended as ${a.status}`);const l=s.filter(t=>t.status==="failed");return l.length>0?{failures:l.flatMap(t=>m(t,r)),kind:"tests-failed"}:e.run.status!=="passed"?u(s.length===0?"no runnable test files executed":"the run did not pass"):{kind:"passed",passedFiles:s.length}}function m(e,r){const n=r===""?e.path:`${r}/${e.path}`,o=e.failureDetails??[],i=o.filter(t=>!k.has(t.kind??"")),s=new Set(i.filter(g).map(c)),a=[...new Set(i.map(c))].map(t=>({...s.has(t)?{ambiguous:!0}:{},file:n,title:t}));return o.filter(t=>t.kind==="engine-failure"||t.kind==="vitest-error").map(t=>t.kind==="vitest-error"?"unexplained":F(t,i)).includes("unexplained")||a.length===0?[...a,{file:n,title:null}]:a}function g(e){return e.kind==="vitest-test"&&(e.sharedTitle===!0||typeof e.count=="number"&&e.count>1)}function c(e){const r=e.key?.trim()??"";return r===""?e.title:e.kind==="playwright-spec"?r:e.title}function F(e,r){const n=f(e.actual)&&f(e.actual.details)?e.actual.details:null;if(n===null)return"unexplained";if(e.key==="PLAYWRIGHT_SPECS_FAILED"){const o=y(r.filter(l=>l.kind==="playwright-spec")),i=f(n.stats)?n.stats:{},s=n.failOnFlakyTests!==!1&&i.flaky!==0;return i.unexpected===o&&n.reportErrors===0&&n.attachmentFailures===0&&n.evidenceErrors===0&&n.runStatus==="failed"&&n.exitCode===h&&typeof n.failOnFlakyTests=="boolean"&&!s?"restated":"unexplained"}return"unexplained"}function y(e){return e.reduce((r,n)=>r+(typeof n.count=="number"?n.count:1),0)}function u(e){return{kind:"run-failed",reason:e}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{redactBugText as a}from"../../tracker/redaction.js";const h=/^[A-Za-z_][A-Za-z0-9_]*$/u,d=/^[A-Za-z0-9][A-Za-z0-9._-]*$/u;export function suppliedReproduceArgs(e){if((e.database?.length??0)>0)throw s("--database NAME=URL","Put named databases in an --environment-file, or select the default database's URL from a host variable with --env-from DATABASE_URL=HOST_KEY.");if((e.env?.length??0)>0)throw s("--env NAME=VALUE","Select the value from a host variable with --env-from NAME=HOST_KEY, or put it in an --environment-file.");const r=[];e.baseUrl!==void 0&&r.push("--base-url",i(e.baseUrl,"--base-url"));for(const t of e.endpoint??[]){const n=t.indexOf("="),o=t.slice(0,Math.max(n,0));if(!d.test(o))throw new Error("--endpoint expects NAME=URL, where NAME uses only ASCII letters, digits, dot, underscore or hyphen and starts with a letter or digit");r.push("--endpoint",`${o}=${i(t.slice(n+1),`--endpoint ${o}`)}`)}for(const t of e.envFrom??[]){const n=t.split("=");if(n.length!==2||!n.every(o=>h.test(o)))throw new Error("--env-from expects NAME=HOST_KEY, where both are variable names");r.push("--env-from",t)}if(e.environmentFile!==void 0){if(a(e.environmentFile)!==e.environmentFile)throw new Error("The --environment-file path holds text that Testkit redacts as a secret, and the issue would carry it. Rename the file.");r.push("--environment-file",e.environmentFile)}return r}function i(e,r){let t;try{t=new URL(e)}catch{throw new Error(`${r} is not a valid URL`)}if(t.username!==""||t.password!==""||t.search!==""||t.hash!==""||a(e)!==e)throw new Error(`${r} carries credentials, a query or a fragment, and the issue's reproduce command would hold them. Supply that URL in an --environment-file instead.`);return e}function s(e,r){return new Error(`bug file does not take ${e}, because the issue's reproduce command would hold the raw value. ${r}`)}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{redactSensitiveText as
|
|
1
|
+
import{redactSensitiveText as c}from"../../kernel/redaction.js";import{isUnknownRecord as p}from"../../kernel/unknown-values.js";import{CAMPAIGN_ID_MAX_LENGTH as i,isCampaignId as o}from"../bugs/draft.js";import{isCommitId as g}from"../bugs/facts.js";export const CAMPAIGN_SCHEMA_VERSION=1,CAMPAIGN_TARGET_MAX_LENGTH=200;const f=11;export function readCampaignTarget(t){const r=c(t.trim());if(r.length===0||r.length>CAMPAIGN_TARGET_MAX_LENGTH||/[\r\n]/u.test(r))throw new Error(`--target must be one line of 1 to ${String(CAMPAIGN_TARGET_MAX_LENGTH)} characters.`);return r}export function readCampaignId(t){if(o(t))return t;throw new Error(`--id must be lowercase letters, digits, and single hyphens, at most ${String(i)} characters. Got ${JSON.stringify(t)}.`)}export function defaultCampaignId(t,r){return`${t.normalize("NFKD").replace(/\p{M}+/gu,"").toLowerCase().replace(/[^a-z0-9]+/gu,"-").replace(/^-+/u,"").slice(0,i-f).replace(/-+$/u,"")||"campaign"}-${r.toISOString().slice(0,10)}`}export function readCampaign(t){if(!p(t))throw new Error("it must be a JSON object");if(t.schemaVersion!==CAMPAIGN_SCHEMA_VERSION)throw new Error(`unknown schemaVersion ${JSON.stringify(t.schemaVersion)}`);const r=[],e=(n,a,m)=>a(n)?n:(r.push(m),""),s={schemaVersion:CAMPAIGN_SCHEMA_VERSION,id:e(t.id,o,"id must be a campaign id"),target:e(t.target,d,"target must be one line of text"),startedAt:e(t.startedAt,isTimestamp,"startedAt must be a timestamp"),startCommit:e(t.startCommit,g,"startCommit must be a full commit id"),...t.finishedAt===void 0?{}:{finishedAt:e(t.finishedAt,isTimestamp,"finishedAt must be a timestamp")}};if(r.length>0)throw new Error(r.join(", "));return s}function d(t){return typeof t=="string"&&t.trim().length>0&&!/[\r\n]/u.test(t)}export function isTimestamp(t){return typeof t=="string"&&!Number.isNaN(Date.parse(t))}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{formatRunSummary as m}from"../../process/runs/manifest.js";import d from"path";import{pruneEmptyDir as p}from"../../process/files/directory-status.js";import f from"fs";import{loadManagedConfigs as v}from"../../config/loader/managed-configs.js";import{collectBundleCleanupTargets as g}from"../../engines/bundle-cache.js";import{createEnvironmentMaintenance as y}from"../../environment/maintenance.js";import{runtimePlanning as h}from"../../environment/runtime-planning.js";export async function cleanupEnvironment(e){const{allConfigs:
|
|
1
|
+
import{formatRunSummary as m}from"../../process/runs/manifest.js";import d from"path";import{pruneEmptyDir as p}from"../../process/files/directory-status.js";import f from"fs";import{loadManagedConfigs as v}from"../../config/loader/managed-configs.js";import{collectBundleCleanupTargets as g}from"../../engines/bundle-cache.js";import{createEnvironmentMaintenance as y}from"../../environment/maintenance.js";import{runtimePlanning as h}from"../../environment/runtime-planning.js";import{resolveProductDir as C}from"../../process/files/product-dir.js";export async function cleanupEnvironment(e){const r=C(process.cwd(),e.dir),{allConfigs:n}=await v({dir:r,service:e.service}),t=await cleanup(r,{allConfigs:n,serviceName:e.service||null,dryRun:e.dryRun,cache:e.cache,resources:e.resources}),a={cleaned:s(t.cleaned),stoppedActive:s(t.stoppedActive),skippedActive:s(t.skippedActive)};return{productDir:r,result:t,runSummaries:a}}export async function cleanup(e,r={}){const n=r.allConfigs??[],t=r.serviceName||null,a=R(r.cache),{environment:c,otherCaches:u}=await y(e).maintain({kind:"cleanup",desiredGraphs:h.collectDesiredRuntimeGraphs(n),serviceName:t,dryRun:!!r.dryRun,resources:!!r.resources},()=>{const i=a.includes("bundles")?g(e,{allConfigs:n,serviceName:t}):[],o=[];return{result:{targets:i,cleaned:o},prune(){for(const l of i)f.rmSync(l.path,{force:!0}),o.push(l);p(d.join(e,".testkit","_bundles"))}}});return{...c,targets:{runtime:c.targets,bundles:u.targets},bundleCleaned:u.cleaned}}function R(e){const n=(Array.isArray(e)?e:e?[e]:[]).filter(Boolean).map(String);return n.includes("all")?["runtime","bundles"]:n}function s(e){return e.map(r=>({runId:r.runId,summary:m(r)}))}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import
|
|
1
|
+
import f from"node:path";import{resolveProductDir as g}from"../../config/loader/index.js";import{collectRequiredConfigs as p,loadManagedConfigs as u,resolveTargetConfig as v,topologicallySortConfigs as d}from"../../config/loader/managed-configs.js";import{runtimePlanning as C}from"../../environment/runtime-planning.js";import{withEnvFileValues as w}from"../../config/loader/env.js";import{portsOf as h,releasePorts as P,reservePorts as y}from"../../environment/ports.js";export async function prepareSchemaOperation(o,c){const t=g(process.cwd(),o.dir),{configs:n}=await u({dir:t}),e=v(n,o.service||null),i=p(n,e.name).map(w);return{productDir:t,serviceName:e.name,async resolveConfigs(l){const s=await y(i.filter(r=>r.testkit.local).map(r=>r.name));await P(s.values());const a=C.resolveRuntimeInstanceConfigs(i,"runtime-1",f.join(l,"runtime-1"),{graphDirName:`${c}-${e.name}`,ports:h(s)}),m=a.find(r=>r.name===e.name);if(!m)throw new Error(`Resolved runtime config missing target service "${e.name}"`);return{configs:d(a),target:m}}}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{filterConfigsByService as
|
|
1
|
+
import{filterConfigsByService as a}from"../../config/loader/managed-configs.js";import{loadConfigContext as n}from"../../config/loader/index.js";import{createEnvironmentMaintenance as i}from"../../environment/maintenance.js";import{hasLocalDatabaseState as d}from"../../database/lifecycle-cleanup.js";export async function destroy(t,e,r={}){await i(t).maintain({kind:"destroy",configs:e,destroyOwnedResources:r.destroyOwnedResources})}export async function destroyEnvironment(t){const e=await n({dir:t.dir,plain:!1,retired:[]}),r=a(e.services,t.service||null),s=e.services.some(o=>o.testkit.database!==void 0||o.testkit.databaseFrom!==void 0);return await destroy(e.productDir,r,{destroyOwnedResources:!t.service&&(s||d(e.productDir))}),{ok:!0,productDir:e.productDir,results:r.map(o=>({name:o.name,destroyed:!0}))}}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{resolveRequestedFiles as
|
|
2
|
-
`),
|
|
1
|
+
import{resolveRequestedFiles as p}from"../file-selection.js";import{resolveVitestSelection as v}from"../../engines/catalog.js";import u from"fs";import t from"path";import{loadDiscoveryContext as d,resolveProductDir as y}from"../../config/loader/index.js";export async function executeDiscoverOperation({notice:a,output:o,vitest:m,...i},l=process.cwd()){const e=y(l,i.dir),f=p(i.file||[],e,l),{discovery:s,notice:c}=await d({...i,dir:e,file:f,vitest:v(m??{},e)});c!==null&&a?.(c);let n=null;if(o){const r=t.resolve(e,o);u.mkdirSync(t.dirname(r),{recursive:!0}),u.writeFileSync(r,`${JSON.stringify(s,null,2)}
|
|
2
|
+
`),n=(t.relative(e,r)||t.basename(r)).replaceAll("\\","/")}return{...s,outputLabel:n}}
|
package/dist/app/doctor/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import m from"path";import{randomUUID as v}from"node:crypto";import{loadDiscoveryContext as k,loadConfigContext as w}from"../../config/loader/index.js";import{runLintForConfig as D}from"../lint/index.js";export async function runDoctor(e={}){const t=[],
|
|
1
|
+
import m from"path";import{randomUUID as v}from"node:crypto";import{loadDiscoveryContext as k,loadConfigContext as w}from"../../config/loader/index.js";import{runLintForConfig as D}from"../lint/index.js";import{isUnknownRecord as a}from"../../kernel/unknown-values.js";import{requireUnknownArray as d}from"../../evidence/read-fields.js";export async function runDoctor(e={}){const t=[],s=e.dir?m.resolve(process.cwd(),e.dir):process.cwd(),r=await w({dir:s,configImportCacheSalt:v(),plain:!1});t.push({code:"config-load",level:"pass",message:"Loaded testkit config and service config"});const l=await k({dir:s,diagnostics:"report"},r),g=l.discovery,f=R(g,"discovery result"),u=d(f.diagnostics,"discovery result diagnostics"),p=d(f.files,"discovery result files"),c=u.filter(S);t.push({code:"discovery",level:c.length===0?"pass":"fail",message:c.length===0?`Discovered ${String(p.length)} testkit files without diagnostics`:`Discovery reported ${String(c.length)} error diagnostics`,details:c});const o=await D(n(r,"config"),{dir:s});if(t.push({code:"lint",level:o.ok?"pass":"fail",message:o.ok?`No Testkit lint violations across ${String(o.summary.testkitFiles)} suite file(s)`:`Found ${String(o.summary.violations)} Testkit lint violation(s)`,details:o.violations}),e.typecheck!==!1)try{const{runTestkitTypecheckForContext:i}=await import("../typecheck/index.js"),y=await i(r,l.discovery,{dir:s}),h=d(n(y,"results"),"typecheck results");t.push({code:"typecheck",level:"pass",message:`Typechecked ${String(h.length)} generated program(s)`})}catch(i){t.push({code:"typecheck",level:"fail",message:C(i)})}return{ok:!t.some(i=>i.level==="fail"),productDir:s,checks:t}}function S(e){return a(e)&&Reflect.get(e,"severity")==="error"}function C(e){const t=n(e,"result"),s=n(t,"stderr");if(typeof s=="string"&&s.length>0)return s;const r=n(t,"stdout");return typeof r=="string"&&r.length>0?r:e instanceof Error?e.message:String(e)}function R(e,t){if(!a(e))throw new Error(`${t} must be an object`);return e}function n(e,t){return a(e)?Reflect.get(e,t):void 0}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{createEnvironment as S,environmentTaskIdentities as C,renderSharedEnvironment as k}from"../run/environment.js";import{buildTaskExecutionEnv as R,buildTemplateContext as A,finalizeSerializable as O}from"../../steps/index.js";import{runtimePlanning as j}from"../../environment/runtime-planning.js";import{sourceSchemaCredentialEnvNames as M}from"../../database/source-schema-env.js";import{prepareFileSetup as U}from"./file-setup.js";import{cloneTaskDatabases as T}from"./task-databases.js";import{envRedactionTargets as D,jsonRedactionTargets as N,sensitiveKeyMatcher as E,urlRedactionTargets as x}from"../../kernel/redaction-targets.js";export function planConfiguredCapacity(e){const t=j.buildRuntimeGraphs(e);return{graphs:t,instanceCount:t.reduce((s,a)=>s+a.instanceCount,0),resourceBudgets:I(t)}}function I(e){const t=new Map;for(const s of e)for(const a of s.resourceReservations){const o=t.get(a.key)??{key:a.key,kind:a.kind,scope:a.scope,resourceName:a.resourceName,capacity:a.capacity,reserved:a.reserved,available:a.available,graphs:[]};o.capacity=Math.max(o.capacity,a.capacity),o.reserved=Math.max(o.reserved,a.reserved),o.available=Math.max(0,o.capacity-o.reserved),o.graphs.push({graphKey:s.key,services:a.services,perRuntime:a.perRuntime}),t.set(a.key,o)}return[...t.values()].sort((s,a)=>s.key.localeCompare(a.key))}export function createConfigDrivenEnvironments(e,t,s,a=null){const o=E(a?.redactKeys);return{canAcquire:i=>e.canAcquire(i),getGraph:i=>e.getGraph(i),getGraphFailure:i=>e.getGraphFailure(i),markGraphFailed:(i,d)=>{e.markGraphFailed(i,d)},async acquire(i,d){const p=a?.acquisition({source:"configured",graphKey:i.graphKey,leaseId:d.id,tasks:C(i)});try{const u=c=>{const r=t.get(c);if(r===void 0)throw new Error(`No services are declared for group "${c}"`);return r},h={name:i.targetName,uses:u(i.targetName)},g=await e.acquire({...i,leaseId:d.id},{onRuntimeAssigned:c=>p?.assigned(c)});p?.acquired(K(g));const v=c=>L(p,()=>e.release(g.leaseId,c));try{const c=n=>a?.addRedactionTarget(n),r=k(i,n=>renderEnvironment(g,{name:n,uses:u(n)},d,c,o));return p?.rendered(r),{environment:r,async prepare(n,l){const f={lease:d,productDir:s,record:p,redact:c};if(n.runtimeIsolation!=="resetBefore")return U(n,l,{...f,environment:r});const m=await T(g,r,n,d,l),b=renderEnvironment(m.ready,h,d,c,o);p?.rendered(b);const y=await U(n,l,{...f,environment:b}).catch(async w=>{throw await m.release(),w});return{artifacts:y?.artifacts??[],environment:b,handles:y?.handles??{},setupData:y===null?b.setupData:y.setupData,release:async()=>[...await y?.release()??[],...await m.release()]}},release:v}}catch(c){throw await v({invalidate:!1}),c}}catch(u){throw e.signal.aborted&&u===e.signal.reason?p?.cancelled(u):p?.failed(u),u}}}}function K(e){return{runtimeId:e.runtimeId,services:[...e.services.values()].map(({config:t})=>({serviceName:t.name,runtimeLabel:String(t.runtimeLabel??t.name)}))}}async function L(e,t){try{await t()}catch(s){throw e?.releaseFailed(s),s}e?.released()}const B=new Set(["BASE_URL","DATABASE_URL"]);export function renderEnvironment(e,t,s,a=()=>{},o=E()){const i={leaseDir:s.directory,leaseId:s.id},d=new Map([...e.services].map(([r,n])=>{const l=q(R(n.config,i,{},null,{includeTestkitControls:!1,inheritProcessEnv:!1}));for(const f of[...D(l,o),...[n.baseUrl,n.database?.url].flatMap(m=>m?x(m):[])])a(f);return[r,l]})),p=F(e),u=t.uses.map(r=>{const n=e.services.get(r),l=d.get(r);if(!n||!l)throw new Error(`Runtime instance is missing used service "${r}"`);const f=G(l,p),m=Object.entries(f).find(([b])=>b.toUpperCase()==="DATABASE_URL")?.[1];return{name:r,config:n.config,baseUrl:typeof n.baseUrl=="string"&&n.baseUrl.length>0?n.baseUrl:null,databaseUrl:n.database?.url??(m||null),env:Object.fromEntries(Object.entries(f).filter(([b])=>!B.has(b.toUpperCase())))}}),h={},g=new Set;for(const r of u){const n=Object.entries(r.env).filter(([l])=>!g.has(l.toUpperCase()));for(const[l,f]of n)h[l]=f;for(const[l]of n)g.add(l.toUpperCase())}const v=u.at(0)?.config,c=v?.testkit.ui?_(O(v.testkit.ui,A(v,i))):null;for(const r of N("ui",c,o))a(r);return S({baseUrl:u.find(r=>r.baseUrl!==null)?.baseUrl??null,databaseUrl:u.find(r=>r.databaseUrl!==null)?.databaseUrl??null,databases:Object.fromEntries(u.flatMap(r=>r.databaseUrl===null?[]:[[r.name,r.databaseUrl]])),endpoints:Object.fromEntries(u.flatMap(r=>r.baseUrl===null?[]:[[r.name,r.baseUrl]])),env:h,group:t.name,ui:c})}function F(e){return new Set([...e.services.values()].flatMap(({config:t})=>M(t)).map(t=>t.toUpperCase()))}function G(e,t){return Object.fromEntries(Object.entries(e).filter(([s])=>!t.has(s.toUpperCase())))}function q(e){return Object.fromEntries(Object.entries(e).filter(t=>typeof t[1]=="string"))}function _(e){const t=JSON.stringify(e);if(typeof t!="string")return null;const s=JSON.parse(t);return s!==null&&typeof s=="object"&&!Array.isArray(s)?s:null}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import f from"node:fs";import l from"node:path";import{errorMessage as p}from"../../kernel/error-serialization.js";export const ENVIRONMENT_FILE_VERSION=1;const b=new Set(["version","baseUrl","databaseUrl","endpoints","databases","env","ui","setupData","handles"]);export function readEnvironmentFile(n,o){const r=l.resolve(o,n);let e;try{e=f.readFileSync(r,"utf8")}catch(t){throw new Error(`Environment file ${n} could not be read: ${p(t)}`,{cause:t})}return{content:parseEnvironmentFile(e,n),label:n}}export function parseEnvironmentFile(n,o){const r=h(n);if(!r.ok)throw new Error(`Environment file ${o} is not valid JSON${r.location}`);const e=r.value,t=(s,c)=>{throw new Error(`Environment file ${o}: ${s} ${c}`)};if(!a(e))return t("the document","must be a JSON object");if(e.version!==ENVIRONMENT_FILE_VERSION){const s=`this Testkit reads version ${ENVIRONMENT_FILE_VERSION.toString()}`;return e.version===void 0?t("version",`is missing; ${s}`):t("version",typeof e.version=="number"&&Number.isInteger(e.version)?`${e.version.toString()} is not supported; ${s}`:`must be a whole number; ${s}`)}for(const s of Object.keys(e))b.has(s)||t(s,"is not part of an environment file, which holds values, prepared setup data and handle descriptors, never provider config");const i={databases:d(e.databases,"databases",t),endpoints:d(e.endpoints,"endpoints",t),env:d(e.env,"env",t),handles:m(e.handles,t)};return e.baseUrl!=null&&(i.baseUrl=u(e.baseUrl,"baseUrl",t)),e.databaseUrl!=null&&(i.databaseUrl=u(e.databaseUrl,"databaseUrl",t)),e.ui!=null&&(a(e.ui)||t("ui","must be a JSON object or null"),i.ui=e.ui),e.setupData!==void 0&&(i.setupData=e.setupData),i}function d(n,o,r){if(n===void 0)return{};if(!a(n))return r(o,"must be an object of strings");for(const[e,t]of Object.entries(n))e.length===0&&r(o,"holds an empty name"),u(t,`${o}.${e}`,r);return n}function m(n,o){if(n===void 0)return{};if(!a(n))return o("handles","must be an object of handle descriptors");for(const[r,e]of Object.entries(n)){a(e)||o(`handles.${r}`,"must be a handle descriptor object");const t=e.kind;(typeof t!="string"||t.length===0)&&o(`handles.${r}.kind`,"must be a non-empty string")}return n}function u(n,o,r){return typeof n=="string"?n:r(o,"must be a string")}function a(n){return n!==null&&typeof n=="object"&&!Array.isArray(n)}function h(n){try{return{ok:!0,value:JSON.parse(n)}}catch(o){const r=/line (\d+) column (\d+)/u.exec(o instanceof Error?o.message:"");return{ok:!1,location:r?` at line ${r[1]}, column ${r[2]}`:""}}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import f from"node:path";import{httpCaptureRedactionTargets as E}from"../run/setup/runtime-node-setup-protocol.js";import{classifyRuntimeNodeSetupFailure as M,findRuntimeNodeSetupFile as N,getRuntimeNodeSetupCleanupFailures as S,MAX_RUNTIME_NODE_SETUP_CLEANUP_TIMEOUT_MS as F,runRuntimeNodeSetup as y}from"../run/setup/runtime-node-setup.js";import{defaultEnvironmentValues as T}from"../run/engine-orchestration.js";import{TaskPreparationError as U}from"../run/environment.js";import{toError as d}from"../../kernel/error-serialization.js";import{ambiguousHandleDescriptor as w}from"../../engines/environment/handles.js";export async function prepareFileSetup(e,r,{environment:a,lease:t,productDir:n,record:s,redact:c}){let o,l;try{const i=N(n,e.file);if(i===null)return null;o=s?.setup({module:f.relative(n,i).split(f.sep).join("/"),task:{file:e.file,group:e.targetName,id:e.id}}),l=await y({cleanupTimeoutMs:Math.min(r.timeoutMs,F),deadlineMs:r.deadlineMs,lease:{leaseDir:t.directory,leaseId:t.id},onSidecar:u=>{for(const p of E(u))c(p)},runtimeEnv:T(a),signal:r.signal,targetConfig:{name:e.targetName,productDir:n},task:e})}catch(i){const u=M(i),p=m(i);u==="cancelled"?o?.cancelled(i):o?.failed(i);for(const h of p)o?.releaseFailed(h.error);throw new U(u,d(i),p)}o?.prepared(l.setupData);let g=null;return{artifacts:l.artifacts,handles:_(l.sidecars),setupData:l.setupData,release:()=>g??=R(l.cleanup,o)}}async function R(e,r){try{await e()}catch(a){const t=m(a),n=t.length>0?t:[{error:d(a),owner:"testkit"}];for(const s of n)r?.releaseFailed(s.error);return n}return r?.released(),[]}function _(e){const r={};for(const a of new Set(e.map(t=>t.id))){const t=e.filter(o=>o.id===a),[{requestsUrl:n,resetUrl:s,url:c}]=t;Object.defineProperty(r,a,{enumerable:!0,value:t.length>1?w(t.length):{kind:"http-capture",requestsUrl:n,resetUrl:s,url:c}})}return r}function m(e){return S(e).map(({error:r,owner:a})=>({error:r,owner:a}))}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export function declaresProvisioning(n){return n.some(({testkit:r})=>r.local!==void 0||r.database!==void 0||r.databaseFrom!==void 0||r.runtime.build!==null||r.runtime.prepare.steps.length>0||r.runtime.toolchain!==null)}export function declaresValues(n){return n.some(({testkit:r})=>Object.keys(r.serviceEnv).length>0||r.envFiles.length>0||r.ui!=null)}export function routeEnvironments(n){const r=e=>{const a=n.get(e);if(a===void 0)throw new Error(`No environment source for runtime graph "${e}"`);return a};return{acquire:(e,a)=>r(e.graphKey).acquire(e,a),canAcquire:e=>r(e.graphKey).canAcquire(e),getGraph:e=>r(e).getGraph(e),getGraphFailure:e=>r(e).getGraphFailure(e),markGraphFailed:(e,a)=>{r(e).markGraphFailed(e,a)}}}export function holdBeforeRelease(n,r){return{...n,async acquire(e,a){const i=await n.acquire(e,a);let d=null,t=!1;const c=()=>d??=Promise.resolve().then(()=>r(e.targetName,i.environment)).then(()=>({failed:!1}),l=>({error:l,failed:!0}));return{environment:i.environment,async prepare(l,u){const o=await i.prepare(l,u);return o===null?null:{...o,async release(){return await c(),o.release()}}},async release(l){const u=await c(),o=u.failed&&!t;t||=u.failed;try{await i.release(l)}catch(s){if(!o)throw s}if(o)throw u.error}}}}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{environmentTaskIdentities as p,renderSharedEnvironment as h}from"../run/environment.js";import{withEnvFileValues as g}from"../../config/loader/env.js";import{sensitiveKeyMatcher as w}from"../../kernel/redaction-targets.js";import{renderEnvironment as y}from"./config-driven.js";import{prepareFileSetup as v}from"./file-setup.js";import{resetBeforeRefusal as E}from"./task-databases.js";const K=new Set(["bin","lease","leaseDir","pathList","productDir","service","stateDir"]);export function createStaticValueEnvironments(e,c,n=null){const o=new Map,f=r=>{const i=o.get(r.name);if(i!==void 0)return i;const t=g(r);return S(t),o.set(r.name,t),t};return{canAcquire:()=>!0,getGraph:()=>null,getGraphFailure:()=>null,markGraphFailed:()=>{},acquire(r,i){const t=n?.acquisition({source:"static",graphKey:r.graphKey,leaseId:i.id,tasks:p(r)});return Promise.resolve().then(()=>{const s=h(r,a=>{const m=e.get(a);if(m===void 0)throw new Error(`No services are declared for group "${a}"`);const l={graphKey:r.graphKey,leaseId:i.id,runtimeId:r.graphKey,targetNames:[a],services:new Map(m.map(u=>[u.name,{baseUrl:null,database:null,config:f(u)}]))};return y(l,{name:a,uses:m.map(({name:u})=>u)},i,u=>n?.addRedactionTarget(u),w(n?.redactKeys))});return t?.acquired({runtimeId:null,services:[]}),t?.rendered(s),{environment:s,prepare:async(a,m)=>{if(a.runtimeIsolation==="resetBefore")throw E(a,!1);return v(a,m,{environment:s,lease:i,productDir:c,record:t,redact:l=>n?.addRedactionTarget(l)})},release:()=>(t?.released(),Promise.resolve())}}).catch(s=>{throw t?.failed(s),s})}}}function S(e){const c=[...Object.entries(e.testkit.serviceEnv).map(([n,o])=>[`env.${n}`,o]),["ui",e.testkit.ui]];for(const[n,o]of c)for(const f of d(o))if(!K.has(f))throw new Error(`Service "${e.name}" uses {${f}} in ${n}, which needs a running service, and "${e.name}" starts none`)}function d(e){return typeof e=="string"?[...e.matchAll(/\{([a-zA-Z]+)(?::[^}]+)?\}/gu)].map(c=>c[1]):Array.isArray(e)?e.flatMap(d):e!==null&&typeof e=="object"?Object.values(e).flatMap(d):[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{parsePostgresUrl as m}from"../../database/postgres/connection-check.js";import{errorMessage as A}from"../../kernel/error-serialization.js";import{parseHttpUrl as w}from"../../process/readiness.js";const u="BASE_URL",U="DATABASE_URL";export function hasSuppliedInput(e){return e.baseUrl!==void 0||e.environmentFile!==void 0||[e.database,e.endpoint,e.env,e.envFrom].some(a=>(a?.length??0)>0)}export function resolveSuppliedInput(e,a,o){const s=$("the default",!0),d=$("endpoint"),f=$("database"),l=$("env",!0),c=(r,t,n)=>{const i=r.toUpperCase();i===u?s.define(u,b(t,n),n):i===U?s.define(U,h(t,n),n):l.define(r,t,n)};if(a!==null){const{content:r,label:t}=a;if(r.baseUrl!==void 0&&s.define(u,b(r.baseUrl,`${t}: baseUrl`),`${t}: baseUrl`),r.databaseUrl!==void 0){const n=`${t}: databaseUrl`;s.define(U,h(r.databaseUrl,n),n)}for(const[n,i]of Object.entries(r.endpoints))d.define(n,b(i,`${t}: endpoints.${n}`),`${t}: endpoints.${n}`);for(const[n,i]of Object.entries(r.databases))f.define(n,h(i,`${t}: databases.${n}`),`${t}: databases.${n}`);for(const[n,i]of Object.entries(r.env))c(n,i,`${t}: env.${n}`)}e.baseUrl!==void 0&&s.define(u,b(e.baseUrl,"--base-url"),"--base-url");for(const r of e.endpoint??[]){const[t,n]=v(r,"--endpoint","NAME=URL");d.define(t,b(n,`--endpoint ${t}`),`--endpoint ${t}`)}for(const r of e.database??[]){const[t,n]=v(r,"--database","NAME=URL");f.define(t,h(n,`--database ${t}`),`--database ${t}`)}for(const r of e.env??[]){const[t,n]=v(r,"--env","NAME=VALUE");c(t,n,`--env ${t}`)}for(const r of e.envFrom??[]){const[t,n]=v(r,"--env-from","NAME=HOST_KEY"),i=`--env-from ${t}=${n}`,E=o[n];if(E===void 0)throw new Error(`${i}: the host variable ${n} is not set`);c(t,E,i)}const p=s.values();return{baseUrl:p[u]??null,databaseUrl:p[U]??null,databases:Object.fromEntries(Object.entries(f.values()).filter(([,r])=>r.length>0)),endpoints:d.values(),env:l.values(),handles:a?.content.handles??{},...a?.content.setupData===void 0?{}:{setupData:a.content.setupData},ui:a?.content.ui??null}}export function suppliedBindings(e){return{...e.env,...e.baseUrl===null?{}:{BASE_URL:e.baseUrl},...e.databaseUrl===null?{}:{DATABASE_URL:e.databaseUrl}}}export function projectSuppliedEnvironment(e,a){const o=s=>a.filter(d=>Object.hasOwn(s,d)).map(d=>s[d])[0]??null;return{baseUrl:e.baseUrl??o(e.endpoints),databaseUrl:e.databaseUrl??o(e.databases),databases:{...e.databases},endpoints:{...e.endpoints},env:{...e.env},...Object.keys(e.handles).length===0?{}:{handles:{...e.handles}},...e.setupData===void 0?{}:{setupData:e.setupData},ui:e.ui}}function $(e,a=!1){const o=new Map;return{define(s,d,f){const l=a?s.toUpperCase():s,c=o.get(l);if(c===void 0){o.set(l,{label:f,name:s,value:d});return}if(c.value!==d){const p=e==="the default"?`the default ${s}`:`${e} ${c.name}`;throw new Error(`${c.label} and ${f} supply different values for ${p}`)}},values(){return Object.fromEntries([...o.values()].map(({name:s,value:d})=>[s,d]))}}}function v(e,a,o){const s=e.indexOf("=");if(s<=0)throw new Error(`${a} expects ${o}`);return[e.slice(0,s),e.slice(s+1)]}function b(e,a){try{w(e)}catch(o){throw new Error(`${a}: ${o instanceof Error?o.message:String(o)}`,{cause:o})}return e}function h(e,a){if(e.length===0)return e;try{m(e)}catch(o){throw new Error(`${a} ${A(o)}`,{cause:o})}return e}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{createEnvironment as y,environmentTaskIdentities as g,renderSharedEnvironment as R}from"../run/environment.js";import{httpCaptureRedactionTargets as T}from"../run/setup/runtime-node-setup-protocol.js";import{checkPostgresConnection as E,parsePostgresUrl as M}from"../../database/postgres/connection-check.js";import{errorMessage as l}from"../../kernel/error-serialization.js";import{envRedactionTargets as O,jsonRedactionTargets as f,sensitiveKeyMatcher as j,urlRedactionTargets as q}from"../../kernel/redaction-targets.js";import{parseHttpUrl as D,requireHttpResponse as I}from"../../process/readiness.js";import{prepareFileSetup as P}from"./file-setup.js";import{resetBeforeRefusal as S}from"./task-databases.js";const m=3e4;export function createSuppliedEnvironments(t,{productDir:e,record:r=null,signal:o}){const i=j(r?.redactKeys);return{canAcquire:()=>!0,getGraph:()=>null,getGraphFailure:()=>null,markGraphFailed:()=>{},async acquire(a,s){const p=Object.hasOwn(t,a.targetName),c=r?.acquisition({source:p?"supplied":"none",graphKey:a.graphKey,leaseId:s.id,tasks:g(a)}),h=p?t[a.targetName]:{};for(const n of $(h,i))r?.addRedactionTarget(n);let d;try{d=R(a,n=>suppliedEnvironment(n,Object.hasOwn(t,n)?t[n]:{})),await C(a.targetName,d,o)}catch(n){throw o?.aborted&&n===o.reason?c?.cancelled(n):c?.failed(n),n}return c?.acquired({runtimeId:null,services:[]}),c?.rendered(d),{environment:d,prepare:async(n,U)=>{if(n.runtimeIsolation==="resetBefore")throw S(n,p);return p?null:P(n,U,{environment:d,lease:s,productDir:e,record:c,redact:w=>r?.addRedactionTarget(w)})},release:()=>(c?.released(),Promise.resolve())}}}}function $(t,e){return[...O(t.env??{},e),...[t.baseUrl,t.databaseUrl,...Object.values(t.databases??{}),...Object.values(t.endpoints??{})].flatMap(r=>r?q(r):[]),...f("handles",t.handles??{},e),...Object.values(t.handles??{}).filter(r=>r.kind==="http-capture").flatMap(T),...f("setupData",t.setupData??{},e),...f("ui",t.ui??{},e)]}async function C(t,e,r){const o=b(e.endpoints),i=b(e.databases);for(const[a,s]of o)await u(t,"endpoint",s,()=>D(a),r);for(const[a,s]of i)await u(t,"database",s,()=>{_(a)},r);for(const[a,s]of o)await u(t,"endpoint",s,()=>I(a,{signal:r,timeoutMs:m}),r);for(const[a,s]of i)await u(t,"database",s,()=>E(a,{signal:r,timeoutMs:m}),r)}function b(t){const e=new Map;for(const[r,o]of Object.entries(t))e.has(o)||e.set(o,r);return e}function _(t){try{M(t)}catch(e){throw new Error(`its URL ${l(e)}`,{cause:e})}}async function u(t,e,r,o,i){try{await o()}catch(a){throw i?.aborted?i.reason:new Error(`Supplied ${e} "${r}" for group "${t}" is not usable: ${l(a)}`,{cause:a})}}export function suppliedEnvironment(t,e){return{...y({baseUrl:e.baseUrl??null,databaseUrl:e.databaseUrl||null,databases:e.databases??{},endpoints:e.endpoints??{},env:e.env??{},group:t,...e.setupData===void 0?{}:{setupData:e.setupData},ui:e.ui??null}),...e.handles===void 0?{}:{handles:{...e.handles}}}}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{TaskPreparationError as g}from"../run/environment.js";import{bindDatabaseUrl as h}from"../../database/bindings.js";import{isEngineTaskDeadlineExceededReason as k}from"../../engines/api/index.js";import{toError as w}from"../../kernel/error-serialization.js";import{withDatabaseBindings as T}from"../../steps/index.js";export function reachedDatabases(e,t){const n=[t.databaseUrl,...Object.values(t.databases),...Object.values(t.env),JSON.stringify(t.ui)].join(`
|
|
2
|
+
`);return[...e].filter(([o])=>n.includes(o))}export async function cloneTaskDatabases(e,t,n,o,l){const d=new Map;for(const a of e.services.values())a.database!==null&&a.config.testkit.database&&d.set(a.database.database,a);const f=reachedDatabases(d,t);if(f.length===0)throw resetBeforeRefusal(n,!1);const c=new Map;try{const{cloneTaskDatabase:a,dropTaskDatabase:s}=await import("../../database/index.js");for(const[r,i]of f){const u={productDir:i.config.productDir,stateDir:i.config.stateDir},b=await a(u,i.config.name,`${o.id}:${String(n.id)}`,{signal:l.signal});c.set(r,{binding:h(b.url),drop:()=>s(u,b.databaseName)})}}catch(a){const s=k(l.signal.reason),r=l.signal.aborted?s?"deadline":"cancelled":"infra";throw new g(r,w(a),await m(c))}const p=a=>c.get(a.database)?.binding??a;let D=null;return{ready:{...e,services:new Map([...e.services].map(([a,s])=>[a,{...s,database:s.database===null?null:p(s.database),config:T(s.config,new Map([...s.config.testkit.templateContext?.databaseBindingsByService??new Map].map(([r,i])=>[r,p(i)])))}]))},release:()=>D??=m(c)}}async function m(e){const t=[];for(const n of e.values())try{await n.drop()}catch(o){t.push({error:w(o),owner:"testkit"})}return t}export function resetBeforeRefusal(e,t){const n=t?`group "${e.targetName}" runs on supplied values, and Testkit resets only a database it provisions`:`group "${e.targetName}" reaches no database Testkit provisions`;return new g("infra",new Error(`${e.file} sets runtimeIsolation "resetBefore", but ${n}`),[])}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import
|
|
1
|
+
import n from"node:path";import{posixPath as u}from"../process/files/paths.js";export function resolveRequestedFiles(e,r,s=process.cwd()){const t=p(e),i=d(r,"product"),a=d(s,"invocation"),o=[],l=new Set;for(const f of t){const c=m(f,i,a);l.has(c)||(l.add(c),o.push(c))}return o}function m(e,r,s){const t=String(e),i=n.isAbsolute(t)?[t]:[n.resolve(s,t),n.resolve(r,t)];for(const a of i){const o=u(n.relative(r,a));if(!o.startsWith("../")&&o!==".."&&!n.isAbsolute(o))return o.replace(/^\.\/+/,"")}return u(t).replace(/^\.\/+/,"")}function p(e){if(!Array.isArray(e))throw new TypeError("Requested test files must be an array");return e}function d(e,r){if(typeof e!="string")throw new TypeError(`Testkit ${r} directory must be a string`);return e}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import
|
|
1
|
+
import i from"node:path";import{collectArtifactEntries as l,listRunBundles as f,loadRun as t,verifyRunBundle as a}from"../../evidence/index.js";export function inspectArtifacts(r){const e=i.resolve(r.dir||process.cwd());if(r.mode==="runs")return{mode:"runs",runs:f(e,{file:r.file})};const u=r.runId?null:t(e),n=r.runId||u?.run.id||null;if(r.mode==="verify")return{mode:"verify",runId:n,verification:a(e,n)};const d=u??t(e,n),c=l(e,d,r.file,r.group,r.kind,r.includePayload);return{mode:"artifacts",runId:n,entries:c}}
|