@guanlin4924/devflow-pi 0.1.93 → 0.1.95
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -10
- package/node_modules/@playwright/test/LICENSE +202 -0
- package/node_modules/@playwright/test/NOTICE +5 -0
- package/node_modules/@playwright/test/README.md +318 -0
- package/node_modules/@playwright/test/cli.js +19 -0
- package/node_modules/@playwright/test/index.d.ts +18 -0
- package/node_modules/@playwright/test/index.js +17 -0
- package/node_modules/@playwright/test/index.mjs +18 -0
- package/node_modules/@playwright/test/package.json +35 -0
- package/node_modules/@playwright/test/reporter.d.ts +17 -0
- package/node_modules/@playwright/test/reporter.js +17 -0
- package/node_modules/@playwright/test/reporter.mjs +17 -0
- package/node_modules/playwright/LICENSE +202 -0
- package/node_modules/playwright/NOTICE +5 -0
- package/node_modules/playwright/README.md +318 -0
- package/node_modules/playwright/ThirdPartyNotices.txt +14 -0
- package/node_modules/playwright/cli.js +19 -0
- package/node_modules/playwright/index.d.ts +17 -0
- package/node_modules/playwright/index.js +17 -0
- package/node_modules/playwright/index.mjs +18 -0
- package/node_modules/playwright/jsx-runtime.js +42 -0
- package/node_modules/playwright/jsx-runtime.mjs +21 -0
- package/node_modules/playwright/lib/agents/agentParser.js +89 -0
- package/node_modules/playwright/lib/agents/copilot-setup-steps.yml +34 -0
- package/node_modules/playwright/lib/agents/generateAgents.js +395 -0
- package/node_modules/playwright/lib/agents/playwright-test-coverage.prompt.md +31 -0
- package/node_modules/playwright/lib/agents/playwright-test-generate.prompt.md +8 -0
- package/node_modules/playwright/lib/agents/playwright-test-generator.agent.md +88 -0
- package/node_modules/playwright/lib/agents/playwright-test-heal.prompt.md +6 -0
- package/node_modules/playwright/lib/agents/playwright-test-healer.agent.md +56 -0
- package/node_modules/playwright/lib/agents/playwright-test-plan.prompt.md +9 -0
- package/node_modules/playwright/lib/agents/playwright-test-planner.agent.md +74 -0
- package/node_modules/playwright/lib/cli/reportActions.js +78 -0
- package/node_modules/playwright/lib/cli/testActions.js +214 -0
- package/node_modules/playwright/lib/common/index.js +2923 -0
- package/node_modules/playwright/lib/common/index.js.txt +34 -0
- package/node_modules/playwright/lib/errorContext.js +129 -0
- package/node_modules/playwright/lib/globals.js +58 -0
- package/node_modules/playwright/lib/index.js +815 -0
- package/node_modules/playwright/lib/isomorphic.js +260 -0
- package/node_modules/playwright/lib/isomorphic.js.txt +9 -0
- package/node_modules/playwright/lib/loader/loaderProcessEntry.js +34 -0
- package/node_modules/playwright/lib/loader/loaderProcessEntry.js.txt +9 -0
- package/node_modules/playwright/lib/matchers/expect.js +13490 -0
- package/node_modules/playwright/lib/matchers/expect.js.LICENSE +640 -0
- package/node_modules/playwright/lib/matchers/expect.js.txt +67 -0
- package/node_modules/playwright/lib/mcp/test/browserBackend.js +135 -0
- package/node_modules/playwright/lib/mcp/test/generatorTools.js +122 -0
- package/node_modules/playwright/lib/mcp/test/plannerTools.js +150 -0
- package/node_modules/playwright/lib/mcp/test/seed.js +82 -0
- package/node_modules/playwright/lib/mcp/test/streams.js +44 -0
- package/node_modules/playwright/lib/mcp/test/testBackend.js +99 -0
- package/node_modules/playwright/lib/mcp/test/testContext.js +306 -0
- package/node_modules/playwright/lib/mcp/test/testTool.js +30 -0
- package/node_modules/playwright/lib/mcp/test/testTools.js +98 -0
- package/node_modules/playwright/lib/package.js +47 -0
- package/node_modules/playwright/lib/program.js +241 -0
- package/node_modules/playwright/lib/runner/index.js +8527 -0
- package/node_modules/playwright/lib/runner/index.js.txt +61 -0
- package/node_modules/playwright/lib/transform/babelBundle.js +72274 -0
- package/node_modules/playwright/lib/transform/babelBundle.js.LICENSE +2384 -0
- package/node_modules/playwright/lib/transform/babelBundle.js.txt +325 -0
- package/node_modules/playwright/lib/transform/esmLoader.js +8054 -0
- package/node_modules/playwright/lib/transform/esmLoader.js.LICENSE +355 -0
- package/node_modules/playwright/lib/transform/esmLoader.js.txt +60 -0
- package/node_modules/playwright/lib/util.js +373 -0
- package/node_modules/playwright/lib/worker/workerProcessEntry.js +1861 -0
- package/node_modules/playwright/lib/worker/workerProcessEntry.js.txt +19 -0
- package/node_modules/playwright/package.json +55 -0
- package/node_modules/playwright/test.d.ts +18 -0
- package/node_modules/playwright/test.js +24 -0
- package/node_modules/playwright/test.mjs +35 -0
- package/node_modules/playwright/types/test.d.ts +11074 -0
- package/node_modules/playwright/types/testReporter.d.ts +950 -0
- package/node_modules/playwright-core/LICENSE +202 -0
- package/node_modules/playwright-core/NOTICE +5 -0
- package/node_modules/playwright-core/README.md +3 -0
- package/node_modules/playwright-core/ThirdPartyNotices.txt +13 -0
- package/node_modules/playwright-core/bin/install_media_pack.ps1 +5 -0
- package/node_modules/playwright-core/bin/install_webkit_wsl.ps1 +33 -0
- package/node_modules/playwright-core/bin/reinstall_chrome_beta_linux.sh +42 -0
- package/node_modules/playwright-core/bin/reinstall_chrome_beta_mac.sh +13 -0
- package/node_modules/playwright-core/bin/reinstall_chrome_beta_win.ps1 +24 -0
- package/node_modules/playwright-core/bin/reinstall_chrome_stable_linux.sh +42 -0
- package/node_modules/playwright-core/bin/reinstall_chrome_stable_mac.sh +12 -0
- package/node_modules/playwright-core/bin/reinstall_chrome_stable_win.ps1 +24 -0
- package/node_modules/playwright-core/bin/reinstall_msedge_beta_linux.sh +48 -0
- package/node_modules/playwright-core/bin/reinstall_msedge_beta_mac.sh +11 -0
- package/node_modules/playwright-core/bin/reinstall_msedge_beta_win.ps1 +23 -0
- package/node_modules/playwright-core/bin/reinstall_msedge_dev_linux.sh +48 -0
- package/node_modules/playwright-core/bin/reinstall_msedge_dev_mac.sh +11 -0
- package/node_modules/playwright-core/bin/reinstall_msedge_dev_win.ps1 +23 -0
- package/node_modules/playwright-core/bin/reinstall_msedge_stable_linux.sh +48 -0
- package/node_modules/playwright-core/bin/reinstall_msedge_stable_mac.sh +11 -0
- package/node_modules/playwright-core/bin/reinstall_msedge_stable_win.ps1 +24 -0
- package/node_modules/playwright-core/browsers.json +52 -0
- package/node_modules/playwright-core/cli.js +21 -0
- package/node_modules/playwright-core/index.d.ts +17 -0
- package/node_modules/playwright-core/index.js +17 -0
- package/node_modules/playwright-core/index.mjs +28 -0
- package/node_modules/playwright-core/lib/bootstrap.js +88 -0
- package/node_modules/playwright-core/lib/coreBundle.js +75813 -0
- package/node_modules/playwright-core/lib/entry/cliDaemon.js +5 -0
- package/node_modules/playwright-core/lib/entry/dashboardApp.js +3 -0
- package/node_modules/playwright-core/lib/entry/mcp.js +10 -0
- package/node_modules/playwright-core/lib/entry/oopBrowserDownload.js +3 -0
- package/node_modules/playwright-core/lib/package.js +50 -0
- package/node_modules/playwright-core/lib/server/chromium/appIcon.png +0 -0
- package/node_modules/playwright-core/lib/server/electron/loader.js +116 -0
- package/node_modules/playwright-core/lib/serverRegistry.js +1939 -0
- package/node_modules/playwright-core/lib/serverRegistry.js.LICENSE +65 -0
- package/node_modules/playwright-core/lib/tools/cli-client/channelSessions.js +141 -0
- package/node_modules/playwright-core/lib/tools/cli-client/cli.js +6 -0
- package/node_modules/playwright-core/lib/tools/cli-client/help.json +721 -0
- package/node_modules/playwright-core/lib/tools/cli-client/minimist.js +128 -0
- package/node_modules/playwright-core/lib/tools/cli-client/output.js +351 -0
- package/node_modules/playwright-core/lib/tools/cli-client/program.js +418 -0
- package/node_modules/playwright-core/lib/tools/cli-client/registry.js +180 -0
- package/node_modules/playwright-core/lib/tools/cli-client/session.js +259 -0
- package/node_modules/playwright-core/lib/tools/dashboard/appIcon.png +0 -0
- package/node_modules/playwright-core/lib/tools/skills/playwright-cli/SKILL.md +425 -0
- package/node_modules/playwright-core/lib/tools/skills/playwright-cli/references/element-attributes.md +23 -0
- package/node_modules/playwright-core/lib/tools/skills/playwright-cli/references/playwright-tests.md +39 -0
- package/node_modules/playwright-core/lib/tools/skills/playwright-cli/references/request-mocking.md +87 -0
- package/node_modules/playwright-core/lib/tools/skills/playwright-cli/references/running-code.md +241 -0
- package/node_modules/playwright-core/lib/tools/skills/playwright-cli/references/session-management.md +225 -0
- package/node_modules/playwright-core/lib/tools/skills/playwright-cli/references/storage-state.md +275 -0
- package/node_modules/playwright-core/lib/tools/skills/playwright-cli/references/test-generation.md +433 -0
- package/node_modules/playwright-core/lib/tools/skills/playwright-cli/references/tracing.md +139 -0
- package/node_modules/playwright-core/lib/tools/skills/playwright-cli/references/video-recording.md +143 -0
- package/node_modules/playwright-core/lib/tools/skills/playwright-component-testing/SKILL.md +136 -0
- package/node_modules/playwright-core/lib/tools/skills/playwright-component-testing/references/gallery-spec.md +144 -0
- package/node_modules/playwright-core/lib/tools/skills/playwright-component-testing/references/migration.md +89 -0
- package/node_modules/playwright-core/lib/tools/skills/playwright-component-testing/references/react.md +69 -0
- package/node_modules/playwright-core/lib/tools/skills/playwright-component-testing/references/typing.md +173 -0
- package/node_modules/playwright-core/lib/tools/skills/playwright-component-testing/references/vue.md +77 -0
- package/node_modules/playwright-core/lib/tools/skills/playwright-trace/SKILL.md +174 -0
- package/node_modules/playwright-core/lib/tools/utils/extension.js +112 -0
- package/node_modules/playwright-core/lib/tools/utils/socketConnection.js +108 -0
- package/node_modules/playwright-core/lib/utilsBundle.js +85357 -0
- package/node_modules/playwright-core/lib/utilsBundle.js.LICENSE +1890 -0
- package/node_modules/playwright-core/lib/vite/dashboard/assets/codeMirrorModule--QdMvsKi.css +1 -0
- package/node_modules/playwright-core/lib/vite/dashboard/assets/codeMirrorModule-CQ8RZGBm.js +32 -0
- package/node_modules/playwright-core/lib/vite/dashboard/assets/codicon-DCmgc-ay.ttf +0 -0
- package/node_modules/playwright-core/lib/vite/dashboard/assets/firefox-1bWoP6pv.svg +1 -0
- package/node_modules/playwright-core/lib/vite/dashboard/assets/firefox-beta-k3eOH_eK.svg +1 -0
- package/node_modules/playwright-core/lib/vite/dashboard/assets/firefox-nightly-Cp5nfeDT.svg +1 -0
- package/node_modules/playwright-core/lib/vite/dashboard/assets/index-AwgwcYie.css +1 -0
- package/node_modules/playwright-core/lib/vite/dashboard/assets/index-hRvO4yU2.js +12 -0
- package/node_modules/playwright-core/lib/vite/dashboard/assets/safari-na3_-uQk.svg +1 -0
- package/node_modules/playwright-core/lib/vite/dashboard/index.html +29 -0
- package/node_modules/playwright-core/lib/vite/dashboard/playwright-logo.svg +24 -0
- package/node_modules/playwright-core/lib/vite/htmlReport/index.html +16 -0
- package/node_modules/playwright-core/lib/vite/htmlReport/report.css +2 -0
- package/node_modules/playwright-core/lib/vite/htmlReport/report.js +32 -0
- package/node_modules/playwright-core/lib/vite/recorder/assets/codeMirrorModule--QdMvsKi.css +1 -0
- package/node_modules/playwright-core/lib/vite/recorder/assets/codeMirrorModule-CVQWJZAA.js +32 -0
- package/node_modules/playwright-core/lib/vite/recorder/assets/codicon-DCmgc-ay.ttf +0 -0
- package/node_modules/playwright-core/lib/vite/recorder/assets/index-BZpYJZ-P.css +1 -0
- package/node_modules/playwright-core/lib/vite/recorder/assets/index-hrlLqLtq.js +129 -0
- package/node_modules/playwright-core/lib/vite/recorder/index.html +29 -0
- package/node_modules/playwright-core/lib/vite/recorder/playwright-logo.svg +9 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/assets/codeMirrorModule-BbkfBe3n.js +32 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/assets/defaultSettingsView-Ds6CBOo0.js +182 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/assets/urlMatch-L3liM589.js +1 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/assets/xtermModule-DywYcAf8.js +7 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/codeMirrorModule.-QdMvsKi.css +1 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/codicon.DCmgc-ay.ttf +0 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/defaultSettingsView.Bqk9acqE.css +1 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/index.B4cLoZK3.js +1 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/index.B_TqY17P.css +1 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/index.html +44 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/manifest.webmanifest +16 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/playwright-logo.svg +9 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/snapshot.B_Jk1wbt.js +1 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/snapshot.html +10 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/sw.bundle.js +4 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/uiMode.CU5KtEkS.js +5 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/uiMode.CyMfwkXJ.css +1 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/uiMode.html +18 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/xtermModule.kHJ-D0s7.css +1 -0
- package/node_modules/playwright-core/lib/webp_codec.LICENSE +173 -0
- package/node_modules/playwright-core/lib/webp_codec.wasm +0 -0
- package/node_modules/playwright-core/lib/xdg-open +1267 -0
- package/node_modules/playwright-core/package.json +34 -0
- package/node_modules/playwright-core/types/protocol.d.ts +24645 -0
- package/node_modules/playwright-core/types/structs.d.ts +52 -0
- package/node_modules/playwright-core/types/types.d.ts +26632 -0
- package/package.json +12 -2
- package/plugins/devflow-core/extensions/devflow-core.ts +518 -40
- package/plugins/devflow-core/runtime/hooks/context_sync_gate.py +3 -3
- package/plugins/devflow-core/runtime/hooks/hook_common.py +334 -11
- package/plugins/devflow-core/runtime/hooks/index_gate.py +29 -16
- package/plugins/devflow-core/runtime/hooks/start.py +13 -13
- package/plugins/devflow-core/skills/wireframe-proposal/SKILL.md +2 -2
- package/plugins/devflow-core/skills/wireframe-validate/SKILL.md +4 -4
- package/plugins/devflow-core/skills/workflow-orchestrator/SKILL.md +19 -19
- package/plugins/devflow-core/skills/workflow-orchestrator/agents/openai.yaml +2 -2
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/acceptance_test_runner.py +412 -76
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/advance_state.rb +60 -9
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/api_test_matrix.py +2 -2
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/approval_pins.py +433 -0
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/approval_store.py +137 -0
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/architecture_assessment.rb +1 -1
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/architecture_brief.rb +1 -1
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/architecture_feasibility.rb +1 -1
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/business_invalidation.rb +5 -5
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/business_model_commit.rb +4 -4
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/business_model_validate.py +1 -1
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/business_source_resolver.rb +4 -4
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/checker_adapter.rb +7 -7
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/control_io.rb +51 -7
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/cross_track_consistency_check.rb +1 -1
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/dsl_coverage.py +87 -0
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/dsl_v1.py +318 -0
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/environment_profile.py +134 -0
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/execution_contract.rb +7 -6
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/execution_surface.py +138 -0
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/gate_runtime.rb +3 -3
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/init_state.rb +5 -5
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/init_workflow.rb +5 -5
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/inspect_state.rb +13 -13
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/machine_evidence.rb +3 -3
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/manage_lessons.rb +7 -7
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/parallel_recover.rb +2 -2
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/parallel_run.rb +3 -3
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/phase_ownership.rb +6 -6
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/playwright_adapter.py +515 -0
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/repair_control_plane.rb +1 -1
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/requirement_coverage.rb +1 -1
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/requirement_graph.rb +3 -3
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/review_preflight.py +3 -3
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/review_run.py +18 -18
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/runtime_context_collector.rb +3 -3
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/session_rollover.rb +4 -4
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/static_runtime_context_collector.rb +2 -2
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/sync_artifacts.rb +5 -5
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/tc_hash.py +132 -0
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/tdd_evidence.py +3 -3
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/test_command_policy.py +104 -10
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/test_task_binding_check.py +3 -3
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/update_triage_route.rb +3 -3
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/validate_state.rb +19 -6
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/wireframe_commit.rb +5 -5
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/wireframe_validate.py +1 -1
- package/plugins/devflow-core/skills/workflow-orchestrator/templates/acceptance-remediation.yaml +12 -12
- package/plugins/devflow-core/skills/workflow-orchestrator/templates/feature-development.yaml +201 -222
- package/plugins/devflow-core/skills/workflow-pipeline/SKILL.md +6 -4
- package/plugins/devflow-core/skills/workflow-pipeline/references/pipeline-flow.md +68 -140
- package/plugins/devflow-core/skills/workflow-project-context/SKILL.md +14 -14
- package/plugins/devflow-core/skills/workflow-project-context/assets/agents-md-template.md +7 -7
- package/plugins/devflow-core/skills/workflow-project-context/assets/codebase-backend-spec-template.md +4 -4
- package/plugins/devflow-core/skills/workflow-project-context/assets/codebase-frontend-spec-template.md +4 -4
- package/plugins/devflow-core/skills/workflow-project-context/assets/codebase-navigation-template.md +1 -1
- package/plugins/devflow-core/skills/workflow-project-context/assets/context-domain-index-template.md +4 -4
- package/plugins/devflow-core/skills/workflow-project-context/assets/context-spec-index-template.md +10 -10
- package/plugins/devflow-core/skills/workflow-project-context/assets/execution-contract-template.md +2 -2
- package/plugins/devflow-core/skills/workflow-project-context/assets/navigation-index-template.md +18 -18
- package/plugins/devflow-core/skills/workflow-project-context/assets/project-initialization-template.md +32 -32
- package/plugins/devflow-core/skills/workflow-project-context/assets/rules-index-template.md +30 -30
- package/plugins/devflow-core/skills/workflow-project-context/assets/state-template.md +7 -7
- package/plugins/devflow-core/skills/workflow-project-context/references/navigation-guide.md +37 -37
- package/plugins/devflow-core/skills/workflow-project-context/scripts/validate_initialization.py +16 -16
- package/plugins/devflow-core/skills/workflow-project-context/scripts/validate_initialization_database.py +1 -1
- package/plugins/devflow-design/skills/workflow-api-call-guide/SKILL.md +4 -4
- package/plugins/devflow-design/skills/workflow-api-contract/SKILL.md +8 -8
- package/plugins/devflow-design/skills/workflow-api-supplement/SKILL.md +5 -5
- package/plugins/devflow-design/skills/workflow-architecture-feasibility/SKILL.md +1 -1
- package/plugins/devflow-design/skills/workflow-backend-tech-spec/SKILL.md +39 -39
- package/plugins/devflow-design/skills/workflow-backend-tech-spec/assets/backend-spec-template.md +10 -10
- package/plugins/devflow-design/skills/workflow-backend-tech-spec/references/affected-module-exploration.md +2 -2
- package/plugins/devflow-design/skills/workflow-backend-tech-spec/references/code-explore-guide.md +1 -1
- package/plugins/devflow-design/skills/workflow-backend-tech-spec/references/project-rule-contract.md +20 -20
- package/plugins/devflow-design/skills/workflow-design-rule-pack/SKILL.md +8 -8
- package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/index.md +3 -3
- package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/recommendations/accessibility.md +2 -2
- package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/recommendations/component-library.md +2 -2
- package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/recommendations/design-systems.md +1 -1
- package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/recommendations/responsive-grid.md +2 -2
- package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/recommendations/stack-guidelines.md +6 -6
- package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/recommendations/ux-patterns.md +2 -2
- package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tokens/project-tokens.md +1 -1
- package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tools/ui-ux-pro-max/SKILL.md +12 -12
- package/plugins/devflow-design/skills/workflow-design-rule-pack/scripts/install.py +2 -2
- package/plugins/devflow-design/skills/workflow-feature-breakdown/SKILL.md +30 -30
- package/plugins/devflow-design/skills/workflow-feature-breakdown/assets/output-template.md +2 -2
- package/plugins/devflow-design/skills/workflow-frontend-tech-spec/SKILL.md +41 -41
- package/plugins/devflow-design/skills/workflow-frontend-tech-spec/assets/frontend-spec-template.md +15 -15
- package/plugins/devflow-design/skills/workflow-frontend-tech-spec/references/affected-module-exploration.md +2 -2
- package/plugins/devflow-design/skills/workflow-frontend-tech-spec/references/project-rule-contract.md +25 -25
- package/plugins/devflow-design/skills/workflow-integration-verify/SKILL.md +13 -13
- package/plugins/devflow-design/skills/workflow-ui-spec/SKILL.md +23 -23
- package/plugins/devflow-design/skills/workflow-ui-spec/assets/ui-spec-template.md +3 -3
- package/plugins/devflow-implementation/agents/implementation-worker.md +2 -2
- package/plugins/devflow-implementation/skills/workflow-bug-fix/SKILL.md +9 -9
- package/plugins/devflow-implementation/skills/workflow-bug-fix/references/lesson-format.md +2 -2
- package/plugins/devflow-implementation/skills/workflow-bug-fix/references/root-cause-ladder.md +1 -1
- package/plugins/devflow-implementation/skills/workflow-change-plan/SKILL.md +17 -17
- package/plugins/devflow-implementation/skills/workflow-change-plan/references/code-conventions.md +1 -1
- package/plugins/devflow-implementation/skills/workflow-change-plan/references/output-template.md +3 -3
- package/plugins/devflow-implementation/skills/workflow-change-plan/references/project-rule-contract.md +16 -16
- package/plugins/devflow-implementation/skills/workflow-execute-phase/SKILL.md +38 -38
- package/plugins/devflow-implementation/skills/workflow-execute-phase/references/execute-phase.md +4 -2
- package/plugins/devflow-intel/agents/project-scout.md +1 -1
- package/plugins/devflow-intel/extensions/devflow-intel.ts +20 -19
- package/plugins/devflow-intel/skills/code-index-query/SKILL.md +6 -6
- package/plugins/devflow-intel/skills/workflow-code-index/SKILL.md +12 -12
- package/plugins/devflow-intel/skills/workflow-code-index/references/discovery.md +2 -2
- package/plugins/devflow-intel/skills/workflow-code-index/references/query-guide.md +1 -1
- package/plugins/devflow-intel/skills/workflow-code-index/scripts/code_index.py +31 -12
- package/plugins/devflow-intel/skills/workflow-code-index/scripts/core/discovery.py +2 -2
- package/plugins/devflow-intel/skills/workflow-code-index/scripts/core/scanner.py +4 -1
- package/plugins/devflow-intel/skills/workflow-code-index/scripts/validators/project_binding_check.py +4 -4
- package/plugins/devflow-intel/skills/workflow-context-sync/SKILL.md +14 -14
- package/plugins/devflow-intel/skills/workflow-context-sync/scripts/context_sync_cursor.py +2 -2
- package/plugins/devflow-intel/skills/workflow-update-navigation/SKILL.md +26 -26
- package/plugins/devflow-intel/skills/workflow-update-navigation/references/incremental-update-guide.md +2 -2
- package/plugins/devflow-quality/runtime/playwright/devflow-test-dsl-v1.schema.json +872 -0
- package/plugins/devflow-quality/runtime/playwright/playwright.config.mjs +46 -0
- package/plugins/devflow-quality/runtime/playwright/reporter.mjs +311 -0
- package/plugins/devflow-quality/runtime/playwright/runner.spec.mjs +1308 -0
- package/plugins/devflow-quality/runtime/playwright/runtime-manifest.json +11 -0
- package/plugins/devflow-quality/skills/code-review/SKILL.md +12 -12
- package/plugins/devflow-quality/skills/code-review/references/spec-checklist.md +1 -1
- package/plugins/devflow-quality/skills/workflow-acceptance-test-design/SKILL.md +11 -8
- package/plugins/devflow-quality/skills/workflow-gen-test-guide/SKILL.md +6 -6
- package/plugins/devflow-quality/skills/workflow-gen-test-guide/legacy/SKILL.md +14 -14
- package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/SKILL.md +82 -69
- package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/references/api-mainflow-rules.md +20 -15
- package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/references/codebase-discovery.md +12 -10
- package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/references/intermediate-format.md +115 -192
- package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/references/mainflow-selection.md +27 -23
- package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/references/project-dsl-contract.md +78 -153
- package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/references/ui-mainflow-rules.md +36 -83
- package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/scripts/compile_dsl.py +497 -556
- package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/scripts/discover_codebases.py +2 -2
- package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/scripts/export_legacy_testagent.py +647 -0
- package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/scripts/normalize_case_payloads.py +10 -3
- package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/scripts/validate_case_payloads.py +165 -275
- package/plugins/devflow-quality/skills/workflow-human-acceptance/SKILL.md +61 -0
- package/plugins/devflow-quality/skills/workflow-release-closeout/SKILL.md +18 -18
- package/plugins/devflow-quality/skills/workflow-run-acceptance-tests/SKILL.md +20 -14
- package/plugins/devflow-requirements/skills/requirement-feasibility-review/SKILL.md +1 -1
- package/plugins/devflow-requirements/skills/workflow-demand-clarify/SKILL.md +10 -10
- package/plugins/devflow-requirements/skills/workflow-domain-modeling/SKILL.md +25 -25
- package/plugins/devflow-requirements/skills/workflow-requirement-baseline/SKILL.md +49 -49
- package/plugins/devflow-requirements/skills/workflow-requirement-baseline/assets/baseline-template.md +22 -22
- package/plugins/devflow-requirements/skills/workflow-requirement-baseline/references/antipatterns.md +3 -3
- package/plugins/devflow-requirements/skills/workflow-requirement-baseline/references/challenge-review-guide.md +3 -3
- package/plugins/devflow-requirements/skills/workflow-requirement-baseline/references/project-context-guide.md +11 -11
- package/plugins/devflow-requirements/skills/workflow-requirement-baseline/references/questioning.md +1 -1
- package/plugins/devflow-requirements/skills/workflow-requirement-baseline/references/requirement-review-checklist.md +4 -4
- package/plugins/devflow-requirements/skills/workflow-requirement-triage/SKILL.md +16 -16
- package/plugins/devflow-requirements/skills/workflow-wayfinder/SKILL.md +6 -6
- package/src/approval-store.ts +340 -0
- package/src/cli.ts +15 -0
- package/src/constants.ts +1 -1
- package/src/doctor.ts +259 -2
- package/src/initialization-store.ts +51 -3
- package/src/paths.ts +12 -1
- package/src/project-context.ts +60 -15
- package/src/project-documents.ts +61 -61
- package/src/project-initializer.ts +9 -8
- package/src/project-layout.ts +217 -0
- package/src/runtime.ts +3 -3
- package/templates/commands/start.md +4 -4
- package/templates/omp/AGENTS.md +1 -1
- package/templates/omp/hook-config.json +13 -7
- package/templates/omp/index-policy.json +8 -8
|
@@ -1,11 +1,23 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
-
"""Validate
|
|
3
|
-
|
|
2
|
+
"""Validate generated devflow-test-dsl/v1 cases as pure data.
|
|
3
|
+
|
|
4
|
+
The normal input is the whole ``.devflow/planning/generated-cases/<feature>``
|
|
5
|
+
directory: every ``TC-xxxx.json`` in it is validated (the file name must match
|
|
6
|
+
the DSL ``tc_id``), other files such as ``case-descriptions.json`` are not DSL
|
|
7
|
+
and are ignored, and automated ``ui``/``api_flow`` TCs without a DSL file are
|
|
8
|
+
reported as warnings. A single DSL file or a ``{"cases": [...]}`` payload is
|
|
9
|
+
accepted too.
|
|
10
|
+
|
|
11
|
+
Validation never imports or executes code from the project under test: the
|
|
12
|
+
Schema, semantic rules, structural coverage and tc_sha256 come from Devflow
|
|
13
|
+
Core (dsl_v1, dsl_coverage, tc_hash). ``--discovery`` is accepted only for
|
|
14
|
+
backwards-compatible invocations and is ignored.
|
|
15
|
+
"""
|
|
4
16
|
from __future__ import annotations
|
|
5
17
|
|
|
6
18
|
import argparse
|
|
7
|
-
import importlib
|
|
8
19
|
import json
|
|
20
|
+
import os
|
|
9
21
|
import re
|
|
10
22
|
import sys
|
|
11
23
|
from datetime import datetime, timezone
|
|
@@ -13,47 +25,29 @@ from pathlib import Path
|
|
|
13
25
|
from typing import Any
|
|
14
26
|
|
|
15
27
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
API_ACTIONS = {"get", "post", "put", "patch", "delete", "head", "options"}
|
|
40
|
-
WEB_UI_ACTIONS = {
|
|
41
|
-
"goto",
|
|
42
|
-
"navigate",
|
|
43
|
-
"click",
|
|
44
|
-
"fill",
|
|
45
|
-
"input",
|
|
46
|
-
"select",
|
|
47
|
-
"hover",
|
|
48
|
-
"wait",
|
|
49
|
-
"assert_visible",
|
|
50
|
-
"assert_text",
|
|
51
|
-
"assert_url_contains",
|
|
52
|
-
"assert_any_visible",
|
|
53
|
-
"evaluate_js",
|
|
54
|
-
"screenshot",
|
|
55
|
-
"act",
|
|
56
|
-
}
|
|
28
|
+
def _core_scripts() -> Path:
|
|
29
|
+
candidates = [Path(__file__).resolve().parents[4] / "devflow-core" / "skills" / "workflow-orchestrator" / "scripts"]
|
|
30
|
+
configured = os.environ.get("DEVFLOW_KIT_ROOT")
|
|
31
|
+
if configured:
|
|
32
|
+
candidates.append(Path(configured).expanduser() / "workflow-orchestrator" / "scripts")
|
|
33
|
+
for candidate in candidates:
|
|
34
|
+
if (candidate / "dsl_v1.py").is_file():
|
|
35
|
+
return candidate.resolve()
|
|
36
|
+
raise RuntimeError("Devflow Core scripts (dsl_v1.py) not found")
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
sys.path.insert(0, str(_core_scripts()))
|
|
40
|
+
from dsl_coverage import check as coverage_check # noqa: E402
|
|
41
|
+
from dsl_v1 import validate as validate_dsl # noqa: E402
|
|
42
|
+
from execution_surface import derive as derive_surface # noqa: E402
|
|
43
|
+
from tc_hash import tc_sha256 # noqa: E402
|
|
44
|
+
|
|
45
|
+
DSL_FILE_RE = re.compile(r"^(TC-[0-9]{4,})\.json$")
|
|
46
|
+
# Inputs/support files that live next to the DSL files but are not DSL.
|
|
47
|
+
NON_DSL_FILES = frozenset({"case-descriptions.json", "codebase-discovery.json"})
|
|
48
|
+
GENERATABLE_SURFACES = frozenset({"ui", "api_flow"})
|
|
49
|
+
|
|
50
|
+
|
|
57
51
|
SECRET_KEY_RE = re.compile(r"(token|password|passwd|secret|api[_-]?key|authorization|cookie)", re.I)
|
|
58
52
|
SECRET_VALUE_RE = re.compile(
|
|
59
53
|
r"(sk-[A-Za-z0-9_\-]{16,}|ghp_[A-Za-z0-9_]{16,}|xox[baprs]-[A-Za-z0-9\-]{16,}|"
|
|
@@ -62,33 +56,6 @@ SECRET_VALUE_RE = re.compile(
|
|
|
62
56
|
PLACEHOLDER_RE = re.compile(r"^(\$\{[A-Za-z_][A-Za-z0-9_]*\}|<[^>]+>|REPLACE_ME|dummy|example|your-.+)$", re.I)
|
|
63
57
|
|
|
64
58
|
|
|
65
|
-
def load_payload(path: Path) -> dict[str, Any]:
|
|
66
|
-
raw = json.loads(path.read_text(encoding="utf-8"))
|
|
67
|
-
if isinstance(raw, list):
|
|
68
|
-
return {"metadata": {}, "cases": raw}
|
|
69
|
-
if isinstance(raw, dict) and isinstance(raw.get("cases"), list):
|
|
70
|
-
return raw
|
|
71
|
-
raise ValueError("payload must be a JSON object with cases[] or a JSON array")
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
def backend_root_from_discovery(path: Path) -> Path:
|
|
75
|
-
data = json.loads(path.read_text(encoding="utf-8"))
|
|
76
|
-
for codebase in data.get("codebases", []):
|
|
77
|
-
if codebase.get("domain") == "backend" or "后端" in str(codebase.get("type", "")):
|
|
78
|
-
root = Path(str(codebase.get("root", "")))
|
|
79
|
-
if root.exists():
|
|
80
|
-
return root
|
|
81
|
-
raise ValueError("no existing backend codebase root found in discovery")
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
def load_project_validators(discovery_path: Path):
|
|
85
|
-
backend_root = backend_root_from_discovery(discovery_path)
|
|
86
|
-
sys.path.insert(0, str(backend_root.resolve()))
|
|
87
|
-
case_module = importlib.import_module("app.schemas.case")
|
|
88
|
-
dsl_module = importlib.import_module("app.services.dsl_parser")
|
|
89
|
-
return case_module.CaseCreate, dsl_module.validate_dsl
|
|
90
|
-
|
|
91
|
-
|
|
92
59
|
def is_placeholder(value: str) -> bool:
|
|
93
60
|
return bool(PLACEHOLDER_RE.match(value.strip())) or "${" in value
|
|
94
61
|
|
|
@@ -104,266 +71,189 @@ def walk_values(value: Any, path: str = "$") -> list[tuple[str, Any]]:
|
|
|
104
71
|
return found
|
|
105
72
|
|
|
106
73
|
|
|
107
|
-
|
|
74
|
+
VARIABLE_SECRET_REF_RE = re.compile(r"^\$\.variables\.[^.\[]+\.secret$")
|
|
75
|
+
VARIABLE_LITERAL_RE = re.compile(r"^\$\.variables\.([^.\[]+)\.value$")
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def detect_secrets(case: Any) -> list[str]:
|
|
108
79
|
errors: list[str] = []
|
|
109
80
|
for path, value in walk_values(case):
|
|
110
81
|
if isinstance(value, str) and SECRET_VALUE_RE.search(value) and not is_placeholder(value):
|
|
111
82
|
errors.append(f"{path} contains a token-like literal")
|
|
83
|
+
if VARIABLE_SECRET_REF_RE.match(path):
|
|
84
|
+
continue # {"secret": "ENV_KEY"} names an environment key; the value is not a credential
|
|
85
|
+
literal = VARIABLE_LITERAL_RE.match(path)
|
|
86
|
+
if literal and SECRET_KEY_RE.search(literal.group(1)) and isinstance(value, str) and value.strip() and not is_placeholder(value):
|
|
87
|
+
errors.append(f"{path} holds a literal for secret-looking variable '{literal.group(1)}'; declare it as {{\"secret\": \"ENV_KEY\"}}")
|
|
88
|
+
continue
|
|
112
89
|
key = path.rsplit(".", 1)[-1].lower()
|
|
113
90
|
if SECRET_KEY_RE.search(key) and isinstance(value, str) and value.strip() and not is_placeholder(value):
|
|
114
91
|
errors.append(f"{path} contains a secret-looking literal")
|
|
115
92
|
return errors
|
|
116
93
|
|
|
117
94
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
95
|
+
class LoadError:
|
|
96
|
+
"""A directory entry that could not be parsed; reported as a failed case."""
|
|
97
|
+
|
|
98
|
+
def __init__(self, message: str) -> None:
|
|
99
|
+
self.message = message
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def load_cases(path: Path) -> tuple[list[tuple[str, Any]], list[str]]:
|
|
103
|
+
"""The generated-cases directory, a single DSL file, or {"cases": [...]} / [...].
|
|
104
|
+
|
|
105
|
+
Returns (named documents, warnings). In directory mode only ``TC-xxxx.json``
|
|
106
|
+
files are DSL; a stray ``case-import-payloads.json`` (legacy TestAgent
|
|
107
|
+
export) or any other JSON file is never validated as DSL.
|
|
108
|
+
"""
|
|
109
|
+
if path.is_dir():
|
|
110
|
+
cases: list[tuple[str, Any]] = []
|
|
111
|
+
warnings: list[str] = []
|
|
112
|
+
for item in sorted(path.iterdir()):
|
|
113
|
+
if not item.is_file() or item.suffix != ".json" or item.name.startswith("."):
|
|
114
|
+
continue
|
|
115
|
+
if DSL_FILE_RE.fullmatch(item.name):
|
|
116
|
+
try:
|
|
117
|
+
cases.append((item.name, json.loads(item.read_text(encoding="utf-8"))))
|
|
118
|
+
except (OSError, UnicodeDecodeError, json.JSONDecodeError) as error:
|
|
119
|
+
cases.append((item.name, LoadError(f"{item.name} is not valid JSON: {error}")))
|
|
120
|
+
elif item.name not in NON_DSL_FILES:
|
|
121
|
+
warnings.append(f"ignored {item.name}: only TC-xxxx.json files are Runtime DSL"
|
|
122
|
+
+ (" (case-import-payloads.json is a legacy TestAgent export, never a Runtime DSL artifact)"
|
|
123
|
+
if item.name == "case-import-payloads.json" else ""))
|
|
124
|
+
return cases, warnings
|
|
125
|
+
raw = json.loads(path.read_text(encoding="utf-8"))
|
|
126
|
+
if isinstance(raw, dict) and isinstance(raw.get("cases"), list):
|
|
127
|
+
raw = raw["cases"]
|
|
128
|
+
if isinstance(raw, list):
|
|
129
|
+
return [(f"cases[{index}]", item) for index, item in enumerate(raw)], []
|
|
130
|
+
if isinstance(raw, dict):
|
|
131
|
+
return [(path.name, raw)], []
|
|
132
|
+
raise ValueError("input must be a generated-cases directory, a DSL object, an array of DSL objects, or {\"cases\": [...]}")
|
|
129
133
|
|
|
130
|
-
def validate_dsl_static(dsl: dict[str, Any], tags: list[str]) -> list[str]:
|
|
131
|
-
errors: list[str] = []
|
|
132
|
-
if not dsl.get("name"):
|
|
133
|
-
errors.append("dsl_json.name is required")
|
|
134
|
-
steps = dsl.get("steps")
|
|
135
|
-
if not isinstance(steps, list) or not steps:
|
|
136
|
-
errors.append("dsl_json.steps must be a non-empty list")
|
|
137
|
-
return errors
|
|
138
134
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
135
|
+
def missing_dsl_warnings(suite_nodes: list[Any], present: set[str]) -> list[str]:
|
|
136
|
+
"""Automated ui/api_flow TCs without a DSL file: advisory, the gate blocks them as dsl_not_approved."""
|
|
137
|
+
warnings: list[str] = []
|
|
138
|
+
for node in suite_nodes:
|
|
139
|
+
if not (isinstance(node, dict) and node.get("kind") == "test_case" and isinstance(node.get("id"), str) and isinstance(node.get("data"), dict)):
|
|
144
140
|
continue
|
|
145
|
-
|
|
146
|
-
if
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
driver = step.get("driver")
|
|
154
|
-
action = str(step.get("action") or "").lower()
|
|
155
|
-
if driver not in ALLOWED_DRIVERS:
|
|
156
|
-
errors.append(f"{path}.driver must be one of {sorted(ALLOWED_DRIVERS)}")
|
|
157
|
-
if not action:
|
|
158
|
-
errors.append(f"{path}.action is required")
|
|
159
|
-
elif driver == "api" and action not in API_ACTIONS:
|
|
160
|
-
errors.append(f"{path}.action is not a valid API method")
|
|
161
|
-
elif driver in {"web", "ui"} and action not in WEB_UI_ACTIONS:
|
|
162
|
-
errors.append(f"{path}.action is not a valid UI/Web action")
|
|
163
|
-
|
|
164
|
-
params = step.get("params") or {}
|
|
165
|
-
if driver == "api" and not params.get("url"):
|
|
166
|
-
errors.append(f"{path}.params.url is required for API steps")
|
|
167
|
-
if driver == "ui":
|
|
168
|
-
strategy = step.get("strategy") or {}
|
|
169
|
-
target = step.get("target") or {}
|
|
170
|
-
strategy_mode = strategy.get("mode", "")
|
|
171
|
-
if strategy_mode != "ai_only" and not any(target.values()):
|
|
172
|
-
errors.append(f"{path}.target is required for non-ai_only UI steps")
|
|
173
|
-
unknown_keys = set(target.keys()) - VALID_TARGET_KEYS
|
|
174
|
-
if unknown_keys:
|
|
175
|
-
errors.append(
|
|
176
|
-
f"{path}.target contains invalid keys {sorted(unknown_keys)}. "
|
|
177
|
-
f"Valid keys: {sorted(VALID_TARGET_KEYS)}"
|
|
178
|
-
)
|
|
179
|
-
|
|
180
|
-
# --- Locator quality rules ---
|
|
181
|
-
|
|
182
|
-
# Rule 1: 精确匹配器 (css/xpath/role) 必须来自 source evidence,检查选择器质量
|
|
183
|
-
for exact_key in EXACT_LOCATOR_KEYS & set(target.keys()):
|
|
184
|
-
value = str(target.get(exact_key, "")).strip()
|
|
185
|
-
if not value:
|
|
186
|
-
continue
|
|
187
|
-
if exact_key == "css":
|
|
188
|
-
if len(value) < MIN_CSS_LENGTH:
|
|
189
|
-
errors.append(
|
|
190
|
-
f"{path}.target.css='{value}' is too generic ({len(value)} chars, min {MIN_CSS_LENGTH}). "
|
|
191
|
-
f"CSS selectors are exact matchers and must be scoped. "
|
|
192
|
-
f"Add context: dialog footer, table row, form item, etc."
|
|
193
|
-
)
|
|
194
|
-
# CSS 选择器不应是裸的 tag/class 名(无组合器、无伪类)
|
|
195
|
-
if " " not in value and "." not in value and "#" not in value:
|
|
196
|
-
errors.append(
|
|
197
|
-
f"{path}.target.css='{value}' looks like a bare identifier. "
|
|
198
|
-
f"Use a scoped selector like '.el-dialog__footer .el-button--primary'."
|
|
199
|
-
)
|
|
200
|
-
if exact_key == "role":
|
|
201
|
-
if "name" not in target or not str(target.get("name", "")).strip():
|
|
202
|
-
errors.append(
|
|
203
|
-
f"{path}.target has 'role' but missing 'name'. "
|
|
204
|
-
f"role+name is a paired exact matcher; role alone is not scoped enough."
|
|
205
|
-
)
|
|
206
|
-
|
|
207
|
-
# Rule 2: 语义匹配器 — label 用于高风险文本时检查唯一性
|
|
208
|
-
label_value = str(target.get("label", "")).strip()
|
|
209
|
-
if label_value and label_value in HIGH_RISK_LABELS:
|
|
210
|
-
has_scope = bool(target.get("css") or target.get("near_text") or target.get("xpath"))
|
|
211
|
-
if not has_scope:
|
|
212
|
-
errors.append(
|
|
213
|
-
f"{path}.target.label='{label_value}' is a high-risk label "
|
|
214
|
-
f"(common table-row action, likely appears on multiple rows). "
|
|
215
|
-
f"Add scope with 'css' for row-specific selector, or use 'near_text' to bind to a row identifier."
|
|
216
|
-
)
|
|
217
|
-
|
|
218
|
-
# Rule 3: 验证步骤必须用 ai_only
|
|
219
|
-
if action in VERIFICATION_ACTIONS and strategy_mode != "ai_only":
|
|
220
|
-
errors.append(
|
|
221
|
-
f"{path}.action='{action}' is a verification step but strategy.mode='{strategy_mode}'. "
|
|
222
|
-
f"Verification steps must use strategy.mode='ai_only'. "
|
|
223
|
-
f"Visual verification of transient UI (toast, dialogs) is inherently an AI task."
|
|
224
|
-
)
|
|
225
|
-
# act + prompt 也是验证,同样要求 ai_only
|
|
226
|
-
if action == "act" and step.get("prompt") and strategy_mode != "ai_only":
|
|
227
|
-
errors.append(
|
|
228
|
-
f"{path}.action='act' with prompt indicates an AI-driven step but strategy.mode='{strategy_mode}'. "
|
|
229
|
-
f"Use strategy.mode='ai_only' for AI-driven verification/action steps."
|
|
230
|
-
)
|
|
231
|
-
|
|
232
|
-
if driver == "api":
|
|
233
|
-
for ai, assertion in enumerate(step.get("assertions") or []):
|
|
234
|
-
atype = str(assertion.get("type") or "")
|
|
235
|
-
if atype and atype not in VALID_ASSERTION_TYPES:
|
|
236
|
-
errors.append(
|
|
237
|
-
f"{path}.assertions[{ai}].type '{atype}' is not a valid assertion type. "
|
|
238
|
-
f"Valid types: {sorted(VALID_ASSERTION_TYPES)}"
|
|
239
|
-
)
|
|
240
|
-
|
|
241
|
-
# Web/UI steps: catch assertions that look like confused actions
|
|
242
|
-
if driver in {"web", "ui"}:
|
|
243
|
-
for ai, assertion in enumerate(step.get("assertions") or []):
|
|
244
|
-
atype = str(assertion.get("type") or "").lower()
|
|
245
|
-
if atype in {"text", "visible", "url_contains", "any_visible"}:
|
|
246
|
-
errors.append(
|
|
247
|
-
f"{path}.assertions[{ai}].type '{atype}' is not a valid assertion type. "
|
|
248
|
-
f"For web/ui steps, use action='assert_{atype}' instead of assertions[]."
|
|
249
|
-
)
|
|
250
|
-
|
|
251
|
-
for index, step in enumerate(steps):
|
|
252
|
-
for dep in step.get("depends_on") or []:
|
|
253
|
-
if dep not in step_ids:
|
|
254
|
-
errors.append(f"dsl_json.steps[{index}].depends_on references missing step '{dep}'")
|
|
255
|
-
|
|
256
|
-
case_tags = set(tags)
|
|
257
|
-
dsl_tags = set(dsl.get("tags") or [])
|
|
258
|
-
if not case_tags:
|
|
259
|
-
errors.append("tags must include api-mainflow or ui-mainflow")
|
|
260
|
-
elif not case_tags.issubset(MAINFLOW_TAGS):
|
|
261
|
-
errors.append(f"tags contain non-mainflow values: {tags}")
|
|
262
|
-
if not dsl_tags:
|
|
263
|
-
errors.append("dsl_json.tags must include api-mainflow or ui-mainflow")
|
|
264
|
-
elif not dsl_tags.issubset(MAINFLOW_TAGS):
|
|
265
|
-
errors.append(f"dsl_json.tags contain non-mainflow values: {dsl.get('tags')}")
|
|
141
|
+
data = node["data"]
|
|
142
|
+
if node.get("status") != "confirmed" or data.get("automation_mode") != "automated":
|
|
143
|
+
continue
|
|
144
|
+
surface, _legacy = derive_surface(data)
|
|
145
|
+
if surface in GENERATABLE_SURFACES and node["id"] not in present:
|
|
146
|
+
warnings.append(f"automated {surface} TC {node['id']} has no DSL file; it will be blocked (dsl_not_approved) until one is compiled and approved, or the TC is downgraded")
|
|
147
|
+
return warnings
|
|
266
148
|
|
|
267
|
-
|
|
149
|
+
|
|
150
|
+
def load_suite_nodes(path: Path) -> list[Any]:
|
|
151
|
+
suite = json.loads(path.read_text(encoding="utf-8"))
|
|
152
|
+
nodes = suite.get("nodes") if isinstance(suite, dict) else None
|
|
153
|
+
if not isinstance(nodes, list):
|
|
154
|
+
raise ValueError("TC suite must contain nodes[]")
|
|
155
|
+
return nodes
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def suite_cases(nodes: list[Any]) -> dict[str, dict[str, Any]]:
|
|
159
|
+
return {node["id"]: node["data"] for node in nodes
|
|
160
|
+
if isinstance(node, dict) and node.get("kind") == "test_case" and isinstance(node.get("id"), str) and isinstance(node.get("data"), dict)}
|
|
268
161
|
|
|
269
162
|
|
|
270
|
-
def
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
163
|
+
def validate_case(dsl: Any, suite: dict[str, dict[str, Any]], file_name: str | None = None) -> list[str]:
|
|
164
|
+
if isinstance(dsl, LoadError):
|
|
165
|
+
return [dsl.message]
|
|
166
|
+
errors = validate_dsl(dsl)
|
|
167
|
+
errors.extend(detect_secrets(dsl))
|
|
168
|
+
if errors or not isinstance(dsl, dict):
|
|
169
|
+
return errors
|
|
170
|
+
match = DSL_FILE_RE.fullmatch(file_name or "")
|
|
171
|
+
if match and match.group(1) != dsl["tc_id"]:
|
|
172
|
+
errors.append(f"file {file_name} contains tc_id {dsl['tc_id']}; the file must be named <tc_id>.json")
|
|
173
|
+
tc = suite.get(dsl["tc_id"])
|
|
174
|
+
if tc is None:
|
|
175
|
+
return [f"tc_id {dsl['tc_id']} is not in the frozen TC suite"]
|
|
176
|
+
if dsl["tc_sha256"] != tc_sha256(tc):
|
|
177
|
+
errors.append("tc_sha256 does not match the frozen TC data (JCS SHA-256)")
|
|
178
|
+
errors.extend(coverage_check(tc, dsl))
|
|
179
|
+
return errors
|
|
275
180
|
|
|
276
181
|
|
|
277
182
|
def render_report(results: list[dict[str, Any]], warnings: list[str], payload_path: Path) -> str:
|
|
278
183
|
total_errors = sum(len(item["errors"]) for item in results)
|
|
279
184
|
status = "passed" if total_errors == 0 else "failed"
|
|
280
185
|
lines = [
|
|
281
|
-
"# Mainflow Case Validation Report",
|
|
282
|
-
"",
|
|
186
|
+
"# Mainflow Case Validation Report", "",
|
|
283
187
|
f"- Payload: `{payload_path}`",
|
|
284
188
|
f"- Generated at: {datetime.now(timezone.utc).isoformat()}",
|
|
285
189
|
f"- Status: **{status}**",
|
|
286
190
|
f"- Cases: {len(results)}",
|
|
287
191
|
f"- Errors: {total_errors}",
|
|
288
|
-
f"- Warnings: {len(warnings)}",
|
|
289
|
-
"",
|
|
290
|
-
"
|
|
291
|
-
"",
|
|
292
|
-
"| Case | Tags | Status | Errors |",
|
|
192
|
+
f"- Warnings: {len(warnings)}", "",
|
|
193
|
+
"## Case Results", "",
|
|
194
|
+
"| Case | TC | Status | Errors |",
|
|
293
195
|
"|---|---|---:|---:|",
|
|
294
196
|
]
|
|
295
197
|
for item in results:
|
|
296
|
-
|
|
297
|
-
lines.append(f"| {item['name']} | {', '.join(item['tags'])} | {case_status} | {len(item['errors'])} |")
|
|
298
|
-
|
|
198
|
+
lines.append(f"| {item['name']} | {item['tc_id']} | {'passed' if not item['errors'] else 'failed'} | {len(item['errors'])} |")
|
|
299
199
|
if warnings:
|
|
300
200
|
lines.extend(["", "## Warnings", ""])
|
|
301
201
|
lines.extend(f"- {warning}" for warning in warnings)
|
|
302
|
-
|
|
303
202
|
failed = [item for item in results if item["errors"]]
|
|
304
203
|
if failed:
|
|
305
204
|
lines.extend(["", "## Errors", ""])
|
|
306
205
|
for item in failed:
|
|
307
206
|
lines.append(f"### {item['name']}")
|
|
308
|
-
for error in item["errors"]
|
|
309
|
-
lines.append(f"- {error}")
|
|
207
|
+
lines.extend(f"- {error}" for error in item["errors"])
|
|
310
208
|
lines.append("")
|
|
311
|
-
|
|
312
209
|
return "\n".join(lines).rstrip() + "\n"
|
|
313
210
|
|
|
314
211
|
|
|
315
212
|
def main() -> int:
|
|
316
|
-
parser = argparse.ArgumentParser()
|
|
317
|
-
parser.add_argument("input", help="
|
|
318
|
-
parser.add_argument("--
|
|
319
|
-
parser.add_argument("--output", required=True, help="validation-report.md")
|
|
213
|
+
parser = argparse.ArgumentParser(allow_abbrev=False)
|
|
214
|
+
parser.add_argument("input", help=".devflow/planning/generated-cases/<feature> directory (all TC-xxxx.json), a DSL v1 file, or {\"cases\": [...]}")
|
|
215
|
+
parser.add_argument("--suite", required=True, help="frozen TC suite (.devflow/planning/requirements/<feature>/tests.json)")
|
|
216
|
+
parser.add_argument("--output", required=True, help="validation report path (validation-report.md)")
|
|
217
|
+
parser.add_argument("--discovery", help="deprecated and ignored: validation never loads project code")
|
|
320
218
|
args = parser.parse_args()
|
|
321
219
|
|
|
322
220
|
payload_path = Path(args.input)
|
|
323
|
-
discovery_path = Path(args.discovery)
|
|
324
221
|
output_path = Path(args.output)
|
|
325
222
|
warnings: list[str] = []
|
|
326
|
-
|
|
327
|
-
|
|
223
|
+
if args.discovery:
|
|
224
|
+
warnings.append("--discovery is ignored: DSL validation is pure data and never imports project code.")
|
|
328
225
|
try:
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
CaseCreate = project_validate_dsl = None
|
|
334
|
-
except Exception as exc: # noqa: BLE001
|
|
226
|
+
cases, load_warnings = load_cases(payload_path)
|
|
227
|
+
suite_nodes = load_suite_nodes(Path(args.suite))
|
|
228
|
+
suite = suite_cases(suite_nodes)
|
|
229
|
+
except (OSError, ValueError, KeyError) as exc:
|
|
335
230
|
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
336
|
-
output_path.write_text(
|
|
337
|
-
"# Mainflow Case Validation Report\n\n"
|
|
338
|
-
f"- Payload: `{payload_path}`\n"
|
|
339
|
-
"- Status: **failed**\n\n"
|
|
340
|
-
"## Errors\n\n"
|
|
341
|
-
f"- Validation bootstrap failed: {exc}\n",
|
|
342
|
-
encoding="utf-8",
|
|
343
|
-
)
|
|
231
|
+
output_path.write_text(f"# Mainflow Case Validation Report\n\n- Payload: `{payload_path}`\n- Status: **failed**\n\n## Errors\n\n- Validation bootstrap failed: {exc}\n", encoding="utf-8")
|
|
344
232
|
print(f"ERROR: {exc}", file=sys.stderr)
|
|
345
233
|
return 2
|
|
346
|
-
|
|
347
|
-
if
|
|
234
|
+
warnings.extend(load_warnings)
|
|
235
|
+
if payload_path.is_dir():
|
|
236
|
+
warnings.extend(missing_dsl_warnings(suite_nodes, {dsl["tc_id"] for _, dsl in cases if isinstance(dsl, dict) and isinstance(dsl.get("tc_id"), str)}))
|
|
237
|
+
if not cases:
|
|
348
238
|
warnings.append("No cases were generated.")
|
|
349
239
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
results.append({"name": name, "
|
|
360
|
-
|
|
361
|
-
report = render_report(results, warnings, payload_path)
|
|
240
|
+
results: list[dict[str, Any]] = []
|
|
241
|
+
seen: set[str] = set()
|
|
242
|
+
for name, dsl in cases:
|
|
243
|
+
errors = validate_case(dsl, suite, name if payload_path.is_dir() else None)
|
|
244
|
+
tc_id = dsl.get("tc_id") if isinstance(dsl, dict) else None
|
|
245
|
+
if isinstance(tc_id, str):
|
|
246
|
+
if tc_id in seen:
|
|
247
|
+
errors.append(f"duplicate DSL for {tc_id}: each TC must have exactly one DSL file")
|
|
248
|
+
seen.add(tc_id)
|
|
249
|
+
results.append({"name": name, "tc_id": tc_id or "?", "errors": errors})
|
|
250
|
+
|
|
362
251
|
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
363
|
-
output_path.write_text(
|
|
252
|
+
output_path.write_text(render_report(results, warnings, payload_path), encoding="utf-8")
|
|
364
253
|
total_errors = sum(len(item["errors"]) for item in results)
|
|
365
|
-
|
|
366
|
-
|
|
254
|
+
status = "passed" if total_errors == 0 else "failed"
|
|
255
|
+
print(json.dumps({"status": status, "cases": len(results), "errors": total_errors}, ensure_ascii=False))
|
|
256
|
+
return 0 if status == "passed" else 1
|
|
367
257
|
|
|
368
258
|
|
|
369
259
|
if __name__ == "__main__":
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: workflow-human-acceptance
|
|
3
|
+
description: "Use after code review to execute frozen manual TC cases, capture human evidence, submit them as human_result approvals for the user to confirm, and synchronize findings to developers for final acceptance aggregation."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 人工验收与开发者同步
|
|
7
|
+
|
|
8
|
+
本步骤在 `code-review` 完成后运行。它只执行冻结套件中 `automation_mode: manual` 的 `TC-*`,并将实际结果、问题和复测要求同步给开发者。不得修改 TC 的步骤、oracle 或范围。自动化 `ui|api_flow` TC 的 DSL 生成与 `execution_plan` 批准属于 `run-acceptance-tests` 的绑定阶段(`workflow-generate-mainflow-cases`),不在本步骤内。
|
|
9
|
+
|
|
10
|
+
## 输入
|
|
11
|
+
|
|
12
|
+
1. `.devflow/planning/requirements/{feature}/tests.json` 中已冻结且未 stale 的 TC。
|
|
13
|
+
2. `.devflow/planning/phases/{phase}/REVIEW.md` 的代码审查结论。
|
|
14
|
+
3. `.devflow/planning/features/{feature}/验收测试设计.md` 的环境、账号和数据要求。
|
|
15
|
+
|
|
16
|
+
## 过程
|
|
17
|
+
|
|
18
|
+
1. 确认 `code-review` 已完成,测试套件已由 CP-3 冻结。
|
|
19
|
+
2. 只筛选 `automation_mode: manual` 的 TC;`automated` 由后续 Core runner 执行,`blocked` 保持阻塞。
|
|
20
|
+
3. 人工按冻结步骤执行,逐条收集实际结果和项目内证据文件;Agent 不得代填 `passed|failed|blocked` 结论。
|
|
21
|
+
4. 本步骤不生成自动化用例,也不改变自动化 TC 的模式;需要降级为 `manual` 的自动化 TC 必须先有有效的 `mode_override` approval,随后才按人工 TC 处理。
|
|
22
|
+
5. 对每个 manual TC 调用 `devflow_approval(action="propose", feature="...", kind="human_result", items=[{"subject":"TC-xxxx","evidence_files":[...]}])`。Agent 只能提交证据,不得提交 status、actual_result 或 pins。
|
|
23
|
+
6. 用户在 `/devflow` → “待审批”中逐 TC 查看 oracle、步骤和证据,自行选择 `passed|failed|blocked` 并填写实际结果;只有该 UI 确认产生的 `human_result` approval 才是最终人工结果。
|
|
24
|
+
7. 写入开发者交接,包含已批准、失败/阻塞、尚待确认 TC、首个偏差、证据、复现步骤、责任人和复测条件。
|
|
25
|
+
|
|
26
|
+
当冻结套件不含 manual TC 时,不创建 `human_result` proposal,并在开发者交接中说明“无人工 TC”。`human_result` 只在 database authority 模式下受支持;兼容(文件)模式下会返回 `approval_requires_database_authority`,manual TC 保持 blocked,不得改用草稿文件放行。
|
|
27
|
+
|
|
28
|
+
## 人工结果草稿
|
|
29
|
+
|
|
30
|
+
如需在确认前暂存观察,可写 `.devflow/planning/test-runs/{feature}/human-acceptance-results.json`,但它只是可丢弃草稿,不能被 runner 当作 verdict:
|
|
31
|
+
|
|
32
|
+
```json
|
|
33
|
+
{
|
|
34
|
+
"schema_version": 1,
|
|
35
|
+
"origin": "devflow_human_acceptance",
|
|
36
|
+
"feature": "<feature>",
|
|
37
|
+
"test_suite": { "graph_revision": 1, "fingerprint": "..." },
|
|
38
|
+
"results": [
|
|
39
|
+
{
|
|
40
|
+
"tc_id": "TC-0001",
|
|
41
|
+
"tester": "<name>",
|
|
42
|
+
"executed_at": "<ISO-8601>",
|
|
43
|
+
"actual_result": "<observed result>",
|
|
44
|
+
"evidence_files": ["artifacts/acceptance/TC-0001.png"]
|
|
45
|
+
}
|
|
46
|
+
]
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
草稿不得作为版本通过证据。每个 manual TC 的最终 verdict 和 actual_result 只从 control.db 中仍有效的 `human_result` approval 读取;`passed` 必须固定至少一个项目内证据文件及其哈希。
|
|
51
|
+
|
|
52
|
+
## 开发者交接
|
|
53
|
+
|
|
54
|
+
写入 `.devflow/planning/test-runs/{feature}/developer-handoff.md`,至少包含:
|
|
55
|
+
|
|
56
|
+
- 人工 TC 通过、失败、阻塞数量。
|
|
57
|
+
- 问题与证据路径。
|
|
58
|
+
- 开发者修复和复测要求。
|
|
59
|
+
- 待用户在 `/devflow` → “待审批”确认的 `human_result` 与 `execution_plan` proposal 列表(如有)。
|
|
60
|
+
|
|
61
|
+
本 Skill 不调用 `devflow_transition`;人工验收产物展示给用户后,由 Runtime 执行确认和状态迁移。
|