@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.
Files changed (369) hide show
  1. package/README.md +10 -10
  2. package/node_modules/@playwright/test/LICENSE +202 -0
  3. package/node_modules/@playwright/test/NOTICE +5 -0
  4. package/node_modules/@playwright/test/README.md +318 -0
  5. package/node_modules/@playwright/test/cli.js +19 -0
  6. package/node_modules/@playwright/test/index.d.ts +18 -0
  7. package/node_modules/@playwright/test/index.js +17 -0
  8. package/node_modules/@playwright/test/index.mjs +18 -0
  9. package/node_modules/@playwright/test/package.json +35 -0
  10. package/node_modules/@playwright/test/reporter.d.ts +17 -0
  11. package/node_modules/@playwright/test/reporter.js +17 -0
  12. package/node_modules/@playwright/test/reporter.mjs +17 -0
  13. package/node_modules/playwright/LICENSE +202 -0
  14. package/node_modules/playwright/NOTICE +5 -0
  15. package/node_modules/playwright/README.md +318 -0
  16. package/node_modules/playwright/ThirdPartyNotices.txt +14 -0
  17. package/node_modules/playwright/cli.js +19 -0
  18. package/node_modules/playwright/index.d.ts +17 -0
  19. package/node_modules/playwright/index.js +17 -0
  20. package/node_modules/playwright/index.mjs +18 -0
  21. package/node_modules/playwright/jsx-runtime.js +42 -0
  22. package/node_modules/playwright/jsx-runtime.mjs +21 -0
  23. package/node_modules/playwright/lib/agents/agentParser.js +89 -0
  24. package/node_modules/playwright/lib/agents/copilot-setup-steps.yml +34 -0
  25. package/node_modules/playwright/lib/agents/generateAgents.js +395 -0
  26. package/node_modules/playwright/lib/agents/playwright-test-coverage.prompt.md +31 -0
  27. package/node_modules/playwright/lib/agents/playwright-test-generate.prompt.md +8 -0
  28. package/node_modules/playwright/lib/agents/playwright-test-generator.agent.md +88 -0
  29. package/node_modules/playwright/lib/agents/playwright-test-heal.prompt.md +6 -0
  30. package/node_modules/playwright/lib/agents/playwright-test-healer.agent.md +56 -0
  31. package/node_modules/playwright/lib/agents/playwright-test-plan.prompt.md +9 -0
  32. package/node_modules/playwright/lib/agents/playwright-test-planner.agent.md +74 -0
  33. package/node_modules/playwright/lib/cli/reportActions.js +78 -0
  34. package/node_modules/playwright/lib/cli/testActions.js +214 -0
  35. package/node_modules/playwright/lib/common/index.js +2923 -0
  36. package/node_modules/playwright/lib/common/index.js.txt +34 -0
  37. package/node_modules/playwright/lib/errorContext.js +129 -0
  38. package/node_modules/playwright/lib/globals.js +58 -0
  39. package/node_modules/playwright/lib/index.js +815 -0
  40. package/node_modules/playwright/lib/isomorphic.js +260 -0
  41. package/node_modules/playwright/lib/isomorphic.js.txt +9 -0
  42. package/node_modules/playwright/lib/loader/loaderProcessEntry.js +34 -0
  43. package/node_modules/playwright/lib/loader/loaderProcessEntry.js.txt +9 -0
  44. package/node_modules/playwright/lib/matchers/expect.js +13490 -0
  45. package/node_modules/playwright/lib/matchers/expect.js.LICENSE +640 -0
  46. package/node_modules/playwright/lib/matchers/expect.js.txt +67 -0
  47. package/node_modules/playwright/lib/mcp/test/browserBackend.js +135 -0
  48. package/node_modules/playwright/lib/mcp/test/generatorTools.js +122 -0
  49. package/node_modules/playwright/lib/mcp/test/plannerTools.js +150 -0
  50. package/node_modules/playwright/lib/mcp/test/seed.js +82 -0
  51. package/node_modules/playwright/lib/mcp/test/streams.js +44 -0
  52. package/node_modules/playwright/lib/mcp/test/testBackend.js +99 -0
  53. package/node_modules/playwright/lib/mcp/test/testContext.js +306 -0
  54. package/node_modules/playwright/lib/mcp/test/testTool.js +30 -0
  55. package/node_modules/playwright/lib/mcp/test/testTools.js +98 -0
  56. package/node_modules/playwright/lib/package.js +47 -0
  57. package/node_modules/playwright/lib/program.js +241 -0
  58. package/node_modules/playwright/lib/runner/index.js +8527 -0
  59. package/node_modules/playwright/lib/runner/index.js.txt +61 -0
  60. package/node_modules/playwright/lib/transform/babelBundle.js +72274 -0
  61. package/node_modules/playwright/lib/transform/babelBundle.js.LICENSE +2384 -0
  62. package/node_modules/playwright/lib/transform/babelBundle.js.txt +325 -0
  63. package/node_modules/playwright/lib/transform/esmLoader.js +8054 -0
  64. package/node_modules/playwright/lib/transform/esmLoader.js.LICENSE +355 -0
  65. package/node_modules/playwright/lib/transform/esmLoader.js.txt +60 -0
  66. package/node_modules/playwright/lib/util.js +373 -0
  67. package/node_modules/playwright/lib/worker/workerProcessEntry.js +1861 -0
  68. package/node_modules/playwright/lib/worker/workerProcessEntry.js.txt +19 -0
  69. package/node_modules/playwright/package.json +55 -0
  70. package/node_modules/playwright/test.d.ts +18 -0
  71. package/node_modules/playwright/test.js +24 -0
  72. package/node_modules/playwright/test.mjs +35 -0
  73. package/node_modules/playwright/types/test.d.ts +11074 -0
  74. package/node_modules/playwright/types/testReporter.d.ts +950 -0
  75. package/node_modules/playwright-core/LICENSE +202 -0
  76. package/node_modules/playwright-core/NOTICE +5 -0
  77. package/node_modules/playwright-core/README.md +3 -0
  78. package/node_modules/playwright-core/ThirdPartyNotices.txt +13 -0
  79. package/node_modules/playwright-core/bin/install_media_pack.ps1 +5 -0
  80. package/node_modules/playwright-core/bin/install_webkit_wsl.ps1 +33 -0
  81. package/node_modules/playwright-core/bin/reinstall_chrome_beta_linux.sh +42 -0
  82. package/node_modules/playwright-core/bin/reinstall_chrome_beta_mac.sh +13 -0
  83. package/node_modules/playwright-core/bin/reinstall_chrome_beta_win.ps1 +24 -0
  84. package/node_modules/playwright-core/bin/reinstall_chrome_stable_linux.sh +42 -0
  85. package/node_modules/playwright-core/bin/reinstall_chrome_stable_mac.sh +12 -0
  86. package/node_modules/playwright-core/bin/reinstall_chrome_stable_win.ps1 +24 -0
  87. package/node_modules/playwright-core/bin/reinstall_msedge_beta_linux.sh +48 -0
  88. package/node_modules/playwright-core/bin/reinstall_msedge_beta_mac.sh +11 -0
  89. package/node_modules/playwright-core/bin/reinstall_msedge_beta_win.ps1 +23 -0
  90. package/node_modules/playwright-core/bin/reinstall_msedge_dev_linux.sh +48 -0
  91. package/node_modules/playwright-core/bin/reinstall_msedge_dev_mac.sh +11 -0
  92. package/node_modules/playwright-core/bin/reinstall_msedge_dev_win.ps1 +23 -0
  93. package/node_modules/playwright-core/bin/reinstall_msedge_stable_linux.sh +48 -0
  94. package/node_modules/playwright-core/bin/reinstall_msedge_stable_mac.sh +11 -0
  95. package/node_modules/playwright-core/bin/reinstall_msedge_stable_win.ps1 +24 -0
  96. package/node_modules/playwright-core/browsers.json +52 -0
  97. package/node_modules/playwright-core/cli.js +21 -0
  98. package/node_modules/playwright-core/index.d.ts +17 -0
  99. package/node_modules/playwright-core/index.js +17 -0
  100. package/node_modules/playwright-core/index.mjs +28 -0
  101. package/node_modules/playwright-core/lib/bootstrap.js +88 -0
  102. package/node_modules/playwright-core/lib/coreBundle.js +75813 -0
  103. package/node_modules/playwright-core/lib/entry/cliDaemon.js +5 -0
  104. package/node_modules/playwright-core/lib/entry/dashboardApp.js +3 -0
  105. package/node_modules/playwright-core/lib/entry/mcp.js +10 -0
  106. package/node_modules/playwright-core/lib/entry/oopBrowserDownload.js +3 -0
  107. package/node_modules/playwright-core/lib/package.js +50 -0
  108. package/node_modules/playwright-core/lib/server/chromium/appIcon.png +0 -0
  109. package/node_modules/playwright-core/lib/server/electron/loader.js +116 -0
  110. package/node_modules/playwright-core/lib/serverRegistry.js +1939 -0
  111. package/node_modules/playwright-core/lib/serverRegistry.js.LICENSE +65 -0
  112. package/node_modules/playwright-core/lib/tools/cli-client/channelSessions.js +141 -0
  113. package/node_modules/playwright-core/lib/tools/cli-client/cli.js +6 -0
  114. package/node_modules/playwright-core/lib/tools/cli-client/help.json +721 -0
  115. package/node_modules/playwright-core/lib/tools/cli-client/minimist.js +128 -0
  116. package/node_modules/playwright-core/lib/tools/cli-client/output.js +351 -0
  117. package/node_modules/playwright-core/lib/tools/cli-client/program.js +418 -0
  118. package/node_modules/playwright-core/lib/tools/cli-client/registry.js +180 -0
  119. package/node_modules/playwright-core/lib/tools/cli-client/session.js +259 -0
  120. package/node_modules/playwright-core/lib/tools/dashboard/appIcon.png +0 -0
  121. package/node_modules/playwright-core/lib/tools/skills/playwright-cli/SKILL.md +425 -0
  122. package/node_modules/playwright-core/lib/tools/skills/playwright-cli/references/element-attributes.md +23 -0
  123. package/node_modules/playwright-core/lib/tools/skills/playwright-cli/references/playwright-tests.md +39 -0
  124. package/node_modules/playwright-core/lib/tools/skills/playwright-cli/references/request-mocking.md +87 -0
  125. package/node_modules/playwright-core/lib/tools/skills/playwright-cli/references/running-code.md +241 -0
  126. package/node_modules/playwright-core/lib/tools/skills/playwright-cli/references/session-management.md +225 -0
  127. package/node_modules/playwright-core/lib/tools/skills/playwright-cli/references/storage-state.md +275 -0
  128. package/node_modules/playwright-core/lib/tools/skills/playwright-cli/references/test-generation.md +433 -0
  129. package/node_modules/playwright-core/lib/tools/skills/playwright-cli/references/tracing.md +139 -0
  130. package/node_modules/playwright-core/lib/tools/skills/playwright-cli/references/video-recording.md +143 -0
  131. package/node_modules/playwright-core/lib/tools/skills/playwright-component-testing/SKILL.md +136 -0
  132. package/node_modules/playwright-core/lib/tools/skills/playwright-component-testing/references/gallery-spec.md +144 -0
  133. package/node_modules/playwright-core/lib/tools/skills/playwright-component-testing/references/migration.md +89 -0
  134. package/node_modules/playwright-core/lib/tools/skills/playwright-component-testing/references/react.md +69 -0
  135. package/node_modules/playwright-core/lib/tools/skills/playwright-component-testing/references/typing.md +173 -0
  136. package/node_modules/playwright-core/lib/tools/skills/playwright-component-testing/references/vue.md +77 -0
  137. package/node_modules/playwright-core/lib/tools/skills/playwright-trace/SKILL.md +174 -0
  138. package/node_modules/playwright-core/lib/tools/utils/extension.js +112 -0
  139. package/node_modules/playwright-core/lib/tools/utils/socketConnection.js +108 -0
  140. package/node_modules/playwright-core/lib/utilsBundle.js +85357 -0
  141. package/node_modules/playwright-core/lib/utilsBundle.js.LICENSE +1890 -0
  142. package/node_modules/playwright-core/lib/vite/dashboard/assets/codeMirrorModule--QdMvsKi.css +1 -0
  143. package/node_modules/playwright-core/lib/vite/dashboard/assets/codeMirrorModule-CQ8RZGBm.js +32 -0
  144. package/node_modules/playwright-core/lib/vite/dashboard/assets/codicon-DCmgc-ay.ttf +0 -0
  145. package/node_modules/playwright-core/lib/vite/dashboard/assets/firefox-1bWoP6pv.svg +1 -0
  146. package/node_modules/playwright-core/lib/vite/dashboard/assets/firefox-beta-k3eOH_eK.svg +1 -0
  147. package/node_modules/playwright-core/lib/vite/dashboard/assets/firefox-nightly-Cp5nfeDT.svg +1 -0
  148. package/node_modules/playwright-core/lib/vite/dashboard/assets/index-AwgwcYie.css +1 -0
  149. package/node_modules/playwright-core/lib/vite/dashboard/assets/index-hRvO4yU2.js +12 -0
  150. package/node_modules/playwright-core/lib/vite/dashboard/assets/safari-na3_-uQk.svg +1 -0
  151. package/node_modules/playwright-core/lib/vite/dashboard/index.html +29 -0
  152. package/node_modules/playwright-core/lib/vite/dashboard/playwright-logo.svg +24 -0
  153. package/node_modules/playwright-core/lib/vite/htmlReport/index.html +16 -0
  154. package/node_modules/playwright-core/lib/vite/htmlReport/report.css +2 -0
  155. package/node_modules/playwright-core/lib/vite/htmlReport/report.js +32 -0
  156. package/node_modules/playwright-core/lib/vite/recorder/assets/codeMirrorModule--QdMvsKi.css +1 -0
  157. package/node_modules/playwright-core/lib/vite/recorder/assets/codeMirrorModule-CVQWJZAA.js +32 -0
  158. package/node_modules/playwright-core/lib/vite/recorder/assets/codicon-DCmgc-ay.ttf +0 -0
  159. package/node_modules/playwright-core/lib/vite/recorder/assets/index-BZpYJZ-P.css +1 -0
  160. package/node_modules/playwright-core/lib/vite/recorder/assets/index-hrlLqLtq.js +129 -0
  161. package/node_modules/playwright-core/lib/vite/recorder/index.html +29 -0
  162. package/node_modules/playwright-core/lib/vite/recorder/playwright-logo.svg +9 -0
  163. package/node_modules/playwright-core/lib/vite/traceViewer/assets/codeMirrorModule-BbkfBe3n.js +32 -0
  164. package/node_modules/playwright-core/lib/vite/traceViewer/assets/defaultSettingsView-Ds6CBOo0.js +182 -0
  165. package/node_modules/playwright-core/lib/vite/traceViewer/assets/urlMatch-L3liM589.js +1 -0
  166. package/node_modules/playwright-core/lib/vite/traceViewer/assets/xtermModule-DywYcAf8.js +7 -0
  167. package/node_modules/playwright-core/lib/vite/traceViewer/codeMirrorModule.-QdMvsKi.css +1 -0
  168. package/node_modules/playwright-core/lib/vite/traceViewer/codicon.DCmgc-ay.ttf +0 -0
  169. package/node_modules/playwright-core/lib/vite/traceViewer/defaultSettingsView.Bqk9acqE.css +1 -0
  170. package/node_modules/playwright-core/lib/vite/traceViewer/index.B4cLoZK3.js +1 -0
  171. package/node_modules/playwright-core/lib/vite/traceViewer/index.B_TqY17P.css +1 -0
  172. package/node_modules/playwright-core/lib/vite/traceViewer/index.html +44 -0
  173. package/node_modules/playwright-core/lib/vite/traceViewer/manifest.webmanifest +16 -0
  174. package/node_modules/playwright-core/lib/vite/traceViewer/playwright-logo.svg +9 -0
  175. package/node_modules/playwright-core/lib/vite/traceViewer/snapshot.B_Jk1wbt.js +1 -0
  176. package/node_modules/playwright-core/lib/vite/traceViewer/snapshot.html +10 -0
  177. package/node_modules/playwright-core/lib/vite/traceViewer/sw.bundle.js +4 -0
  178. package/node_modules/playwright-core/lib/vite/traceViewer/uiMode.CU5KtEkS.js +5 -0
  179. package/node_modules/playwright-core/lib/vite/traceViewer/uiMode.CyMfwkXJ.css +1 -0
  180. package/node_modules/playwright-core/lib/vite/traceViewer/uiMode.html +18 -0
  181. package/node_modules/playwright-core/lib/vite/traceViewer/xtermModule.kHJ-D0s7.css +1 -0
  182. package/node_modules/playwright-core/lib/webp_codec.LICENSE +173 -0
  183. package/node_modules/playwright-core/lib/webp_codec.wasm +0 -0
  184. package/node_modules/playwright-core/lib/xdg-open +1267 -0
  185. package/node_modules/playwright-core/package.json +34 -0
  186. package/node_modules/playwright-core/types/protocol.d.ts +24645 -0
  187. package/node_modules/playwright-core/types/structs.d.ts +52 -0
  188. package/node_modules/playwright-core/types/types.d.ts +26632 -0
  189. package/package.json +12 -2
  190. package/plugins/devflow-core/extensions/devflow-core.ts +518 -40
  191. package/plugins/devflow-core/runtime/hooks/context_sync_gate.py +3 -3
  192. package/plugins/devflow-core/runtime/hooks/hook_common.py +334 -11
  193. package/plugins/devflow-core/runtime/hooks/index_gate.py +29 -16
  194. package/plugins/devflow-core/runtime/hooks/start.py +13 -13
  195. package/plugins/devflow-core/skills/wireframe-proposal/SKILL.md +2 -2
  196. package/plugins/devflow-core/skills/wireframe-validate/SKILL.md +4 -4
  197. package/plugins/devflow-core/skills/workflow-orchestrator/SKILL.md +19 -19
  198. package/plugins/devflow-core/skills/workflow-orchestrator/agents/openai.yaml +2 -2
  199. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/acceptance_test_runner.py +412 -76
  200. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/advance_state.rb +60 -9
  201. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/api_test_matrix.py +2 -2
  202. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/approval_pins.py +433 -0
  203. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/approval_store.py +137 -0
  204. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/architecture_assessment.rb +1 -1
  205. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/architecture_brief.rb +1 -1
  206. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/architecture_feasibility.rb +1 -1
  207. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/business_invalidation.rb +5 -5
  208. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/business_model_commit.rb +4 -4
  209. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/business_model_validate.py +1 -1
  210. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/business_source_resolver.rb +4 -4
  211. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/checker_adapter.rb +7 -7
  212. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/control_io.rb +51 -7
  213. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/cross_track_consistency_check.rb +1 -1
  214. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/dsl_coverage.py +87 -0
  215. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/dsl_v1.py +318 -0
  216. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/environment_profile.py +134 -0
  217. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/execution_contract.rb +7 -6
  218. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/execution_surface.py +138 -0
  219. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/gate_runtime.rb +3 -3
  220. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/init_state.rb +5 -5
  221. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/init_workflow.rb +5 -5
  222. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/inspect_state.rb +13 -13
  223. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/machine_evidence.rb +3 -3
  224. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/manage_lessons.rb +7 -7
  225. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/parallel_recover.rb +2 -2
  226. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/parallel_run.rb +3 -3
  227. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/phase_ownership.rb +6 -6
  228. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/playwright_adapter.py +515 -0
  229. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/repair_control_plane.rb +1 -1
  230. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/requirement_coverage.rb +1 -1
  231. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/requirement_graph.rb +3 -3
  232. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/review_preflight.py +3 -3
  233. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/review_run.py +18 -18
  234. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/runtime_context_collector.rb +3 -3
  235. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/session_rollover.rb +4 -4
  236. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/static_runtime_context_collector.rb +2 -2
  237. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/sync_artifacts.rb +5 -5
  238. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/tc_hash.py +132 -0
  239. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/tdd_evidence.py +3 -3
  240. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/test_command_policy.py +104 -10
  241. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/test_task_binding_check.py +3 -3
  242. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/update_triage_route.rb +3 -3
  243. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/validate_state.rb +19 -6
  244. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/wireframe_commit.rb +5 -5
  245. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/wireframe_validate.py +1 -1
  246. package/plugins/devflow-core/skills/workflow-orchestrator/templates/acceptance-remediation.yaml +12 -12
  247. package/plugins/devflow-core/skills/workflow-orchestrator/templates/feature-development.yaml +201 -222
  248. package/plugins/devflow-core/skills/workflow-pipeline/SKILL.md +6 -4
  249. package/plugins/devflow-core/skills/workflow-pipeline/references/pipeline-flow.md +68 -140
  250. package/plugins/devflow-core/skills/workflow-project-context/SKILL.md +14 -14
  251. package/plugins/devflow-core/skills/workflow-project-context/assets/agents-md-template.md +7 -7
  252. package/plugins/devflow-core/skills/workflow-project-context/assets/codebase-backend-spec-template.md +4 -4
  253. package/plugins/devflow-core/skills/workflow-project-context/assets/codebase-frontend-spec-template.md +4 -4
  254. package/plugins/devflow-core/skills/workflow-project-context/assets/codebase-navigation-template.md +1 -1
  255. package/plugins/devflow-core/skills/workflow-project-context/assets/context-domain-index-template.md +4 -4
  256. package/plugins/devflow-core/skills/workflow-project-context/assets/context-spec-index-template.md +10 -10
  257. package/plugins/devflow-core/skills/workflow-project-context/assets/execution-contract-template.md +2 -2
  258. package/plugins/devflow-core/skills/workflow-project-context/assets/navigation-index-template.md +18 -18
  259. package/plugins/devflow-core/skills/workflow-project-context/assets/project-initialization-template.md +32 -32
  260. package/plugins/devflow-core/skills/workflow-project-context/assets/rules-index-template.md +30 -30
  261. package/plugins/devflow-core/skills/workflow-project-context/assets/state-template.md +7 -7
  262. package/plugins/devflow-core/skills/workflow-project-context/references/navigation-guide.md +37 -37
  263. package/plugins/devflow-core/skills/workflow-project-context/scripts/validate_initialization.py +16 -16
  264. package/plugins/devflow-core/skills/workflow-project-context/scripts/validate_initialization_database.py +1 -1
  265. package/plugins/devflow-design/skills/workflow-api-call-guide/SKILL.md +4 -4
  266. package/plugins/devflow-design/skills/workflow-api-contract/SKILL.md +8 -8
  267. package/plugins/devflow-design/skills/workflow-api-supplement/SKILL.md +5 -5
  268. package/plugins/devflow-design/skills/workflow-architecture-feasibility/SKILL.md +1 -1
  269. package/plugins/devflow-design/skills/workflow-backend-tech-spec/SKILL.md +39 -39
  270. package/plugins/devflow-design/skills/workflow-backend-tech-spec/assets/backend-spec-template.md +10 -10
  271. package/plugins/devflow-design/skills/workflow-backend-tech-spec/references/affected-module-exploration.md +2 -2
  272. package/plugins/devflow-design/skills/workflow-backend-tech-spec/references/code-explore-guide.md +1 -1
  273. package/plugins/devflow-design/skills/workflow-backend-tech-spec/references/project-rule-contract.md +20 -20
  274. package/plugins/devflow-design/skills/workflow-design-rule-pack/SKILL.md +8 -8
  275. package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/index.md +3 -3
  276. package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/recommendations/accessibility.md +2 -2
  277. package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/recommendations/component-library.md +2 -2
  278. package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/recommendations/design-systems.md +1 -1
  279. package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/recommendations/responsive-grid.md +2 -2
  280. package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/recommendations/stack-guidelines.md +6 -6
  281. package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/recommendations/ux-patterns.md +2 -2
  282. package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tokens/project-tokens.md +1 -1
  283. package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tools/ui-ux-pro-max/SKILL.md +12 -12
  284. package/plugins/devflow-design/skills/workflow-design-rule-pack/scripts/install.py +2 -2
  285. package/plugins/devflow-design/skills/workflow-feature-breakdown/SKILL.md +30 -30
  286. package/plugins/devflow-design/skills/workflow-feature-breakdown/assets/output-template.md +2 -2
  287. package/plugins/devflow-design/skills/workflow-frontend-tech-spec/SKILL.md +41 -41
  288. package/plugins/devflow-design/skills/workflow-frontend-tech-spec/assets/frontend-spec-template.md +15 -15
  289. package/plugins/devflow-design/skills/workflow-frontend-tech-spec/references/affected-module-exploration.md +2 -2
  290. package/plugins/devflow-design/skills/workflow-frontend-tech-spec/references/project-rule-contract.md +25 -25
  291. package/plugins/devflow-design/skills/workflow-integration-verify/SKILL.md +13 -13
  292. package/plugins/devflow-design/skills/workflow-ui-spec/SKILL.md +23 -23
  293. package/plugins/devflow-design/skills/workflow-ui-spec/assets/ui-spec-template.md +3 -3
  294. package/plugins/devflow-implementation/agents/implementation-worker.md +2 -2
  295. package/plugins/devflow-implementation/skills/workflow-bug-fix/SKILL.md +9 -9
  296. package/plugins/devflow-implementation/skills/workflow-bug-fix/references/lesson-format.md +2 -2
  297. package/plugins/devflow-implementation/skills/workflow-bug-fix/references/root-cause-ladder.md +1 -1
  298. package/plugins/devflow-implementation/skills/workflow-change-plan/SKILL.md +17 -17
  299. package/plugins/devflow-implementation/skills/workflow-change-plan/references/code-conventions.md +1 -1
  300. package/plugins/devflow-implementation/skills/workflow-change-plan/references/output-template.md +3 -3
  301. package/plugins/devflow-implementation/skills/workflow-change-plan/references/project-rule-contract.md +16 -16
  302. package/plugins/devflow-implementation/skills/workflow-execute-phase/SKILL.md +38 -38
  303. package/plugins/devflow-implementation/skills/workflow-execute-phase/references/execute-phase.md +4 -2
  304. package/plugins/devflow-intel/agents/project-scout.md +1 -1
  305. package/plugins/devflow-intel/extensions/devflow-intel.ts +20 -19
  306. package/plugins/devflow-intel/skills/code-index-query/SKILL.md +6 -6
  307. package/plugins/devflow-intel/skills/workflow-code-index/SKILL.md +12 -12
  308. package/plugins/devflow-intel/skills/workflow-code-index/references/discovery.md +2 -2
  309. package/plugins/devflow-intel/skills/workflow-code-index/references/query-guide.md +1 -1
  310. package/plugins/devflow-intel/skills/workflow-code-index/scripts/code_index.py +31 -12
  311. package/plugins/devflow-intel/skills/workflow-code-index/scripts/core/discovery.py +2 -2
  312. package/plugins/devflow-intel/skills/workflow-code-index/scripts/core/scanner.py +4 -1
  313. package/plugins/devflow-intel/skills/workflow-code-index/scripts/validators/project_binding_check.py +4 -4
  314. package/plugins/devflow-intel/skills/workflow-context-sync/SKILL.md +14 -14
  315. package/plugins/devflow-intel/skills/workflow-context-sync/scripts/context_sync_cursor.py +2 -2
  316. package/plugins/devflow-intel/skills/workflow-update-navigation/SKILL.md +26 -26
  317. package/plugins/devflow-intel/skills/workflow-update-navigation/references/incremental-update-guide.md +2 -2
  318. package/plugins/devflow-quality/runtime/playwright/devflow-test-dsl-v1.schema.json +872 -0
  319. package/plugins/devflow-quality/runtime/playwright/playwright.config.mjs +46 -0
  320. package/plugins/devflow-quality/runtime/playwright/reporter.mjs +311 -0
  321. package/plugins/devflow-quality/runtime/playwright/runner.spec.mjs +1308 -0
  322. package/plugins/devflow-quality/runtime/playwright/runtime-manifest.json +11 -0
  323. package/plugins/devflow-quality/skills/code-review/SKILL.md +12 -12
  324. package/plugins/devflow-quality/skills/code-review/references/spec-checklist.md +1 -1
  325. package/plugins/devflow-quality/skills/workflow-acceptance-test-design/SKILL.md +11 -8
  326. package/plugins/devflow-quality/skills/workflow-gen-test-guide/SKILL.md +6 -6
  327. package/plugins/devflow-quality/skills/workflow-gen-test-guide/legacy/SKILL.md +14 -14
  328. package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/SKILL.md +82 -69
  329. package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/references/api-mainflow-rules.md +20 -15
  330. package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/references/codebase-discovery.md +12 -10
  331. package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/references/intermediate-format.md +115 -192
  332. package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/references/mainflow-selection.md +27 -23
  333. package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/references/project-dsl-contract.md +78 -153
  334. package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/references/ui-mainflow-rules.md +36 -83
  335. package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/scripts/compile_dsl.py +497 -556
  336. package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/scripts/discover_codebases.py +2 -2
  337. package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/scripts/export_legacy_testagent.py +647 -0
  338. package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/scripts/normalize_case_payloads.py +10 -3
  339. package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/scripts/validate_case_payloads.py +165 -275
  340. package/plugins/devflow-quality/skills/workflow-human-acceptance/SKILL.md +61 -0
  341. package/plugins/devflow-quality/skills/workflow-release-closeout/SKILL.md +18 -18
  342. package/plugins/devflow-quality/skills/workflow-run-acceptance-tests/SKILL.md +20 -14
  343. package/plugins/devflow-requirements/skills/requirement-feasibility-review/SKILL.md +1 -1
  344. package/plugins/devflow-requirements/skills/workflow-demand-clarify/SKILL.md +10 -10
  345. package/plugins/devflow-requirements/skills/workflow-domain-modeling/SKILL.md +25 -25
  346. package/plugins/devflow-requirements/skills/workflow-requirement-baseline/SKILL.md +49 -49
  347. package/plugins/devflow-requirements/skills/workflow-requirement-baseline/assets/baseline-template.md +22 -22
  348. package/plugins/devflow-requirements/skills/workflow-requirement-baseline/references/antipatterns.md +3 -3
  349. package/plugins/devflow-requirements/skills/workflow-requirement-baseline/references/challenge-review-guide.md +3 -3
  350. package/plugins/devflow-requirements/skills/workflow-requirement-baseline/references/project-context-guide.md +11 -11
  351. package/plugins/devflow-requirements/skills/workflow-requirement-baseline/references/questioning.md +1 -1
  352. package/plugins/devflow-requirements/skills/workflow-requirement-baseline/references/requirement-review-checklist.md +4 -4
  353. package/plugins/devflow-requirements/skills/workflow-requirement-triage/SKILL.md +16 -16
  354. package/plugins/devflow-requirements/skills/workflow-wayfinder/SKILL.md +6 -6
  355. package/src/approval-store.ts +340 -0
  356. package/src/cli.ts +15 -0
  357. package/src/constants.ts +1 -1
  358. package/src/doctor.ts +259 -2
  359. package/src/initialization-store.ts +51 -3
  360. package/src/paths.ts +12 -1
  361. package/src/project-context.ts +60 -15
  362. package/src/project-documents.ts +61 -61
  363. package/src/project-initializer.ts +9 -8
  364. package/src/project-layout.ts +217 -0
  365. package/src/runtime.ts +3 -3
  366. package/templates/commands/start.md +4 -4
  367. package/templates/omp/AGENTS.md +1 -1
  368. package/templates/omp/hook-config.json +13 -7
  369. package/templates/omp/index-policy.json +8 -8
@@ -1,11 +1,23 @@
1
1
  #!/usr/bin/env python3
2
- """Validate normalized mainflow case import payloads."""
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
- MAINFLOW_TAGS = {"api-mainflow", "ui-mainflow"}
17
- ALLOWED_DRIVERS = {"api", "web", "ui"}
18
- VALID_TARGET_KEYS = {"css", "xpath", "label", "placeholder", "role", "name", "near_text", "exact"}
19
- # 精确匹配器:严格对应DOM结构,必须来自 source code 证据,不能凭空编造
20
- EXACT_LOCATOR_KEYS = {"css", "xpath", "role"}
21
- # 语义匹配器:通过用户可见文本/属性定位,更抗DOM变化但需检查唯一性
22
- SEMANTIC_LOCATOR_KEYS = {"label", "placeholder", "near_text"}
23
- # 表格行常见操作文本 — 用 label 定位时几乎一定不唯一
24
- HIGH_RISK_LABELS = {
25
- "编辑", "删除", "查看", "详情", "启用", "禁用", "停用", "启用",
26
- "新增", "添加", "修改", "复制", "移动", "导出", "导入", "下载",
27
- "上传", "设置", "配置", "操作", "更多", "取消", "确定", "保存",
28
- "提交", "重置", "刷新", "搜索", "查询", "筛选", "排序",
29
- }
30
- # CSS 选择器最小长度 — 太短的选择器通常是编造的,缺乏 scope
31
- MIN_CSS_LENGTH = 10
32
- # 验证类 action — 应使用 ai_only
33
- VERIFICATION_ACTIONS = {"assert_visible", "assert_text", "assert_url_contains", "assert_any_visible"}
34
- VALID_ASSERTION_TYPES = {
35
- "equals", "json_path_equals", "status_code", "not_equals", "contains",
36
- "not_contains", "greater_than", "less_than", "json_path_exists",
37
- "regex", "is_empty", "is_not_empty", "in", "not_in",
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
- def detect_secrets(case: dict[str, Any]) -> list[str]:
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
- def validate_case_payload_shape(case: dict[str, Any], CaseCreate: Any) -> list[str]:
119
- errors: list[str] = []
120
- try:
121
- if hasattr(CaseCreate, "model_validate"):
122
- CaseCreate.model_validate(case)
123
- else:
124
- CaseCreate(**case)
125
- except Exception as exc: # noqa: BLE001
126
- errors.append(f"CaseCreate validation failed: {exc}")
127
- return errors
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
- step_ids: set[str] = set()
140
- for index, step in enumerate(steps):
141
- path = f"dsl_json.steps[{index}]"
142
- if not isinstance(step, dict):
143
- errors.append(f"{path} must be an object")
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
- step_id = step.get("id")
146
- if not step_id:
147
- errors.append(f"{path}.id is required")
148
- elif step_id in step_ids:
149
- errors.append(f"{path}.id duplicates '{step_id}'")
150
- else:
151
- step_ids.add(step_id)
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
- return errors
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 validate_project_dsl(dsl: dict[str, Any], validate_dsl: Any) -> list[str]:
271
- result = validate_dsl(dsl)
272
- if getattr(result, "valid", False):
273
- return []
274
- return [f"project dsl_parser: {error}" for error in getattr(result, "errors", [])]
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
- "## Case Results",
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
- case_status = "passed" if not item["errors"] else "failed"
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="case-import-payloads.json")
318
- parser.add_argument("--discovery", required=True, help="codebase-discovery.json")
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
- results: list[dict[str, Any]] = []
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
- payload = load_payload(payload_path)
330
- if payload.get("cases"):
331
- CaseCreate, project_validate_dsl = load_project_validators(discovery_path)
332
- else:
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 not payload.get("cases"):
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
- for index, case in enumerate(payload.get("cases") or [], start=1):
351
- name = str(case.get("name") or f"case-{index}")
352
- tags = list(case.get("tags") or [])
353
- dsl = case.get("dsl_json") or {}
354
- errors: list[str] = []
355
- errors.extend(validate_case_payload_shape(case, CaseCreate))
356
- errors.extend(validate_dsl_static(dsl, tags))
357
- errors.extend(detect_secrets(case))
358
- errors.extend(validate_project_dsl(dsl, project_validate_dsl))
359
- results.append({"name": name, "tags": tags, "errors": errors})
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(report, encoding="utf-8")
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
- print(json.dumps({"status": "passed" if total_errors == 0 else "failed", "errors": total_errors}, ensure_ascii=False))
366
- return 0 if total_errors == 0 else 1
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 执行确认和状态迁移。