@skyramp/mcp 0.4.1 → 0.4.2-rc.1
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/build/adapters/jestAdapter.js +23 -5
- package/build/adapters/mochaAdapter.js +7 -1
- package/build/adapters/playwrightAdapter.js +3 -1
- package/build/adapters/pytestAdapter.js +14 -3
- package/build/commands/localDevTestChangesCommand.js +1 -0
- package/build/commands/recommendTestsAndExecuteCommand.js +5 -6
- package/build/commands/testThisEndpointCommand.js +16 -4
- package/build/index.js +34 -4
- package/build/playwright/blueprintDigest.js +28 -7
- package/build/playwright/registerPlaywrightTools.js +33 -28
- package/build/playwright/traceRecordingPrompt.js +9 -2
- package/build/prompts/code-reuse.js +95 -29
- package/build/prompts/fix-error-prompt.d.ts +9 -1
- package/build/prompts/fix-error-prompt.js +31 -28
- package/build/prompts/local-dev/local-dev-plan.d.ts +3 -0
- package/build/prompts/local-dev/local-dev-plan.js +3 -1
- package/build/prompts/local-dev/local-dev-prompts.d.ts +1 -1
- package/build/prompts/local-dev/local-dev-prompts.js +30 -3
- package/build/prompts/modularization/integration-test-modularization.js +13 -6
- package/build/prompts/modularization/ui-test-modularization.js +1 -1
- package/build/prompts/personas.js +1 -1
- package/build/prompts/pom-aware-code-reuse.js +7 -9
- package/build/prompts/reuse-hand-off.d.ts +64 -0
- package/build/prompts/reuse-hand-off.js +130 -0
- package/build/prompts/shared-helper-policy.d.ts +88 -2
- package/build/prompts/shared-helper-policy.js +145 -11
- package/build/prompts/sut-setup/modes/adaptWorkflowPrompt.js +1 -1
- package/build/prompts/sut-setup/modes/dockerComposePrompt.js +1 -1
- package/build/prompts/sut-setup/shared.d.ts +4 -1
- package/build/prompts/sut-setup/shared.js +2 -2
- package/build/prompts/test-maintenance/actionsInstructions.d.ts +19 -11
- package/build/prompts/test-maintenance/actionsInstructions.js +47 -26
- package/build/prompts/test-maintenance/drift-analysis-prompt.js +3 -2
- package/build/prompts/test-maintenance/driftAnalysisSections.js +5 -3
- package/build/prompts/test-maintenance/driftAnalysisShared.js +4 -2
- package/build/prompts/test-maintenance/uiDriftAnalysisSections.js +7 -4
- package/build/prompts/test-recommendation/recommendationSections.js +19 -8
- package/build/prompts/test-recommendation/registerRecommendTestsPrompt.js +5 -2
- package/build/prompts/test-recommendation/test-recommendation-prompt.js +10 -7
- package/build/prompts/testbot/testbot-prompts.js +123 -55
- package/build/recommendation/answers.js +18 -9
- package/build/recommendation/pullRequestText.js +1 -1
- package/build/recommendation/registerPlan.js +31 -17
- package/build/recommendation/subjectStep.d.ts +8 -10
- package/build/recommendation/subjectStep.js +17 -16
- package/build/recommendation/types.d.ts +71 -17
- package/build/recommendation/types.js +9 -15
- package/build/recommendation/verifierContracts.d.ts +7 -3
- package/build/recommendation/verifierContracts.js +8 -4
- package/build/recommendation/verifiers/changedFile.js +11 -13
- package/build/recommendation/verifiers/citedPath.d.ts +8 -0
- package/build/recommendation/verifiers/citedPath.js +16 -2
- package/build/recommendation/verifiers/coverage.d.ts +2 -2
- package/build/recommendation/verifiers/coverage.js +190 -134
- package/build/recommendation/verifiers/defects.js +56 -16
- package/build/recommendation/verifiers/deliveredMatchesPlan.d.ts +7 -1
- package/build/recommendation/verifiers/deliveredMatchesPlan.js +28 -14
- package/build/recommendation/verifiers/endpointGrounded.js +14 -8
- package/build/recommendation/verifiers/existingCoverage.d.ts +6 -0
- package/build/recommendation/verifiers/existingCoverage.js +30 -21
- package/build/recommendation/verifiers/expectedOutcome.js +17 -8
- package/build/recommendation/verifiers/expectedValueSourced.js +54 -43
- package/build/recommendation/verifiers/issueTraceability.d.ts +5 -0
- package/build/recommendation/verifiers/issueTraceability.js +64 -7
- package/build/recommendation/verifiers/removedElementGuarded.js +19 -11
- package/build/recommendation/verifiers/reportedCategory.js +9 -4
- package/build/recommendation/verifiers/requirementSourced.js +34 -21
- package/build/recommendation/verifiers/screenRoute.js +15 -10
- package/build/recommendation/verifiers/statedDifference.js +15 -8
- package/build/recommendation/verifiers/uiElementGrounded.js +50 -16
- package/build/resources/analysisResources.js +7 -3
- package/build/resources/progressResource.js +4 -2
- package/build/resources/sutSetupResource.js +20 -2
- package/build/resources/testbotResource.js +19 -1
- package/build/services/AnalyticsService.js +3 -1
- package/build/services/ScenarioGenerationService.js +5 -5
- package/build/services/TestDiscoveryService.js +21 -5
- package/build/services/TestExecutionService.js +63 -21
- package/build/services/TestGenerationService.d.ts +1 -1
- package/build/services/TestGenerationService.js +43 -24
- package/build/skills/enhanceAssertionsSkill.d.ts +45 -0
- package/build/skills/enhanceAssertionsSkill.js +103 -0
- package/build/skills/fixTestImportErrorsSkill.d.ts +2 -2
- package/build/skills/fixTestImportErrorsSkill.js +2 -2
- package/build/skills/skillFiles.d.ts +38 -0
- package/build/skills/skillFiles.js +94 -0
- package/build/skills/validateAssertionAlignmentSkill.d.ts +34 -0
- package/build/skills/validateAssertionAlignmentSkill.js +59 -0
- package/build/tool-phases.js +4 -0
- package/build/tools/auth/loginTool.js +3 -1
- package/build/tools/auth/logoutTool.js +3 -1
- package/build/tools/code-refactor/alignAssertionsTool.d.ts +2 -0
- package/build/tools/code-refactor/alignAssertionsTool.js +51 -0
- package/build/tools/code-refactor/assertion-state.d.ts +1 -1
- package/build/tools/code-refactor/assertion-state.js +1 -1
- package/build/tools/code-refactor/assertionOperations.d.ts +44 -0
- package/build/tools/code-refactor/assertionOperations.js +82 -0
- package/build/tools/code-refactor/assertionSkillTools.d.ts +3 -0
- package/build/tools/code-refactor/assertionSkillTools.js +86 -0
- package/build/tools/code-refactor/codeReuseTool.js +27 -3
- package/build/tools/code-refactor/enhanceAssertionsTool.js +19 -83
- package/build/tools/code-refactor/gate-markers.d.ts +51 -0
- package/build/tools/code-refactor/gate-markers.js +95 -0
- package/build/tools/code-refactor/retrofit-state.d.ts +3 -1
- package/build/tools/code-refactor/retrofit-state.js +44 -2
- package/build/tools/code-refactor/reuse-outcome.d.ts +23 -1
- package/build/tools/code-refactor/reuse-outcome.js +36 -13
- package/build/tools/code-refactor/reuse-state.d.ts +90 -16
- package/build/tools/code-refactor/reuse-state.js +191 -61
- package/build/tools/code-refactor/utils-verify-gates.d.ts +4 -0
- package/build/tools/code-refactor/utils-verify-gates.js +252 -27
- package/build/tools/code-refactor/verify-gates.d.ts +15 -1
- package/build/tools/code-refactor/verify-gates.js +36 -4
- package/build/tools/enrichTestWithMocksTool.d.ts +1 -1
- package/build/tools/enrichTestWithMocksTool.js +9 -5
- package/build/tools/executeSkyrampTestTool.d.ts +22 -1
- package/build/tools/executeSkyrampTestTool.js +571 -271
- package/build/tools/execution-video-state.js +1 -1
- package/build/tools/fixErrorTool.js +5 -6
- package/build/tools/generate-tests/batchMockGenerationTool.js +1 -1
- package/build/tools/generate-tests/generateBatchScenarioRestTool.js +114 -73
- package/build/tools/generate-tests/generateContractRestTool.js +34 -16
- package/build/tools/generate-tests/generateE2ERestTool.d.ts +1 -0
- package/build/tools/generate-tests/generateE2ERestTool.js +9 -1
- package/build/tools/generate-tests/generateIntegrationRestTool.js +22 -7
- package/build/tools/generate-tests/generateMockRestTool.js +3 -1
- package/build/tools/generate-tests/generateUIRestTool.d.ts +2 -0
- package/build/tools/generate-tests/generateUIRestTool.js +11 -2
- package/build/tools/generate-tests/loadTestSchema.js +1 -3
- package/build/tools/generate-tests/planGuard.js +6 -3
- package/build/tools/generate-tests/scenarioFileIdentity.js +4 -1
- package/build/tools/generate-tests/scenarioLint.js +17 -5
- package/build/tools/generate-tests/trace-reuse-guard.js +5 -2
- package/build/tools/generateEnrichedIntegrationTestTool.js +9 -3
- package/build/tools/one-click/oneClickTool.js +3 -1
- package/build/tools/preflightMockCheckTool.js +23 -7
- package/build/tools/runExistingTestsTool.d.ts +1 -1
- package/build/tools/runExistingTestsTool.js +43 -21
- package/build/tools/submitReportTool.d.ts +51 -12
- package/build/tools/submitReportTool.js +860 -161
- package/build/tools/test-management/actionsTool.js +210 -51
- package/build/tools/test-management/analyzeChangesTool.d.ts +4 -5
- package/build/tools/test-management/analyzeChangesTool.js +127 -68
- package/build/tools/test-management/analyzeTestHealthTool.js +35 -13
- package/build/tools/test-management/registerTestPlanTool.d.ts +44 -34
- package/build/tools/test-management/registerTestPlanTool.js +255 -111
- package/build/tools/test-management/resolveScreenTool.js +33 -9
- package/build/tools/trace/startTraceCollectionTool.js +3 -1
- package/build/tools/trace/stopTraceCollectionTool.js +41 -5
- package/build/tools/verifyTestDependenciesTool.d.ts +3 -0
- package/build/tools/verifyTestDependenciesTool.js +54 -0
- package/build/tools/workspace/initScanWorkspaceTool.js +9 -3
- package/build/tools/workspace/initializeWorkspaceTool.js +3 -1
- package/build/types/AssertionOutcome.d.ts +1 -1
- package/build/types/EnhanceType.d.ts +6 -0
- package/build/types/EnhanceType.js +1 -0
- package/build/types/ExternalTestExecution.d.ts +2 -2
- package/build/types/RepositoryAnalysis.d.ts +0 -40
- package/build/types/ReuseOutcome.d.ts +96 -4
- package/build/types/ReuseOutcome.js +16 -0
- package/build/types/StepMethod.js +20 -6
- package/build/types/TestAnalysis.d.ts +10 -2
- package/build/types/TestExecution.d.ts +45 -0
- package/build/types/TestRecommendation.d.ts +1 -1
- package/build/types/TestRecommendation.js +4 -1
- package/build/types/TestTypes.d.ts +13 -0
- package/build/types/TestTypes.js +34 -3
- package/build/types/TestbotPromptOptions.d.ts +9 -1
- package/build/types/TestbotReport.d.ts +45 -9
- package/build/utils/AnalysisStateManager.d.ts +137 -27
- package/build/utils/AnalysisStateManager.js +227 -43
- package/build/utils/assertion-verify/api-shared-lints.js +34 -16
- package/build/utils/assertion-verify/metrics.js +39 -6
- package/build/utils/assertion-verify/ui-lints.js +4 -2
- package/build/utils/branchDiff.js +47 -12
- package/build/utils/canonicalJson.js +3 -1
- package/build/utils/dartRouteExtractor.js +36 -7
- package/build/utils/fixAttempts.d.ts +26 -0
- package/build/utils/fixAttempts.js +109 -0
- package/build/utils/frontendSelectors.js +23 -4
- package/build/utils/generatedTestRecord.d.ts +19 -0
- package/build/utils/generatedTestRecord.js +61 -0
- package/build/utils/gitStaging.js +7 -2
- package/build/utils/initAgent.js +26 -6
- package/build/utils/language-helper.js +39 -45
- package/build/utils/pathMatching.js +2 -1
- package/build/utils/pathSignatures.js +6 -2
- package/build/utils/planMatchKeys.d.ts +2 -2
- package/build/utils/planMatchKeys.js +20 -14
- package/build/utils/pom-catalog-parse.js +7 -2
- package/build/utils/pom-scope/import-expansion.js +6 -1
- package/build/utils/pom-scope/index.js +50 -12
- package/build/utils/pom-scope/scoring.js +13 -3
- package/build/utils/pom-scope/selector-extractor.js +16 -3
- package/build/utils/pom-scope/strip.d.ts +8 -0
- package/build/utils/pom-scope/strip.js +238 -0
- package/build/utils/pom-scope/testIdDiscovery.js +14 -2
- package/build/utils/pom-verify/__fixtures__/af-style/asset-list.page.d.ts +1 -1
- package/build/utils/pom-verify/__fixtures__/af-style/asset-list.page.js +4 -2
- package/build/utils/pom-verify/__fixtures__/af-style/report.iframe.page.js +3 -1
- package/build/utils/pom-verify/__fixtures__/af-style/workflow-footer.page.js +3 -1
- package/build/utils/pom-verify/bindings.js +5 -1
- package/build/utils/pom-verify/calls.js +9 -2
- package/build/utils/pom-verify/verify.js +27 -5
- package/build/utils/pr-comment-parser.js +20 -7
- package/build/utils/proxy-terminal.d.ts +19 -1
- package/build/utils/proxy-terminal.js +346 -21
- package/build/utils/removedUiElements.js +1 -1
- package/build/utils/reportLanguage.js +35 -7
- package/build/utils/reportVerification.d.ts +14 -8
- package/build/utils/reportVerification.js +19 -19
- package/build/utils/repositorySlug.d.ts +32 -0
- package/build/utils/repositorySlug.js +77 -0
- package/build/utils/reuseRouting.js +6 -2
- package/build/utils/runSerialized.d.ts +3 -0
- package/build/utils/runSerialized.js +39 -0
- package/build/utils/screenRoutes.js +74 -18
- package/build/utils/sourceRouteExtractor.js +13 -6
- package/build/utils/telemetry.d.ts +1 -0
- package/build/utils/telemetry.js +8 -5
- package/build/utils/testDependencyPolicy.d.ts +9 -0
- package/build/utils/testDependencyPolicy.js +788 -0
- package/build/utils/testExecutionRecord.d.ts +90 -0
- package/build/utils/testExecutionRecord.js +267 -0
- package/build/utils/testFileClassification.js +3 -1
- package/build/utils/trace-parser.js +62 -14
- package/build/utils/urlPath.js +3 -1
- package/build/utils/utils-verify/action-key.d.ts +4 -0
- package/build/utils/utils-verify/action-key.js +2 -2
- package/build/utils/utils-verify/allow.d.ts +122 -3
- package/build/utils/utils-verify/allow.js +146 -21
- package/build/utils/utils-verify/body-reach.d.ts +120 -0
- package/build/utils/utils-verify/body-reach.js +335 -0
- package/build/utils/utils-verify/call-sites.d.ts +6 -1
- package/build/utils/utils-verify/call-sites.js +72 -8
- package/build/utils/utils-verify/delivered-imports.d.ts +43 -0
- package/build/utils/utils-verify/delivered-imports.js +84 -0
- package/build/utils/utils-verify/fixed-sleep.d.ts +96 -0
- package/build/utils/utils-verify/fixed-sleep.js +461 -0
- package/build/utils/utils-verify/in-house.d.ts +93 -0
- package/build/utils/utils-verify/in-house.js +719 -0
- package/build/utils/utils-verify/incumbent.d.ts +3 -0
- package/build/utils/utils-verify/incumbent.js +75 -0
- package/build/utils/utils-verify/index.d.ts +1 -0
- package/build/utils/utils-verify/index.js +1 -0
- package/build/utils/utils-verify/language-spec.d.ts +26 -10
- package/build/utils/utils-verify/language-spec.js +217 -20
- package/build/utils/utils-verify/locate.d.ts +26 -0
- package/build/utils/utils-verify/locate.js +125 -23
- package/build/utils/utils-verify/module-name.d.ts +40 -0
- package/build/utils/utils-verify/module-name.js +98 -0
- package/build/utils/utils-verify/parse.d.ts +46 -6
- package/build/utils/utils-verify/parse.js +176 -38
- package/build/utils/utils-verify/retrofit-equivalence.d.ts +5 -0
- package/build/utils/utils-verify/retrofit-equivalence.js +4 -2
- package/build/utils/utils-verify/stage.d.ts +5 -0
- package/build/utils/utils-verify/stage.js +47 -2
- package/build/utils/utils-verify/status-once.d.ts +62 -0
- package/build/utils/utils-verify/status-once.js +207 -0
- package/build/utils/utils-verify/typecheck.d.ts +61 -0
- package/build/utils/utils-verify/typecheck.js +338 -0
- package/build/utils/utils-verify/verify.d.ts +76 -1
- package/build/utils/utils-verify/verify.js +516 -44
- package/build/utils/versions.d.ts +3 -3
- package/build/utils/versions.js +1 -1
- package/build/utils/workspaceAuth.js +107 -37
- package/build/workspace/queryParamResolution.js +11 -4
- package/build/workspace/workspace.js +7 -7
- package/node_modules/playwright/ThirdPartyNotices.txt +19 -19
- package/node_modules/playwright/lib/mcp/skyramp/assertTool.js +8 -2
- package/node_modules/playwright/lib/mcp/skyramp/common/cssValue.js +87 -0
- package/node_modules/playwright/lib/mcp/skyramp/loadTraceTool.js +31 -0
- package/node_modules/playwright/lib/mcp/skyramp/skyRampImport.js +3 -0
- package/node_modules/playwright/lib/mcp/skyramp/traceRecordingBackend.js +181 -15
- package/node_modules/playwright/lib/mcp/test/skyRampExport.js +24 -0
- package/node_modules/playwright/lib/transform/babelBundleImpl.js +2353 -190
- package/node_modules/playwright/node_modules/playwright-core/ThirdPartyNotices.txt +62 -34
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/.package-lock.json +72 -41
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/@hono/node-server/dist/serve-static.js +1 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/@hono/node-server/dist/serve-static.mjs +1 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/@hono/node-server/package.json +2 -2
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/body-parser/README.md +16 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/body-parser/index.js +4 -20
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/body-parser/lib/read.js +17 -17
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/body-parser/lib/types/json.js +60 -32
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/body-parser/lib/types/raw.js +3 -3
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/body-parser/lib/types/text.js +3 -3
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/body-parser/lib/types/urlencoded.js +16 -20
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/body-parser/lib/utils.js +18 -16
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/body-parser/node_modules/content-type/LICENSE +22 -0
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/body-parser/node_modules/content-type/README.md +71 -0
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/body-parser/node_modules/content-type/dist/index.d.ts +46 -0
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/body-parser/node_modules/content-type/dist/index.js +176 -0
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/body-parser/node_modules/content-type/dist/index.js.map +1 -0
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/body-parser/node_modules/content-type/package.json +52 -0
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/body-parser/package.json +23 -10
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/es-object-atoms/CHANGELOG.md +21 -14
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/es-object-atoms/isObject.d.ts +1 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/es-object-atoms/package.json +6 -7
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/es-object-atoms/tsconfig.json +1 -0
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/fast-uri/index.js +266 -45
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/fast-uri/lib/schemes.js +9 -4
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/fast-uri/lib/utils.js +396 -92
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/fast-uri/package.json +1 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/fast-uri/test/component-safe-serialization.test.js +163 -0
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/fast-uri/test/equal.test.js +31 -3
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/fast-uri/test/fixtures/uri-js-parse.json +2 -0
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/fast-uri/test/ipv6-canonical.test.js +34 -0
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/fast-uri/test/ipv6-validation.test.js +124 -0
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/fast-uri/test/malformed-percent.test.js +77 -0
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/fast-uri/test/malformed-urn.test.js +61 -0
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/fast-uri/test/parse.test.js +7 -3
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/fast-uri/test/query-fragment-normalization.test.js +33 -0
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/fast-uri/test/reserved-path-normalization.test.js +109 -0
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/fast-uri/test/scheme-validation.test.js +124 -0
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/fast-uri/test/security-normalization.test.js +101 -0
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/fast-uri/test/security.test.js +301 -3
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/fast-uri/test/urn-full-input.test.js +29 -0
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/fast-uri/test/websocket-query-preservation.test.js +24 -0
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hasown/CHANGELOG.md +7 -0
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hasown/index.d.ts +0 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hasown/package.json +4 -5
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/client/client.js +30 -16
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/client/utils.js +4 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/context.js +32 -13
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/helper/accepts/accepts.js +36 -2
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/helper/proxy/index.js +4 -0
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/helper/ssg/ssg.js +1 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/helper/ssg/utils.js +30 -10
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/helper/streaming/sse.js +5 -4
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/hono-base.js +10 -8
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/jsx/base.js +44 -23
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/jsx/components.js +25 -26
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/jsx/context.js +5 -5
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/jsx/dom/render.js +2 -0
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/jsx/dom/server.js +5 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/jsx/hooks/index.js +16 -13
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/jsx/intrinsic-element/components.js +3 -3
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/jsx/streaming.js +4 -5
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/middleware/cache/index.js +103 -8
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/middleware/compress/index.js +5 -0
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/middleware/cors/index.js +17 -14
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/middleware/csrf/index.js +1 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/middleware/etag/digest.js +47 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/middleware/etag/index.js +7 -4
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/middleware/jwk/jwk.js +9 -4
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/middleware/jwt/jwt.js +9 -4
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/middleware/language/language.js +10 -6
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/middleware/method-not-allowed/index.js +90 -0
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/middleware/pretty-json/index.js +3 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/middleware/secure-headers/secure-headers.js +16 -7
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/request.js +20 -13
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/router/linear-router/router.js +7 -2
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/router/pattern-router/router.js +3 -9
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/router/reg-exp-router/node.js +65 -59
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/router/reg-exp-router/router.js +71 -128
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/router/reg-exp-router/trie.js +14 -5
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/router/trie-router/node.js +47 -70
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/router/trie-router/router.js +3 -11
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/router/utils.js +27 -0
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/router.js +1 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/utils/accept.js +1 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/utils/body.js +21 -3
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/utils/cookie.js +4 -3
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/utils/ipaddr.js +5 -3
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/utils/stream.js +12 -3
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/utils/url.js +19 -11
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/client/client.js +30 -16
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/client/utils.js +4 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/context.js +32 -13
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/helper/accepts/accepts.js +36 -2
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/helper/proxy/index.js +4 -0
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/helper/ssg/ssg.js +1 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/helper/ssg/utils.js +30 -10
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/helper/streaming/sse.js +5 -4
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/hono-base.js +10 -8
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/jsx/base.js +41 -23
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/jsx/components.js +26 -27
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/jsx/context.js +6 -6
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/jsx/dom/render.js +2 -0
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/jsx/dom/server.js +5 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/jsx/hooks/index.js +16 -13
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/jsx/intrinsic-element/components.js +4 -4
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/jsx/streaming.js +5 -6
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/middleware/cache/index.js +103 -8
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/middleware/compress/index.js +5 -0
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/middleware/cors/index.js +17 -14
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/middleware/csrf/index.js +1 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/middleware/etag/digest.js +47 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/middleware/etag/index.js +7 -4
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/middleware/jwk/jwk.js +9 -4
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/middleware/jwt/jwt.js +9 -4
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/middleware/language/language.js +10 -6
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/middleware/method-not-allowed/index.js +68 -0
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/middleware/pretty-json/index.js +3 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/middleware/secure-headers/secure-headers.js +16 -7
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/request.js +21 -14
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/router/linear-router/router.js +7 -2
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/router/pattern-router/router.js +3 -9
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/router/reg-exp-router/node.js +61 -58
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/router/reg-exp-router/router.js +77 -129
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/router/reg-exp-router/trie.js +14 -5
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/router/trie-router/node.js +47 -70
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/router/trie-router/router.js +3 -11
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/router/utils.js +5 -0
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/router.js +1 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/types/adapter/aws-lambda/types.d.ts +9 -0
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/types/client/types.d.ts +1 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/types/context.d.ts +6 -2
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/types/hono-base.d.ts +4 -3
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/types/jsx/base.d.ts +7 -2
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/types/jsx/dom/index.d.ts +5 -5
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/types/jsx/dom/intrinsic-element/components.d.ts +2 -2
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/types/jsx/dom/server.d.ts +5 -5
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/types/jsx/hooks/index.d.ts +8 -6
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/types/jsx/index.d.ts +5 -5
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/types/middleware/cache/index.d.ts +6 -4
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/types/middleware/combine/index.d.ts +1 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/types/middleware/cors/index.d.ts +1 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/types/middleware/jsx-renderer/index.d.ts +2 -2
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/types/middleware/jwk/jwk.d.ts +2 -0
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/types/middleware/jwt/jwt.d.ts +2 -0
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/types/middleware/method-not-allowed/index.d.ts +49 -0
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/types/middleware/secure-headers/permissions-policy.d.ts +3 -3
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/types/router/reg-exp-router/node.d.ts +4 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/types/router/reg-exp-router/trie.d.ts +2 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/types/router/trie-router/node.d.ts +1 -2
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/types/router/trie-router/router.d.ts +0 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/types/router/utils.d.ts +1 -0
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/types/router.d.ts +1 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/types/utils/headers.d.ts +2 -2
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/types/utils/url.d.ts +5 -0
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/utils/accept.js +1 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/utils/body.js +21 -3
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/utils/cookie.js +5 -4
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/utils/ipaddr.js +5 -3
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/utils/stream.js +12 -3
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/utils/url.js +17 -10
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/package.json +11 -4
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/ip-address/README.md +173 -143
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/ip-address/dist/address-error.d.ts +11 -0
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/ip-address/dist/address-error.js.map +1 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/ip-address/dist/common.d.ts +49 -0
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/ip-address/dist/common.js +79 -4
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/ip-address/dist/common.js.map +1 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/ip-address/dist/ipv4.d.ts +78 -5
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/ip-address/dist/ipv4.js +119 -24
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/ip-address/dist/ipv4.js.map +1 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/ip-address/dist/ipv6.d.ts +151 -10
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/ip-address/dist/ipv6.js +316 -90
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/ip-address/dist/ipv6.js.map +1 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/ip-address/dist/v4/constants.d.ts +12 -0
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/ip-address/dist/v4/constants.js +45 -2
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/ip-address/dist/v4/constants.js.map +1 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/ip-address/dist/v6/constants.d.ts +14 -0
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/ip-address/dist/v6/constants.js +50 -3
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/ip-address/dist/v6/constants.js.map +1 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/ip-address/package.json +6 -4
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/qs/.github/THREAT_MODEL.md +3 -3
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/qs/CHANGELOG.md +26 -0
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/qs/README.md +19 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/qs/dist/qs.js +25 -25
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/qs/eslint.config.mjs +1 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/qs/lib/parse.js +16 -6
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/qs/lib/stringify.js +23 -8
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/qs/lib/utils.js +57 -11
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/qs/package.json +8 -7
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/qs/test/parse.js +419 -0
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/qs/test/stringify.js +317 -0
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/qs/test/utils.js +206 -0
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/side-channel/CHANGELOG.md +10 -0
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/side-channel/README.md +1 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/side-channel/index.js +5 -2
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/side-channel/package.json +10 -10
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/side-channel/test/index.js +16 -0
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/type-is/index.js +8 -18
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/type-is/node_modules/content-type/LICENSE +22 -0
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/type-is/node_modules/content-type/README.md +71 -0
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/type-is/node_modules/content-type/dist/index.d.ts +46 -0
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/type-is/node_modules/content-type/dist/index.js +176 -0
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/type-is/node_modules/content-type/dist/index.js.map +1 -0
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/type-is/node_modules/content-type/package.json +52 -0
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/type-is/package.json +9 -5
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/package-lock.json +72 -41
- package/node_modules/playwright/node_modules/playwright-core/bundles/utils/node_modules/.package-lock.json +6 -6
- package/node_modules/playwright/node_modules/playwright-core/bundles/utils/node_modules/brace-expansion/README.md +23 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/utils/node_modules/brace-expansion/index.js +265 -86
- package/node_modules/playwright/node_modules/playwright-core/bundles/utils/node_modules/brace-expansion/package.json +1 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/utils/node_modules/ip-address/README.md +173 -143
- package/node_modules/playwright/node_modules/playwright-core/bundles/utils/node_modules/ip-address/dist/address-error.d.ts +11 -0
- package/node_modules/playwright/node_modules/playwright-core/bundles/utils/node_modules/ip-address/dist/address-error.js.map +1 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/utils/node_modules/ip-address/dist/common.d.ts +49 -0
- package/node_modules/playwright/node_modules/playwright-core/bundles/utils/node_modules/ip-address/dist/common.js +79 -4
- package/node_modules/playwright/node_modules/playwright-core/bundles/utils/node_modules/ip-address/dist/common.js.map +1 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/utils/node_modules/ip-address/dist/ipv4.d.ts +78 -5
- package/node_modules/playwright/node_modules/playwright-core/bundles/utils/node_modules/ip-address/dist/ipv4.js +119 -24
- package/node_modules/playwright/node_modules/playwright-core/bundles/utils/node_modules/ip-address/dist/ipv4.js.map +1 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/utils/node_modules/ip-address/dist/ipv6.d.ts +151 -10
- package/node_modules/playwright/node_modules/playwright-core/bundles/utils/node_modules/ip-address/dist/ipv6.js +316 -90
- package/node_modules/playwright/node_modules/playwright-core/bundles/utils/node_modules/ip-address/dist/ipv6.js.map +1 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/utils/node_modules/ip-address/dist/v4/constants.d.ts +12 -0
- package/node_modules/playwright/node_modules/playwright-core/bundles/utils/node_modules/ip-address/dist/v4/constants.js +45 -2
- package/node_modules/playwright/node_modules/playwright-core/bundles/utils/node_modules/ip-address/dist/v4/constants.js.map +1 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/utils/node_modules/ip-address/dist/v6/constants.d.ts +14 -0
- package/node_modules/playwright/node_modules/playwright-core/bundles/utils/node_modules/ip-address/dist/v6/constants.js +50 -3
- package/node_modules/playwright/node_modules/playwright-core/bundles/utils/node_modules/ip-address/dist/v6/constants.js.map +1 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/utils/node_modules/ip-address/package.json +6 -4
- package/node_modules/playwright/node_modules/playwright-core/bundles/utils/package-lock.json +6 -6
- package/node_modules/playwright/node_modules/playwright-core/lib/cli/program.js +18 -9
- package/node_modules/playwright/node_modules/playwright-core/lib/mcpBundleImpl/index.js +47 -47
- package/node_modules/playwright/node_modules/playwright-core/lib/server/codegen/skyramp/jsonlReader.js +3 -0
- package/node_modules/playwright/node_modules/playwright-core/lib/server/recorder/recorderRunner.js +42 -0
- package/node_modules/playwright/node_modules/playwright-core/lib/utilsBundleImpl/index.js +121 -121
- package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/{index.B7KbSQcC.js → index.BAkLd5DX.js} +1 -1
- package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/index.html +1 -1
- package/node_modules/playwright/node_modules/playwright-core/package.json +1 -1
- package/node_modules/playwright/node_modules/playwright-core/src/cli/program.ts +31 -9
- package/node_modules/playwright/node_modules/playwright-core/src/server/codegen/skyramp/jsonlReader.ts +1 -0
- package/node_modules/playwright/node_modules/playwright-core/src/server/recorder/recorderRunner.ts +57 -1
- package/node_modules/playwright/package.json +2 -2
- package/package.json +7 -6
- package/plugin/prompts/code-reuse/hand-off.md +30 -0
- package/plugin/prompts/generate-tests/generation.md +1 -1
- package/plugin/prompts/plan-tests.md +14 -14
- package/plugin/prompts/testbot-task1.md +4 -2
- package/plugin/skills/enhance-assertions/SKILL.md +25 -0
- package/plugin/skills/enhance-assertions/reference/contract.md +51 -0
- package/plugin/skills/enhance-assertions/reference/integration.md +58 -0
- package/plugin/skills/enhance-assertions/reference/shared-rules.md +220 -0
- package/plugin/skills/enhance-assertions/reference/ui.md +373 -0
- package/plugin/skills/fix-test-import-errors/SKILL.md +44 -50
- package/plugin/skills/validate-assertion-alignment-post-execution/SKILL.md +32 -0
- package/plugin/skills/validate-assertion-alignment-post-execution/reference/checks.md +44 -0
- package/plugin/skills/validate-assertion-alignment-post-execution/reference/evidence.md +47 -0
- package/build/prompts/enhance-assertions/contractProviderAssertionsPrompt.d.ts +0 -2
- package/build/prompts/enhance-assertions/contractProviderAssertionsPrompt.js +0 -29
- package/build/prompts/enhance-assertions/integrationAssertionsPrompt.d.ts +0 -2
- package/build/prompts/enhance-assertions/integrationAssertionsPrompt.js +0 -36
- package/build/prompts/enhance-assertions/sharedAssertionRules.d.ts +0 -16
- package/build/prompts/enhance-assertions/sharedAssertionRules.js +0 -284
- package/build/prompts/enhance-assertions/uiAssertionsPrompt.d.ts +0 -2
- package/build/prompts/enhance-assertions/uiAssertionsPrompt.js +0 -388
- package/node_modules/playwright/node_modules/playwright-core/.DS_Store +0 -0
|
@@ -10,13 +10,18 @@ import { makeProgressReporter } from "../utils/progress.js";
|
|
|
10
10
|
import { TestExecutionStatus, } from "../types/TestExecution.js";
|
|
11
11
|
import { getWorkspaceBaseUrl } from "../utils/workspaceAuth.js";
|
|
12
12
|
import { ProgrammingLanguage, TestType } from "../types/TestTypes.js";
|
|
13
|
-
import { StateManager, getTestsRepoDir, } from "../utils/AnalysisStateManager.js";
|
|
14
|
-
import { DriftAction, TestSource } from "../types/TestAnalysis.js";
|
|
13
|
+
import { StateManager, currentRunStateFile, getTestsRepoDir, resolveOwnRunStatePath, resolveRunStatePath, } from "../utils/AnalysisStateManager.js";
|
|
14
|
+
import { DriftAction, TestSource, } from "../types/TestAnalysis.js";
|
|
15
15
|
import { logger } from "../utils/logger.js";
|
|
16
16
|
import { toolError } from "../utils/utils.js";
|
|
17
17
|
import { recordExecutionVideo } from "./execution-video-state.js";
|
|
18
18
|
import { stageGeneratedPaths } from "../utils/gitStaging.js";
|
|
19
|
+
import { canonicalStateFilePath, persistTestExecutionResult, readPinnedMaxFixAttempts, readRepoSectionOrThrow, reserveTestExecutionAttempt, stateFileKey, } from "../utils/testExecutionRecord.js";
|
|
20
|
+
import { canonicalTestPath } from "./code-refactor/assertion-state.js";
|
|
21
|
+
import { getMaxFixAttempts } from "../utils/fixAttempts.js";
|
|
22
|
+
import { runSerialized } from "../utils/runSerialized.js";
|
|
19
23
|
import * as fs from "fs";
|
|
24
|
+
import { sha256Of } from "../utils/assertion-verify/index.js";
|
|
20
25
|
import { baselineFileMatchesStem, baselineStem, rebaselineSnapshotNameSchema, snapshotDirFor, } from "../utils/rebaselineSnapshots.js";
|
|
21
26
|
import { EXECUTOR_DOCKER_IMAGE } from "../utils/versions.js";
|
|
22
27
|
const TOOL_NAME = "skyramp_execute_test";
|
|
@@ -193,7 +198,11 @@ export function diffBaselineState(before, after) {
|
|
|
193
198
|
export function authorizeRebaseline(stateData, testFile, requested) {
|
|
194
199
|
if (requested.length === 0)
|
|
195
200
|
return {};
|
|
196
|
-
|
|
201
|
+
// Canonical on both sides: the verdict and the row were written by analysis,
|
|
202
|
+
// the argument by the agent, and `/repo/tests/./a.spec.ts` is one file.
|
|
203
|
+
const key = canonicalTestPath(testFile);
|
|
204
|
+
const verdict = (stateData?.maintenanceVerdicts ?? []).find((v) => canonicalTestPath(String(v.testFilePath ?? "")) === key &&
|
|
205
|
+
v.action === DriftAction.Update);
|
|
197
206
|
if (!verdict) {
|
|
198
207
|
return {
|
|
199
208
|
error: `rebaselineSnapshots refused: no UPDATE verdict for ${testFile} in the stateFile. Only a maintained test whose skyramp_analyze_test_health verdict listed the baselines can be refreshed — a newly generated test writes its own baseline on its first run and has nothing to refresh.`,
|
|
@@ -206,8 +215,12 @@ export function authorizeRebaseline(stateData, testFile, requested) {
|
|
|
206
215
|
error: `rebaselineSnapshots refused: ${unauthorized.join(", ")} not in the UPDATE verdict for ${path.basename(testFile)} (authorized: ${authorized.size ? [...authorized].join(", ") : "none"}). Pass exactly the rebaseline_snapshots skyramp_actions returned, using the name the test passes to toHaveScreenshot (page-001.png), not the on-disk file (page-001-chromium-linux.png).`,
|
|
207
216
|
};
|
|
208
217
|
}
|
|
209
|
-
const entry = (stateData?.existingTests ?? []).find((t) => t.testFile ===
|
|
210
|
-
|
|
218
|
+
const entry = (stateData?.existingTests ?? []).find((t) => canonicalTestPath(t.testFile) === key);
|
|
219
|
+
// The reservation writes an Unknown placeholder into this row while a before
|
|
220
|
+
// run is in flight (SKYR-4460); a run that died there left no evidence, so
|
|
221
|
+
// the placeholder must not read as a recorded baseline.
|
|
222
|
+
if (!entry?.executionBefore ||
|
|
223
|
+
entry.executionBefore.status === TestExecutionStatus.Unknown) {
|
|
211
224
|
return {
|
|
212
225
|
error: `rebaselineSnapshots refused: no phase: "before" execution is recorded for ${path.basename(testFile)}. Run the pre-edit baseline first (it is the evidence the baseline is stale), then pass rebaselineSnapshots on the final run.`,
|
|
213
226
|
};
|
|
@@ -237,7 +250,9 @@ export function applyRefreshOutcomeToVerdicts(verdicts, testFile, outcome, execu
|
|
|
237
250
|
return { verdicts };
|
|
238
251
|
let note;
|
|
239
252
|
const next = verdicts.map((v) => {
|
|
240
|
-
if (v.testFilePath
|
|
253
|
+
if (canonicalTestPath(String(v.testFilePath ?? "")) !==
|
|
254
|
+
canonicalTestPath(testFile) ||
|
|
255
|
+
v.action !== DriftAction.Update)
|
|
241
256
|
return v;
|
|
242
257
|
const remaining = (v.rebaselineSnapshots ?? []).filter((n) => !outcome.notRefreshed.includes(n));
|
|
243
258
|
const reason = `baseline refresh of ${outcome.notRefreshed.join(", ")} was not applied by ${executorImage} (its @skyramp/skyramp lacks SKYRAMP_UPDATE_SNAPSHOTS, or the name matches no toHaveScreenshot call)`;
|
|
@@ -246,7 +261,11 @@ export function applyRefreshOutcomeToVerdicts(verdicts, testFile, outcome, execu
|
|
|
246
261
|
const { rebaselineSnapshots: _dropped, rebaselineOnly: _only, ...rest } = v;
|
|
247
262
|
void _dropped;
|
|
248
263
|
void _only;
|
|
249
|
-
return {
|
|
264
|
+
return {
|
|
265
|
+
...rest,
|
|
266
|
+
action: DriftAction.Verify,
|
|
267
|
+
rationale: `${v.rationale} [${reason}]`,
|
|
268
|
+
};
|
|
250
269
|
}
|
|
251
270
|
note = `Verdict for ${path.basename(testFile)}: ${reason}; the UPDATE is held to its spec/POM edit only.`;
|
|
252
271
|
const { rebaselineSnapshots: _dropped, ...rest } = v;
|
|
@@ -275,7 +294,84 @@ export function describeRefreshOutcome(outcome) {
|
|
|
275
294
|
}
|
|
276
295
|
return parts.join(" ");
|
|
277
296
|
}
|
|
278
|
-
|
|
297
|
+
/**
|
|
298
|
+
* The fix-and-rerun attempt cap (SKYR-4460), enforced where the prompt's prose
|
|
299
|
+
* cannot be: a file that has already received `cap` runs in the final phase
|
|
300
|
+
* gets a refusal instead of another execution. Only the "after" phase counts —
|
|
301
|
+
* a maintained test's baseline run is evidence, not an attempt — and a record
|
|
302
|
+
* from before the counter existed reads as zero attempts.
|
|
303
|
+
*
|
|
304
|
+
* Deliberate limit: `phase: "before"` runs are never refused. The cap bounds
|
|
305
|
+
* the fix-and-rerun loop, which is a final-phase activity; a baseline is taken
|
|
306
|
+
* once per file by the prompt (and once per existing test by the baseline
|
|
307
|
+
* runner), so there is no loop to bound there. A runaway baseline loop would
|
|
308
|
+
* need its own guard — it is not this one.
|
|
309
|
+
*/
|
|
310
|
+
export function fixAttemptRefusal(record, phase, cap, testFile) {
|
|
311
|
+
if (phase !== "after")
|
|
312
|
+
return undefined;
|
|
313
|
+
const prior = record?.afterRuns ?? 0;
|
|
314
|
+
if (prior < cap)
|
|
315
|
+
return undefined;
|
|
316
|
+
return (`Attempt cap reached: ${path.basename(testFile)} has already been executed ` +
|
|
317
|
+
`${prior} time${prior === 1 ? "" : "s"} in the final phase, and the cap for this ` +
|
|
318
|
+
`run is ${cap} (maxFixAttempts). It was NOT run again. Do not edit and re-run it: ` +
|
|
319
|
+
// The report accepts Pass, Fail or Skipped: a run that errored, or one that
|
|
320
|
+
// recorded no result, is reported as Fail.
|
|
321
|
+
(record?.status === TestExecutionStatus.Pass
|
|
322
|
+
? `report it as status "Pass" (its last run passed)`
|
|
323
|
+
: record?.status && record.status !== TestExecutionStatus.Unknown
|
|
324
|
+
? `report it as status "Fail" (its last run ended ${record.status})`
|
|
325
|
+
: `its last run recorded no result, so the report will publish "Unknown" for it — describe the failure in its details`) +
|
|
326
|
+
` with the failure details already in your context, then move on. A failing test ` +
|
|
327
|
+
`that documents a real bug is a valid outcome; say in the report whether the ` +
|
|
328
|
+
`failure is the bug or the test, and that the attempt cap was reached.`);
|
|
329
|
+
}
|
|
330
|
+
/** The budget line appended to a failure, so the agent knows how many
|
|
331
|
+
* fix-and-rerun attempts remain for this file before it must report. */
|
|
332
|
+
/** Wait before the tool's single retry of a transient connection error.
|
|
333
|
+
* Module state with a test seam, so the handler test does not sleep 10s. */
|
|
334
|
+
let transientRetryDelayMs = 10_000;
|
|
335
|
+
export function setTransientRetryDelayForTests(ms) {
|
|
336
|
+
transientRetryDelayMs = ms;
|
|
337
|
+
}
|
|
338
|
+
/** Appended to the response when the tool re-ran a thrown transient connection
|
|
339
|
+
* error itself: two executions, one attempt. The prompt withholds the agent's
|
|
340
|
+
* own unchanged re-run when it sees this, so one attempt is never three runs. */
|
|
341
|
+
const TRANSIENT_RETRY_NOTE = `\n\nNote: the executor hit a transient connection error and re-ran this file once unchanged before answering; the two runs count as one attempt. Do not re-run it unchanged again — fix the cause the output names, or report it.`;
|
|
342
|
+
/** The warning both result paths append when the run's state could not take
|
|
343
|
+
* the result: the attempt was counted at reservation, the record was not. */
|
|
344
|
+
function persistFailureWarning(stateFile, reason) {
|
|
345
|
+
return (`\n\nWarning: this run's result could not be recorded in stateFile ` +
|
|
346
|
+
`${stateFile} (${reason}). The attempt was counted; the report will read ` +
|
|
347
|
+
`this file's result as Unknown unless the state file is repaired.`);
|
|
348
|
+
}
|
|
349
|
+
export function describeAttempt(priorAfterRuns, cap, opts = {}) {
|
|
350
|
+
const attempt = priorAfterRuns + 1;
|
|
351
|
+
const remaining = Math.max(0, cap - attempt);
|
|
352
|
+
const head = `Execution attempt ${attempt} of ${cap} for this file (maxFixAttempts=${cap}).`;
|
|
353
|
+
if (remaining === 0) {
|
|
354
|
+
return (`${head} No fix-and-rerun attempts remain: do not edit and re-run this file ` +
|
|
355
|
+
`again — report it as failed with these details.`);
|
|
356
|
+
}
|
|
357
|
+
const budget = `${head} ${remaining} fix-and-rerun attempt${remaining === 1 ? "" : "s"} remain` +
|
|
358
|
+
`${remaining === 1 ? "s" : ""}. `;
|
|
359
|
+
if (opts.unchangedRerun) {
|
|
360
|
+
// The file's contents did not move since the previous run: this WAS the
|
|
361
|
+
// one unchanged re-run the file gets. Say so instead of offering another.
|
|
362
|
+
return (budget +
|
|
363
|
+
`This run was an unchanged re-run of the previous one (same file contents), ` +
|
|
364
|
+
`so no further unchanged re-run is allowed for this file: change the test ` +
|
|
365
|
+
`file or its inputs to address the cause above, or report it.`);
|
|
366
|
+
}
|
|
367
|
+
return (budget +
|
|
368
|
+
`Re-run only after changing the test file or its ` +
|
|
369
|
+
`inputs to address the cause above. A file gets ONE unchanged re-run, for ` +
|
|
370
|
+
`either of two failures: a run that produced no output at all, or a ` +
|
|
371
|
+
`connection error — and not even that when this response carries the tool's ` +
|
|
372
|
+
`retry note, which means the tool has already spent it.`);
|
|
373
|
+
}
|
|
374
|
+
export function buildExecutionFailureText(result, opts = {}) {
|
|
279
375
|
const output = stripVTControlCharacters(result.output || "").trim();
|
|
280
376
|
const facts = [`status=${result.status}`];
|
|
281
377
|
if (typeof result.exitCode === "number")
|
|
@@ -302,8 +398,17 @@ export function buildExecutionFailureText(result) {
|
|
|
302
398
|
"test process, or the application could each have died silently. Do NOT " +
|
|
303
399
|
"report the app as unreachable or misconfigured on this basis — nothing " +
|
|
304
400
|
"here shows that. Check any Errors line below and that the test runner " +
|
|
305
|
-
"started, then
|
|
306
|
-
|
|
401
|
+
"started, then " +
|
|
402
|
+
(opts.unchangedRerun
|
|
403
|
+
? "— this run was already an unchanged re-run of the previous one, so do " +
|
|
404
|
+
"NOT re-run it again — "
|
|
405
|
+
: "re-run it once unchanged if the attempt budget still allows it and this " +
|
|
406
|
+
"response carries no retry note — a run that produced no output is one " +
|
|
407
|
+
"of the two cases an unchanged re-run is right (the other is a " +
|
|
408
|
+
"connection error), and neither applies once the tool has already " +
|
|
409
|
+
"re-run the file itself; if it fails the same way, ") +
|
|
410
|
+
"report the execution failure with its cause unresolved and leave the " +
|
|
411
|
+
"generated test unchanged.");
|
|
307
412
|
}
|
|
308
413
|
if (errors.length > 0)
|
|
309
414
|
sections.push(`Errors: ${errors.join("; ")}`);
|
|
@@ -357,6 +462,7 @@ export function registerExecuteSkyrampTestTool(server) {
|
|
|
357
462
|
.describe("Path to save Playwright session storage after test execution for authentication purposes. Can be a relative path to the workspace (e.g., 'auth-session.json') or an absolute path. The session will be saved after the test completes."),
|
|
358
463
|
stateFile: z
|
|
359
464
|
.string()
|
|
465
|
+
.trim()
|
|
360
466
|
.optional()
|
|
361
467
|
.describe("Path to state file from skyramp_analyze_changes. Always pass when available — results are written back so skyramp_submit_report can override before/afterStatus with ground-truth pass/fail."),
|
|
362
468
|
phase: z
|
|
@@ -366,308 +472,502 @@ export function registerExecuteSkyrampTestTool(server) {
|
|
|
366
472
|
rebaselineSnapshots: z
|
|
367
473
|
.array(rebaselineSnapshotNameSchema)
|
|
368
474
|
.optional()
|
|
369
|
-
.describe(
|
|
475
|
+
.describe('UI tests only. toHaveScreenshot() baseline filenames (e.g. ["page-001.png"]) this run REPLACES instead of comparing against, because the PR intentionally changed how the captured page/element/region looks (SKYR-4298). ' +
|
|
370
476
|
"Pass exactly the list skyramp_actions returned as rebaseline_snapshots for this spec — the tool checks it against the persisted UPDATE verdict in stateFile (so stateFile is required) and refuses names the verdict did not authorize, a spec with no such verdict, or a spec whose phase: 'before' run has not been recorded yet. Use the name as the test passes it (page-001.png), not the on-disk file (page-001-chromium-linux.png). " +
|
|
371
477
|
"The refreshed PNGs land beside the spec and are delivered with the Testbot PR as image diffs; the result names which baselines were refreshed and which were not. Never use this to silence a screenshot mismatch the diff does not explain."),
|
|
372
478
|
repository: z
|
|
373
479
|
.string()
|
|
374
|
-
.
|
|
375
|
-
.
|
|
480
|
+
.trim()
|
|
481
|
+
.min(1)
|
|
482
|
+
.describe("The owner/repo whose analysis section to write execution results into (e.g. 'letsramp/api-insight'). Set it on every call — the primary's owner/repo for a primary-repo test, or a related repo's owner/repo for that repo's section of the run-scoped stateFile."),
|
|
376
483
|
},
|
|
377
484
|
_meta: {
|
|
378
485
|
keywords: ["run test", "execute test"],
|
|
379
486
|
},
|
|
380
487
|
}, async (params, extra) => {
|
|
381
|
-
|
|
382
|
-
//
|
|
383
|
-
|
|
384
|
-
//
|
|
385
|
-
|
|
386
|
-
//
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
488
|
+
// `stateFile` may be omitted by the agent; the run's own state file (the
|
|
489
|
+
// one skyramp_analyze_changes wrote for this run) is the fallback, so a
|
|
490
|
+
// dropped argument cannot dodge the attempt cap or lose the result the
|
|
491
|
+
// report reads. Only a call with no run at all executes uncounted. A blank
|
|
492
|
+
// path is "omitted", not a file, so it takes the same fallback. Inside a
|
|
493
|
+
// run, a named path must be THIS run's file under any spelling: another
|
|
494
|
+
// run's (or a copied) state file would hand the file a fresh counter and
|
|
495
|
+
// put the result where the report never looks, so it is refused before
|
|
496
|
+
// anything is queued or written. The path is then canonicalized (real
|
|
497
|
+
// path) so every later read and write names one file — a write through a
|
|
498
|
+
// symlink would otherwise replace the link instead of the target.
|
|
499
|
+
const requestedStateFile = params.stateFile?.trim();
|
|
500
|
+
let stateFilePath;
|
|
501
|
+
if (requestedStateFile) {
|
|
502
|
+
const own = resolveOwnRunStatePath(requestedStateFile);
|
|
503
|
+
if (own.refusal) {
|
|
504
|
+
// Worded here, not with the shared refusal: that one ends "leave
|
|
505
|
+
// stateFile out", and this tool's other messages and the prompt say
|
|
506
|
+
// to pass it on every call. Both are true; say so in one sentence.
|
|
507
|
+
return toolError(`Not executed: stateFile names ${requestedStateFile}, which is not this run's state file. ` +
|
|
508
|
+
`Pass this run's stateFile (${currentRunStateFile()}) with repository — or leave stateFile out, ` +
|
|
509
|
+
`and the run's own file is used. The attempt cap is enforced against that file either way.`);
|
|
402
510
|
}
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
511
|
+
stateFilePath = own.path;
|
|
512
|
+
}
|
|
513
|
+
else {
|
|
514
|
+
stateFilePath = currentRunStateFile();
|
|
515
|
+
}
|
|
516
|
+
if (stateFilePath)
|
|
517
|
+
stateFilePath = canonicalStateFilePath(stateFilePath);
|
|
518
|
+
// The "no run at all" branch: nothing below counts or records. Say so
|
|
519
|
+
// where an operator will look six months later, and tell the agent the
|
|
520
|
+
// result will not reach the report.
|
|
521
|
+
if (!stateFilePath) {
|
|
522
|
+
logger.warning(`${TOOL_NAME} has no run state: attempt cap not enforced, result not recorded`, {
|
|
523
|
+
testFile: params.testFile,
|
|
524
|
+
resolvedRunStatePath: resolveRunStatePath(),
|
|
525
|
+
});
|
|
526
|
+
}
|
|
527
|
+
const noRunNote = stateFilePath
|
|
528
|
+
? ""
|
|
529
|
+
: `\n\nNote: no run state file was found (none passed, and no active run), so this execution was not counted against an attempt cap and its result is not recorded for the report.`;
|
|
530
|
+
// One execution at a time per run: everything below that touches the
|
|
531
|
+
// state file — the cap read, the reservation, the retrofit staging, the
|
|
532
|
+
// assertion proof, the result, the video record, the baseline verdict —
|
|
533
|
+
// is a read-modify-write of one section, so two calls in the same run
|
|
534
|
+
// for ANY two files could overwrite each other. Serializing the whole
|
|
535
|
+
// handler on the state file closes every one of those windows at once;
|
|
536
|
+
// reserve/persist also serialize on this key and re-enter it. The prompt
|
|
537
|
+
// already forbids parallel execute calls; this keeps the state exact even
|
|
538
|
+
// when that is ignored. The key is the file's real path, so two spellings
|
|
539
|
+
// of one state file share one queue. A call with no run state serializes
|
|
540
|
+
// per file (a symlink and its target share one queue via the canonical path).
|
|
541
|
+
return runSerialized(stateFilePath
|
|
542
|
+
? stateFileKey(stateFilePath)
|
|
543
|
+
: canonicalTestPath(params.testFile), async () => {
|
|
544
|
+
let errorResult;
|
|
545
|
+
// Attempt-cap bookkeeping (SKYR-4460), visible to the outer catch so a
|
|
546
|
+
// throw after the reservation can still account for the attempt.
|
|
547
|
+
let maxFixAttempts = getMaxFixAttempts();
|
|
548
|
+
let priorAfterRuns = 0;
|
|
549
|
+
let reserved = false;
|
|
550
|
+
// Set when the tool re-ran a thrown transient connection error itself
|
|
551
|
+
// (see the executor call): both the result path and the outer catch
|
|
552
|
+
// must say so, or the agent is told it may re-run unchanged once more.
|
|
553
|
+
let transientRetried = false;
|
|
554
|
+
// The record the cap check read, and whether this run re-executes the
|
|
555
|
+
// same file contents it ran last time (SKYR-4460: the one unchanged
|
|
556
|
+
// re-run a file gets is then spent, and the texts say so).
|
|
557
|
+
let unchangedRerun = false;
|
|
558
|
+
// `repository` names the state section; `stateFilePath` (the argument, else
|
|
559
|
+
// this run's own file) says whether there is any state to write. A standalone
|
|
560
|
+
// execution — the local-dev workflow, an IDE call, no run — names its
|
|
561
|
+
// repository but writes nothing.
|
|
562
|
+
const stateSection = stateFilePath
|
|
563
|
+
? { file: stateFilePath, repo: params.repository }
|
|
564
|
+
: undefined;
|
|
565
|
+
// Helper to send progress notifications to the MCP client.
|
|
566
|
+
const sendProgress = makeProgressReporter(extra);
|
|
567
|
+
// Send immediate acknowledgment
|
|
568
|
+
await sendProgress(0, 100, "Starting execution...");
|
|
569
|
+
// Progress callback adapter for TestExecutionService
|
|
570
|
+
const onExecutionProgress = async (progress) => {
|
|
571
|
+
await sendProgress(progress.percent, 100, progress.message);
|
|
572
|
+
};
|
|
573
|
+
const previousBaseUrl = process.env.SKYRAMP_TEST_BASE_URL;
|
|
574
|
+
let didSetSkyrampBaseUrl = false;
|
|
575
|
+
let dockerNetwork;
|
|
576
|
+
try {
|
|
577
|
+
if (!path.isAbsolute(params.testFile)) {
|
|
578
|
+
errorResult = toolError(`testFile must be an absolute path, got: ${params.testFile}`);
|
|
407
579
|
return errorResult;
|
|
408
580
|
}
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
581
|
+
// A missing test file is an argument error: refuse it before any
|
|
582
|
+
// side effect (retrofit staging, the assertion proof record, the
|
|
583
|
+
// attempt reservation) has recorded an execution that never ran.
|
|
584
|
+
if (!fs.existsSync(params.testFile)) {
|
|
585
|
+
errorResult = toolError(`Test file does not exist: ${params.testFile}`);
|
|
413
586
|
return errorResult;
|
|
414
587
|
}
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
text: `Skipped execution: ${params.testFile} is marked external in the state file. ${TOOL_NAME} runs Skyramp-generated tests only; external (native) suites are not executed here.`,
|
|
435
|
-
},
|
|
436
|
-
],
|
|
437
|
-
};
|
|
588
|
+
// Hashed once, before any state write: recorded with the reservation
|
|
589
|
+
// so the NEXT run can tell an unchanged re-run from a fixed file.
|
|
590
|
+
const fileHash = sha256Of(fs.readFileSync(params.testFile, "utf8"));
|
|
591
|
+
const rebaseline = resolveRebaselineSnapshots(params.rebaselineSnapshots, params.phase);
|
|
592
|
+
if (rebaseline.error) {
|
|
593
|
+
errorResult = toolError(rebaseline.error);
|
|
594
|
+
return errorResult;
|
|
595
|
+
}
|
|
596
|
+
const rebaselineSnapshots = rebaseline.snapshots;
|
|
597
|
+
if (rebaselineSnapshots.length > 0) {
|
|
598
|
+
if (!stateSection) {
|
|
599
|
+
errorResult = toolError("rebaselineSnapshots requires stateFile: the refresh is authorized against the UPDATE verdict skyramp_actions persisted there.");
|
|
600
|
+
return errorResult;
|
|
601
|
+
}
|
|
602
|
+
const authState = await StateManager.fromStatePath(stateSection.file).readRepoData(stateSection.repo);
|
|
603
|
+
const auth = authorizeRebaseline(authState, params.testFile, rebaselineSnapshots);
|
|
604
|
+
if (auth.error) {
|
|
605
|
+
errorResult = toolError(auth.error);
|
|
606
|
+
return errorResult;
|
|
438
607
|
}
|
|
439
608
|
}
|
|
440
|
-
|
|
441
|
-
|
|
609
|
+
// Deterministic external-test guard (SKYR-3924): this tool runs Skyramp-generated
|
|
610
|
+
// tests in the executor and cannot run a repo's native (user-written) suite, so a
|
|
611
|
+
// run on an external test only errors (e.g. pytest import/collection failure).
|
|
612
|
+
// If the stateFile records this test as external, skip execution — the prompt asks
|
|
613
|
+
// the agent to exclude them, and this enforces it. Best-effort and conservative:
|
|
614
|
+
// only skip on a positive external match; any state-read issue falls through to
|
|
615
|
+
// normal execution, and a not-found test (e.g. a newly generated one) is not skipped.
|
|
616
|
+
if (stateSection) {
|
|
617
|
+
try {
|
|
618
|
+
const stateManager = StateManager.fromStatePath(stateSection.file);
|
|
619
|
+
const stateData = await stateManager.readRepoData(stateSection.repo);
|
|
620
|
+
const entry = stateData?.existingTests?.find((t) => canonicalTestPath(t.testFile) ===
|
|
621
|
+
canonicalTestPath(params.testFile));
|
|
622
|
+
if (entry?.source === TestSource.External) {
|
|
623
|
+
logger.info(`Skipping execution of external test ${params.testFile} — native suites are not run by ${TOOL_NAME}`);
|
|
624
|
+
return {
|
|
625
|
+
content: [
|
|
626
|
+
{
|
|
627
|
+
type: "text",
|
|
628
|
+
text: `Skipped execution: ${params.testFile} is marked external in the state file. ${TOOL_NAME} runs Skyramp-generated tests only; external (native) suites are not executed here.`,
|
|
629
|
+
},
|
|
630
|
+
],
|
|
631
|
+
};
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
catch (err) {
|
|
635
|
+
logger.warning(`External-test guard could not read stateFile (${err.message}); proceeding with execution`);
|
|
636
|
+
}
|
|
442
637
|
}
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
if (assertionFeedback) {
|
|
472
|
-
errorResult = toolError(assertionFeedback);
|
|
473
|
-
return errorResult;
|
|
474
|
-
}
|
|
475
|
-
// Proof-of-work substrate (SKYR-4262 follow-up): count this execution
|
|
476
|
-
// server-side so the report can cross-check generated vs executed —
|
|
477
|
-
// the narrative is LLM-authored, this number is not. Best-effort.
|
|
478
|
-
await recordAssertionExecution(params.testFile, params.testType, params.stateFile);
|
|
479
|
-
// Send initial progress
|
|
480
|
-
await sendProgress(5, 100, "Starting test execution...");
|
|
481
|
-
// Cross-repo run (SKYR-3819): tests delivered under the run's testsRepoDir
|
|
482
|
-
// (set by skyramp_analyze_changes, run-scoped) live outside workspacePath.
|
|
483
|
-
// Thread it through so the executor mounts the test repo and service
|
|
484
|
-
// matching still resolves the SUT baseUrl/dockerNetwork.
|
|
485
|
-
const testRepoPath = getTestsRepoDir();
|
|
486
|
-
// Resolve workspace config for base URL injection and Docker network
|
|
487
|
-
// attachment. A compose dockerNetwork is not host networking: on macOS
|
|
488
|
-
// the executor still needs localhost rewritten to host.docker.internal.
|
|
489
|
-
if (params.workspacePath) {
|
|
490
|
-
const workspaceConfig = await getWorkspaceBaseUrl(params.workspacePath, params.testFile, params.language, testRepoPath);
|
|
491
|
-
const { baseUrl, candidates } = workspaceConfig;
|
|
492
|
-
dockerNetwork = workspaceConfig.dockerNetwork;
|
|
493
|
-
const shouldInjectBaseUrl = shouldInjectSkyrampBaseUrl(params.testType, params.contractMode);
|
|
494
|
-
if (shouldInjectBaseUrl && !process.env.SKYRAMP_TEST_BASE_URL) {
|
|
495
|
-
if (baseUrl) {
|
|
496
|
-
process.env.SKYRAMP_TEST_BASE_URL = baseUrl;
|
|
497
|
-
didSetSkyrampBaseUrl = true;
|
|
638
|
+
// Fix-and-rerun attempt cap (SKYR-4460). With a stateFile the cap is the one
|
|
639
|
+
// pinned in the run's state (the first call pins the prompt's value), and
|
|
640
|
+
// the check fails CLOSED: this is the enforcement boundary, so a state that
|
|
641
|
+
// cannot be read refuses the run instead of counting as zero prior
|
|
642
|
+
// attempts. A call without any run state resolves from the environment and
|
|
643
|
+
// the default and enforces nothing — there is no run to count against.
|
|
644
|
+
maxFixAttempts = getMaxFixAttempts();
|
|
645
|
+
if (stateSection) {
|
|
646
|
+
let record;
|
|
647
|
+
try {
|
|
648
|
+
const stateData = await readRepoSectionOrThrow(stateSection.file, stateSection.repo);
|
|
649
|
+
// The pin is run-wide and lives at the ROOT, whichever section
|
|
650
|
+
// this file's record is in. A pinned value is re-validated: a
|
|
651
|
+
// hand-edited or half-written state must not turn into "cap 0,
|
|
652
|
+
// nothing ever runs" or "no cap".
|
|
653
|
+
const pinned = await readPinnedMaxFixAttempts(stateSection.file);
|
|
654
|
+
const current = getMaxFixAttempts();
|
|
655
|
+
maxFixAttempts = pinned ?? current;
|
|
656
|
+
if (pinned !== undefined && pinned !== current) {
|
|
657
|
+
logger.warning("Enforcing the attempt cap pinned in the run's state, not the current prompt's", { pinned, current, stateFile: stateSection.file });
|
|
658
|
+
}
|
|
659
|
+
record =
|
|
660
|
+
stateData.testExecutions?.[canonicalTestPath(params.testFile)];
|
|
661
|
+
}
|
|
662
|
+
catch (err) {
|
|
663
|
+
errorResult = toolError(`Not executed: the attempt-cap check could not use stateFile ${stateSection.file} — ${err.message}. ` +
|
|
664
|
+
`Fix the stateFile or repository argument and call again; do not drop stateFile.`);
|
|
665
|
+
return errorResult;
|
|
498
666
|
}
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
667
|
+
priorAfterRuns = record?.afterRuns ?? 0;
|
|
668
|
+
unchangedRerun =
|
|
669
|
+
params.phase === "after" &&
|
|
670
|
+
record?.phase === "after" &&
|
|
671
|
+
record.fileHash !== undefined &&
|
|
672
|
+
record.fileHash === fileHash;
|
|
673
|
+
const refusal = fixAttemptRefusal(record, params.phase, maxFixAttempts, params.testFile);
|
|
674
|
+
if (refusal) {
|
|
675
|
+
logger.info(`Refusing execution of ${params.testFile}: attempt cap ${maxFixAttempts} reached`);
|
|
676
|
+
errorResult = toolError(refusal);
|
|
506
677
|
return errorResult;
|
|
507
678
|
}
|
|
508
679
|
}
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
playwrightSaveStoragePath: params.playwrightSaveStoragePath,
|
|
530
|
-
dockerNetwork,
|
|
531
|
-
useHostNetwork: false,
|
|
532
|
-
...(rebaselineSnapshots.length > 0 ? { rebaselineSnapshots } : {}),
|
|
533
|
-
};
|
|
534
|
-
// Identity of the requested baselines before the run, to report afterwards
|
|
535
|
-
// which ones SmartPlaywright actually rewrote (SKYR-4298).
|
|
536
|
-
const baselinesBefore = rebaselineSnapshots.length > 0
|
|
537
|
-
? readBaselineState(params.testFile, rebaselineSnapshots)
|
|
538
|
-
: {};
|
|
539
|
-
let result;
|
|
540
|
-
try {
|
|
541
|
-
result = await executionService.executeTest(execOptions, onExecutionProgress);
|
|
542
|
-
}
|
|
543
|
-
catch (firstErr) {
|
|
544
|
-
const errMsg = firstErr instanceof Error ? firstErr.message : String(firstErr);
|
|
545
|
-
if (/\bEOF\b|connection refused|ECONNREFUSED|ECONNRESET/i.test(errMsg)) {
|
|
546
|
-
logger.info("Test execution hit transient connection error, retrying after 10s...", { error: errMsg });
|
|
547
|
-
await sendProgress(50, 100, "SUT connection error — retrying in 10s...");
|
|
548
|
-
await new Promise((r) => setTimeout(r, 10_000));
|
|
549
|
-
result = await executionService.executeTest(execOptions, onExecutionProgress);
|
|
680
|
+
// SKYR-4220: stage the shared utils file (see stageUtilsArtifacts) — execution is
|
|
681
|
+
// the last step before delivery, and a utils file left unstaged here ships a
|
|
682
|
+
// test importing a module the PR lacks. After the external-test skip: a native
|
|
683
|
+
// suite this tool will not run gets no scan and no staging.
|
|
684
|
+
await stageAndRecordRetrofits(params.testFile, undefined, stateFilePath);
|
|
685
|
+
// SKYR-4115 backstop: enhance_assertions carries the same check, but nothing
|
|
686
|
+
// guarantees the agent calls it, and execution is the last step that still
|
|
687
|
+
// precedes reporting. See pendingReuseVerification for why enforcing the verify
|
|
688
|
+
// CALL needs no retry budget.
|
|
689
|
+
//
|
|
690
|
+
// Pass the run's state path through: without it the state path resolves
|
|
691
|
+
// from the CI/Testbot anchor alone and the check returns early — failing
|
|
692
|
+
// OPEN — for a caller that supplies a valid stateFile outside CI. It is the
|
|
693
|
+
// canonical path (explicit argument → this run's own file → undefined),
|
|
694
|
+
// the same one the external-test guard above and every write below use,
|
|
695
|
+
// so a symlinked argument cannot fork the state into a second file.
|
|
696
|
+
const owedReuseVerification = await pendingReuseDebt(params.testFile, stateFilePath, params.testType);
|
|
697
|
+
if (owedReuseVerification) {
|
|
698
|
+
errorResult = toolError(owedReuseVerification);
|
|
699
|
+
return errorResult;
|
|
550
700
|
}
|
|
551
|
-
|
|
552
|
-
|
|
701
|
+
// Deterministic assertion-enhancement check: the server verifies the file
|
|
702
|
+
// itself here (never relying on the agent to call `verify: true` — prose
|
|
703
|
+
// can be ignored, this cannot). Insufficient assertions return feedback
|
|
704
|
+
// instead of executing; a fixed file passes on the next execute call.
|
|
705
|
+
// Sits BELOW the external-test guard: an external test is skipped, not
|
|
706
|
+
// executed, so deferring it for assertion work would demand fixes to a
|
|
707
|
+
// file this tool will never run.
|
|
708
|
+
const assertionFeedback = await assertionFeedbackForExecution(params.testFile, stateFilePath);
|
|
709
|
+
if (assertionFeedback) {
|
|
710
|
+
errorResult = toolError(assertionFeedback);
|
|
711
|
+
return errorResult;
|
|
553
712
|
}
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
713
|
+
// Proof-of-work substrate (SKYR-4262 follow-up): count this execution
|
|
714
|
+
// server-side so the report can cross-check generated vs executed —
|
|
715
|
+
// the narrative is LLM-authored, this number is not. Best-effort.
|
|
716
|
+
await recordAssertionExecution(params.testFile, params.testType, stateFilePath);
|
|
717
|
+
// Send initial progress
|
|
718
|
+
await sendProgress(5, 100, "Starting test execution...");
|
|
719
|
+
// Cross-repo run (SKYR-3819): tests delivered under the run's testsRepoDir
|
|
720
|
+
// (set by skyramp_analyze_changes, run-scoped) live outside workspacePath.
|
|
721
|
+
// Thread it through so the executor mounts the test repo and service
|
|
722
|
+
// matching still resolves the SUT baseUrl/dockerNetwork.
|
|
723
|
+
const testRepoPath = getTestsRepoDir();
|
|
724
|
+
// Resolve workspace config for base URL injection and Docker network
|
|
725
|
+
// attachment. A compose dockerNetwork is not host networking: on macOS
|
|
726
|
+
// the executor still needs localhost rewritten to host.docker.internal.
|
|
727
|
+
if (params.workspacePath) {
|
|
728
|
+
const workspaceConfig = await getWorkspaceBaseUrl(params.workspacePath, params.testFile, params.language, testRepoPath);
|
|
729
|
+
const { baseUrl, candidates } = workspaceConfig;
|
|
730
|
+
dockerNetwork = workspaceConfig.dockerNetwork;
|
|
731
|
+
const shouldInjectBaseUrl = shouldInjectSkyrampBaseUrl(params.testType, params.contractMode);
|
|
732
|
+
if (shouldInjectBaseUrl && !process.env.SKYRAMP_TEST_BASE_URL) {
|
|
733
|
+
if (baseUrl) {
|
|
734
|
+
process.env.SKYRAMP_TEST_BASE_URL = baseUrl;
|
|
735
|
+
didSetSkyrampBaseUrl = true;
|
|
575
736
|
}
|
|
576
|
-
else {
|
|
577
|
-
|
|
737
|
+
else if (candidates.length > 0) {
|
|
738
|
+
errorResult = toolError([
|
|
739
|
+
`Cannot determine SKYRAMP_TEST_BASE_URL — test file matches multiple services:`,
|
|
740
|
+
...candidates.map((c) => ` • ${c.serviceName}: ${c.baseUrl}`),
|
|
741
|
+
``,
|
|
742
|
+
`Re-invoke with SKYRAMP_TEST_BASE_URL set to the correct service URL, or make each service's testDirectory unique in .skyramp/workspace.yml.`,
|
|
743
|
+
].join("\n"));
|
|
744
|
+
return errorResult;
|
|
578
745
|
}
|
|
579
746
|
}
|
|
580
747
|
}
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
748
|
+
const executionService = new TestExecutionService();
|
|
749
|
+
const effectiveToken = resolveEffectiveToken(params.unauthenticated, params.token, process.env.SKYRAMP_TEST_TOKEN);
|
|
750
|
+
if (!effectiveToken &&
|
|
751
|
+
!params.unauthenticated &&
|
|
752
|
+
params.token === undefined) {
|
|
753
|
+
logger.warning("No auth token available — authenticated endpoints will likely return 401. Set SKYRAMP_TEST_TOKEN or pass token/unauthenticated.");
|
|
584
754
|
}
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
755
|
+
// Execute test with progress callback - reports Docker cache/pull status.
|
|
756
|
+
// Retry once on transient connection errors (EOF, connection refused) —
|
|
757
|
+
// these indicate the SUT isn't fully ready yet, not a test failure.
|
|
758
|
+
// Retrying inside the tool call saves agent turns vs failing and
|
|
759
|
+
// requiring the agent to re-invoke. This covers a connection error the
|
|
760
|
+
// executor THROWS, under the one attempt already reserved; a connection
|
|
761
|
+
// error that surfaces inside the test's own output reaches the agent as
|
|
762
|
+
// a normal failure, and the prompt's unchanged-re-run allowance is for
|
|
763
|
+
// that one.
|
|
764
|
+
const execOptions = {
|
|
765
|
+
testFile: params.testFile,
|
|
766
|
+
workspacePath: params.workspacePath,
|
|
767
|
+
testRepoPath,
|
|
768
|
+
language: params.language,
|
|
769
|
+
testType: params.testType,
|
|
770
|
+
token: effectiveToken,
|
|
771
|
+
playwrightSaveStoragePath: params.playwrightSaveStoragePath,
|
|
772
|
+
dockerNetwork,
|
|
773
|
+
useHostNetwork: false,
|
|
774
|
+
...(rebaselineSnapshots.length > 0
|
|
775
|
+
? { rebaselineSnapshots }
|
|
776
|
+
: {}),
|
|
777
|
+
};
|
|
778
|
+
// Identity of the requested baselines before the run, to report afterwards
|
|
779
|
+
// which ones SmartPlaywright actually rewrote (SKYR-4298).
|
|
780
|
+
const baselinesBefore = rebaselineSnapshots.length > 0
|
|
781
|
+
? readBaselineState(params.testFile, rebaselineSnapshots)
|
|
782
|
+
: {};
|
|
783
|
+
// Reserve the attempt before the run (SKYR-4460): the counters advance now
|
|
784
|
+
// and the cap is pinned, so a state write that fails after the run cannot
|
|
785
|
+
// hand this file a free attempt. Fails closed, like the check above.
|
|
786
|
+
if (stateSection) {
|
|
787
|
+
try {
|
|
788
|
+
const reservation = await reserveTestExecutionAttempt(stateSection.file, stateSection.repo, params.testType, params.phase, params.testFile, maxFixAttempts, fileHash);
|
|
789
|
+
priorAfterRuns = reservation.priorAfterRuns;
|
|
790
|
+
maxFixAttempts = reservation.cap;
|
|
791
|
+
reserved = true;
|
|
792
|
+
}
|
|
793
|
+
catch (err) {
|
|
794
|
+
errorResult = toolError(`Not executed: could not reserve the execution attempt in stateFile ${stateSection.file} (${err.message}).`);
|
|
795
|
+
return errorResult;
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
let result;
|
|
799
|
+
// The tool's own retry of a transient connection error the executor
|
|
800
|
+
// THREW (a resolved Error/Fail result whose output mentions
|
|
801
|
+
// ECONNREFUSED is not retried here — TestExecutionService converts
|
|
802
|
+
// execution-time exceptions into resolved results): two executions
|
|
803
|
+
// billed as ONE attempt, on purpose — the SUT's hiccup is not the
|
|
804
|
+
// agent's fix to make. The response says when it happened, and the
|
|
805
|
+
// prompt withholds the agent's own unchanged re-run only then, so
|
|
806
|
+
// one attempt is never more than two runs.
|
|
807
|
+
try {
|
|
808
|
+
result = await executionService.executeTest(execOptions, onExecutionProgress);
|
|
809
|
+
}
|
|
810
|
+
catch (firstErr) {
|
|
811
|
+
const errMsg = firstErr instanceof Error ? firstErr.message : String(firstErr);
|
|
812
|
+
if (/\bEOF\b|connection refused|ECONNREFUSED|ECONNRESET/i.test(errMsg)) {
|
|
813
|
+
logger.info(`Test execution hit transient connection error, retrying after ${transientRetryDelayMs}ms...`, { error: errMsg });
|
|
814
|
+
await sendProgress(50, 100, "SUT connection error — retrying in 10s...");
|
|
815
|
+
await new Promise((r) => setTimeout(r, transientRetryDelayMs));
|
|
816
|
+
transientRetried = true;
|
|
817
|
+
result = await executionService.executeTest(execOptions, onExecutionProgress);
|
|
818
|
+
}
|
|
819
|
+
else {
|
|
820
|
+
throw firstErr;
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
const transientRetryNote = transientRetried
|
|
824
|
+
? TRANSIENT_RETRY_NOTE
|
|
825
|
+
: "";
|
|
826
|
+
// Update stateFile with execution results if provided. Multi-repo: write
|
|
827
|
+
// into the section for `repository` of the run-scoped file.
|
|
828
|
+
let persistWarning = noRunNote;
|
|
829
|
+
if (stateSection) {
|
|
830
|
+
try {
|
|
831
|
+
await persistTestExecutionResult(stateSection.file, stateSection.repo, params.testType, params.phase, result, { reserved: true });
|
|
832
|
+
logger.info(`Updated stateFile with execution results for ${params.testFile}`);
|
|
833
|
+
}
|
|
834
|
+
catch (err) {
|
|
835
|
+
// The attempt was reserved before the run, so the count is right.
|
|
836
|
+
// The RESULT is what the report reads for afterStatus, though, so
|
|
837
|
+
// an unrecorded one must reach the agent, not only the log.
|
|
838
|
+
logger.error(`Failed to update stateFile: ${err.message}`);
|
|
839
|
+
persistWarning = persistFailureWarning(stateSection.file, err.message);
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
// Record the recording for the report before returning, so it happens on the
|
|
843
|
+
// failure path too (SKYR-4156). skyramp_submit_report reads these records to
|
|
844
|
+
// populate testResults[].videoPath — testbot uploads only the video
|
|
845
|
+
// directories the report references, so an unrecorded video is never seen.
|
|
846
|
+
await recordExecutionVideo(result, stateFilePath);
|
|
847
|
+
// Which requested baselines were actually rewritten (SKYR-4298). Reported on
|
|
848
|
+
// pass and fail alike; a refreshed PNG is a deliverable like a generated
|
|
849
|
+
// spec, so stage the spec's snapshot directory whenever one was rewritten —
|
|
850
|
+
// even on a failing run, since the report gate checks the PNG, not the
|
|
851
|
+
// status — so the eval harness commit and the artifact collector see it
|
|
852
|
+
// (production delivery adds the whole test directory anyway). No-op outside
|
|
853
|
+
// a testbot run, like every other stageGeneratedPaths call; never fails the
|
|
854
|
+
// execution.
|
|
855
|
+
let refreshOutcomeText = "";
|
|
856
|
+
if (rebaselineSnapshots.length > 0) {
|
|
857
|
+
const after = readBaselineState(params.testFile, rebaselineSnapshots);
|
|
858
|
+
const outcome = diffBaselineState(baselinesBefore, after);
|
|
859
|
+
refreshOutcomeText = describeRefreshOutcome(outcome);
|
|
860
|
+
// Stage the rewritten files themselves, never the directory: `git add` on
|
|
861
|
+
// the directory would ship anything else sitting there under one
|
|
862
|
+
// authorized baseline's authority.
|
|
863
|
+
for (const name of outcome.refreshed) {
|
|
864
|
+
for (const file of outcome.refreshedFiles[name] ?? []) {
|
|
865
|
+
try {
|
|
866
|
+
await stageGeneratedPaths(path.join(snapshotDirFor(params.testFile), file));
|
|
867
|
+
}
|
|
868
|
+
catch (err) {
|
|
869
|
+
logger.warning(`Could not stage refreshed visual baseline ${file} for ${params.testFile}: ${err.message}`);
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
if (outcome.notRefreshed.length > 0 && stateSection) {
|
|
609
874
|
try {
|
|
610
|
-
|
|
875
|
+
const stateManager = StateManager.fromStatePath(stateSection.file);
|
|
876
|
+
const stateData = await stateManager.readRepoData(stateSection.repo);
|
|
877
|
+
if (stateData?.maintenanceVerdicts) {
|
|
878
|
+
const reconciled = applyRefreshOutcomeToVerdicts(stateData.maintenanceVerdicts, params.testFile, outcome, EXECUTOR_DOCKER_IMAGE);
|
|
879
|
+
await stateManager.updateRepoData({
|
|
880
|
+
...stateData,
|
|
881
|
+
maintenanceVerdicts: reconciled.verdicts,
|
|
882
|
+
}, { repo: stateSection.repo });
|
|
883
|
+
if (reconciled.note)
|
|
884
|
+
refreshOutcomeText += ` ${reconciled.note}`;
|
|
885
|
+
}
|
|
611
886
|
}
|
|
612
887
|
catch (err) {
|
|
613
|
-
logger.warning(`Could not
|
|
888
|
+
logger.warning(`Could not reconcile the maintenance verdict with the refresh outcome: ${err.message}`);
|
|
614
889
|
}
|
|
615
890
|
}
|
|
616
891
|
}
|
|
617
|
-
|
|
892
|
+
const withRefreshOutcome = (text) => (refreshOutcomeText ? `${text}\n\n${refreshOutcomeText}` : text) +
|
|
893
|
+
transientRetryNote +
|
|
894
|
+
persistWarning;
|
|
895
|
+
// Progress is already reported by TestExecutionService
|
|
896
|
+
// Only report final status if not already at 100%
|
|
897
|
+
if (result.status !== TestExecutionStatus.Pass) {
|
|
898
|
+
// The budget line only means something when the run counts attempts,
|
|
899
|
+
// i.e. when a stateFile records them and this is a final-phase run.
|
|
900
|
+
const attemptLine = stateSection && params.phase === "after"
|
|
901
|
+
? `\n\n${describeAttempt(priorAfterRuns, maxFixAttempts, { unchangedRerun })}`
|
|
902
|
+
: "";
|
|
903
|
+
errorResult = toolError(withRefreshOutcome(withVideoInfo(buildExecutionFailureText(result, { unchangedRerun }) +
|
|
904
|
+
attemptLine, result.videoPath)));
|
|
905
|
+
return errorResult;
|
|
906
|
+
}
|
|
907
|
+
// Success - progress already reported by TestExecutionService
|
|
908
|
+
return {
|
|
909
|
+
content: [
|
|
910
|
+
{
|
|
911
|
+
type: "text",
|
|
912
|
+
text: withRefreshOutcome(withVideoInfo(`Test execution result: ${stripVTControlCharacters(result.output || "")}`, result.videoPath)),
|
|
913
|
+
},
|
|
914
|
+
],
|
|
915
|
+
};
|
|
916
|
+
}
|
|
917
|
+
catch (err) {
|
|
918
|
+
const message = err.message;
|
|
919
|
+
let attemptNote = "";
|
|
920
|
+
let persistNote = "";
|
|
921
|
+
// Both executions threw: the retry happened and the agent must still
|
|
922
|
+
// hear it, or the prompt lets it spend a third unchanged run.
|
|
923
|
+
const retryNote = transientRetried ? TRANSIENT_RETRY_NOTE : "";
|
|
924
|
+
// A throw after the reservation (Docker image setup, a workspace check,
|
|
925
|
+
// the rethrow from the transient-retry path) has spent an attempt; say
|
|
926
|
+
// so, and land an Error result so the record is not left as the
|
|
927
|
+
// reservation placeholder.
|
|
928
|
+
if (reserved && stateSection) {
|
|
618
929
|
try {
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
930
|
+
await persistTestExecutionResult(stateSection.file, stateSection.repo, params.testType, params.phase, {
|
|
931
|
+
testFile: params.testFile,
|
|
932
|
+
status: TestExecutionStatus.Error,
|
|
933
|
+
executedAt: new Date().toISOString(),
|
|
934
|
+
duration: 0,
|
|
935
|
+
errors: [message],
|
|
936
|
+
warnings: [],
|
|
937
|
+
output: "",
|
|
938
|
+
}, { reserved: true });
|
|
627
939
|
}
|
|
628
|
-
catch (
|
|
629
|
-
|
|
940
|
+
catch (persistErr) {
|
|
941
|
+
// Same as the main path: the count is right (reserved), the
|
|
942
|
+
// record is not, and the agent must hear it, not only the log.
|
|
943
|
+
logger.error(`Failed to record the execution error in stateFile: ${persistErr.message}`);
|
|
944
|
+
persistNote = persistFailureWarning(stateSection.file, persistErr.message);
|
|
945
|
+
}
|
|
946
|
+
if (params.phase === "after") {
|
|
947
|
+
attemptNote = `\n\n${describeAttempt(priorAfterRuns, maxFixAttempts, { unchangedRerun })}`;
|
|
630
948
|
}
|
|
631
949
|
}
|
|
632
|
-
|
|
633
|
-
const withRefreshOutcome = (text) => refreshOutcomeText ? `${text}\n\n${refreshOutcomeText}` : text;
|
|
634
|
-
// Progress is already reported by TestExecutionService
|
|
635
|
-
// Only report final status if not already at 100%
|
|
636
|
-
if (result.status !== TestExecutionStatus.Pass) {
|
|
637
|
-
errorResult = toolError(withRefreshOutcome(withVideoInfo(buildExecutionFailureText(result), result.videoPath)));
|
|
950
|
+
errorResult = toolError(`Test execution failed: ${message}${retryNote}${attemptNote}${persistNote}${noRunNote}`);
|
|
638
951
|
return errorResult;
|
|
639
952
|
}
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
};
|
|
649
|
-
}
|
|
650
|
-
catch (err) {
|
|
651
|
-
errorResult = toolError(`Test execution failed: ${err.message}`);
|
|
652
|
-
return errorResult;
|
|
653
|
-
}
|
|
654
|
-
finally {
|
|
655
|
-
if (didSetSkyrampBaseUrl) {
|
|
656
|
-
if (previousBaseUrl === undefined) {
|
|
657
|
-
delete process.env.SKYRAMP_TEST_BASE_URL;
|
|
658
|
-
}
|
|
659
|
-
else {
|
|
660
|
-
process.env.SKYRAMP_TEST_BASE_URL = previousBaseUrl;
|
|
953
|
+
finally {
|
|
954
|
+
if (didSetSkyrampBaseUrl) {
|
|
955
|
+
if (previousBaseUrl === undefined) {
|
|
956
|
+
delete process.env.SKYRAMP_TEST_BASE_URL;
|
|
957
|
+
}
|
|
958
|
+
else {
|
|
959
|
+
process.env.SKYRAMP_TEST_BASE_URL = previousBaseUrl;
|
|
960
|
+
}
|
|
661
961
|
}
|
|
962
|
+
AnalyticsService.pushMCPToolEvent(TOOL_NAME, errorResult, {
|
|
963
|
+
testFile: params.testFile,
|
|
964
|
+
workspacePath: params.workspacePath,
|
|
965
|
+
language: params.language,
|
|
966
|
+
testType: params.testType,
|
|
967
|
+
}).catch((err) => {
|
|
968
|
+
logger.warning("Analytics event failed", { error: String(err) });
|
|
969
|
+
});
|
|
662
970
|
}
|
|
663
|
-
|
|
664
|
-
testFile: params.testFile,
|
|
665
|
-
workspacePath: params.workspacePath,
|
|
666
|
-
language: params.language,
|
|
667
|
-
testType: params.testType,
|
|
668
|
-
}).catch((err) => {
|
|
669
|
-
logger.warning("Analytics event failed", { error: String(err) });
|
|
670
|
-
});
|
|
671
|
-
}
|
|
971
|
+
});
|
|
672
972
|
});
|
|
673
973
|
}
|