@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
@@ -0,0 +1,137 @@
1
+ #!/usr/bin/env python3
2
+ """Read-only access to Core approval records in control.db (变更清单 §1.8).
3
+
4
+ Approvals are written only by the Runtime extension's UI confirmation path.
5
+ This module never writes: it opens control.db with mode=ro and re-derives
6
+ validity by recomputing the current pins with approval_pins.compute (the single
7
+ pin implementation shared with the proposal/confirm side) and comparing them
8
+ with the stored pins_json. The
9
+ file-compatibility authority has no approval channel, so every lookup there
10
+ fails with approval_requires_database_authority.
11
+ """
12
+ from __future__ import annotations
13
+
14
+ import json
15
+ import os
16
+ import sqlite3
17
+ from pathlib import Path
18
+ from typing import Any
19
+
20
+ from tc_hash import canonicalize
21
+
22
+
23
+ APPROVAL_KINDS = frozenset({"execution_plan", "environment_profile", "mode_override", "human_result"})
24
+ REQUIRES_DATABASE = "approval_requires_database_authority"
25
+
26
+
27
+ def _project_id(root: Path) -> str | None:
28
+ try:
29
+ value = json.loads((root / ".devflow" / "project.json").read_text(encoding="utf-8"))["projectId"]
30
+ return value if isinstance(value, str) and value else None
31
+ except (OSError, KeyError, TypeError, ValueError):
32
+ return None
33
+
34
+
35
+ def devflow_home() -> Path:
36
+ """DEVFLOW_HOME rule shared with the TS writer (src/paths.ts normalizeDevflowHome) and hook_common.
37
+
38
+ Unset, empty or whitespace-only means unset -> ~/.devflow-pi. Otherwise only a leading '~' or '~/'
39
+ is expanded (never '~user'), then the path is made absolute with os.path.abspath (existence is not required).
40
+ """
41
+ value = os.environ.get("DEVFLOW_HOME")
42
+ value = "~/.devflow-pi" if value is None or not value.strip() else value.strip()
43
+ if value == "~" or value.startswith("~/"):
44
+ value = str(Path.home()) + value[1:]
45
+ return Path(os.path.abspath(value))
46
+
47
+
48
+ def _connect(root: Path) -> tuple[sqlite3.Connection | None, str | None]:
49
+ project_id = _project_id(root)
50
+ if project_id is None:
51
+ return None, None
52
+ database = devflow_home() / "projects" / project_id / "control.db"
53
+ if not database.is_file():
54
+ return None, project_id
55
+ # Path.as_uri() percent-quotes '?', '#', '%' etc., so they cannot be read as URI syntax.
56
+ connection = sqlite3.connect(f"{database.as_uri()}?mode=ro", uri=True)
57
+ connection.row_factory = sqlite3.Row
58
+ return connection, project_id
59
+
60
+
61
+ def _same(left: Any, right: Any) -> bool:
62
+ try:
63
+ return canonicalize(left) == canonicalize(right)
64
+ except ValueError:
65
+ return False
66
+
67
+
68
+ def latest_approval(root: Path, feature: str, kind: str, subject_key: str) -> dict[str, Any]:
69
+ """The newest non-superseded approval for (feature, kind, subject_key), without validity checks."""
70
+ if kind not in APPROVAL_KINDS:
71
+ return {"ok": False, "reason": "approval_invalid", "message": f"unknown approval kind: {kind}"}
72
+ try:
73
+ connection, project_id = _connect(root)
74
+ if connection is None:
75
+ return {"ok": False, "reason": REQUIRES_DATABASE, "message": "approvals require the database control-plane authority"}
76
+ try:
77
+ authority = connection.execute("SELECT authority FROM authority_state WHERE project_id=?", (project_id,)).fetchone()
78
+ if not authority or authority["authority"] != "database":
79
+ return {"ok": False, "reason": REQUIRES_DATABASE, "message": "approvals require the database control-plane authority"}
80
+ row = connection.execute(
81
+ """SELECT a.id, a.proposal_id, a.pins_json, a.decision_json, a.approved_via, a.approved_at, p.status AS proposal_status, p.payload_json,
82
+ p.kind AS proposal_kind, p.subject_key AS proposal_subject, p.feature AS proposal_feature, p.project_id AS proposal_project
83
+ FROM approvals a JOIN approval_proposals p ON p.id=a.proposal_id
84
+ WHERE a.project_id=? AND a.feature=? AND a.kind=? AND a.subject_key=? AND a.superseded_at IS NULL
85
+ ORDER BY a.approved_at DESC, a.rowid DESC LIMIT 1""",
86
+ (project_id, feature, kind, subject_key),
87
+ ).fetchone()
88
+ finally:
89
+ connection.close()
90
+ except sqlite3.Error as error:
91
+ return {"ok": False, "reason": "approval_invalid", "message": f"approval store is unreadable: {error}"}
92
+ if row is None:
93
+ return {"ok": False, "reason": "approval_missing", "message": f"no {kind} approval for {subject_key}"}
94
+ if (row["approved_via"] != "runtime_ui_confirm" or row["proposal_status"] != "consumed" or row["proposal_kind"] != kind
95
+ or row["proposal_subject"] != subject_key or row["proposal_feature"] != feature or row["proposal_project"] != project_id):
96
+ return {"ok": False, "reason": "approval_invalid", "message": "approval record is not bound to a consumed UI-confirmed proposal"}
97
+ try:
98
+ pins = json.loads(row["pins_json"])
99
+ decision = json.loads(row["decision_json"])
100
+ payload = json.loads(row["payload_json"] or "{}")
101
+ except (TypeError, json.JSONDecodeError):
102
+ return {"ok": False, "reason": "approval_invalid", "message": "approval record JSON is malformed"}
103
+ if not isinstance(pins, dict) or not isinstance(decision, dict) or not isinstance(payload, dict):
104
+ return {"ok": False, "reason": "approval_invalid", "message": "approval pins, decision and payload must be objects"}
105
+ request = payload.get("request", {})
106
+ return {"ok": True, "reason": None, "approval": {"id": row["id"], "proposal_id": row["proposal_id"], "kind": kind, "subject_key": subject_key,
107
+ "pins": pins, "decision": decision, "request": request if isinstance(request, dict) else {},
108
+ "approved_at": row["approved_at"]}}
109
+
110
+
111
+ def valid_approval(root: Path, feature: str, kind: str, subject_key: str, current_pins: dict[str, Any] | None = None) -> dict[str, Any]:
112
+ """Return {"ok", "reason", "message", "approval"}.
113
+
114
+ Valid only when the newest non-superseded approval's pins equal the pins
115
+ approval_pins.compute derives now from the proposal request; any key given
116
+ in ``current_pins`` (e.g. the hash of the DSL the binding actually names)
117
+ must additionally equal the stored pin.
118
+ """
119
+ found = latest_approval(root, feature, kind, subject_key)
120
+ if not found["ok"]:
121
+ return {**found, "approval": None}
122
+ approval = found["approval"]
123
+ try:
124
+ from approval_pins import compute
125
+ except ImportError as error:
126
+ return {"ok": False, "reason": "approval_invalid", "message": f"approval_pins is unavailable: {error}", "approval": None}
127
+ computed = compute(root, feature, kind, subject_key, approval["request"])
128
+ if not computed.get("ok"):
129
+ return {"ok": False, "reason": "approval_stale", "message": "current pins cannot be computed: " + "; ".join(map(str, computed.get("errors", []))), "approval": None}
130
+ expected = dict(computed["pins"])
131
+ for key, value in (current_pins or {}).items():
132
+ if not _same(expected.get(key), value):
133
+ return {"ok": False, "reason": "approval_stale", "message": f"approval does not cover the current {key}", "approval": None}
134
+ if not _same(approval["pins"], expected):
135
+ changed = sorted(key for key in set(approval["pins"]) | set(expected) if not _same(approval["pins"].get(key), expected.get(key)))
136
+ return {"ok": False, "reason": "approval_stale", "message": f"approval pins no longer match: {', '.join(changed)}", "approval": None}
137
+ return {"ok": True, "reason": None, "message": None, "approval": approval}
@@ -17,7 +17,7 @@ require_relative "runtime_context_collector"
17
17
  module ArchitectureAssessment
18
18
  SCHEMA_VERSION = 1
19
19
  RULE_VERSION = 1
20
- ROOT_DIR = File.join(".planning", "architecture-assessment")
20
+ ROOT_DIR = File.join(".devflow/planning", "architecture-assessment")
21
21
 
22
22
  UNRESOLVED = {
23
23
  DELTA_SET_BINDING_FAILED: "DELTA_SET_BINDING_FAILED",
@@ -12,7 +12,7 @@ require_relative "architecture_feasibility"
12
12
  require_relative "control_io"
13
13
 
14
14
  module ArchitectureBrief
15
- ROOT = ".planning/features"
15
+ ROOT = ".devflow/planning/features"
16
16
  SCHEMA_VERSION = 1
17
17
 
18
18
  module_function
@@ -27,7 +27,7 @@ module ArchitectureFeasibility
27
27
 
28
28
  pointer = JSON.parse(File.read(pointer_path))
29
29
  relative = pointer.fetch("path")
30
- raise ArgumentError, "static runtime-context pointer path is invalid" unless relative.is_a?(String) && relative.start_with?(".context/static-runtime-context/revisions/")
30
+ raise ArgumentError, "static runtime-context pointer path is invalid" unless relative.is_a?(String) && relative.start_with?(".devflow/context/static-runtime-context/revisions/")
31
31
 
32
32
  absolute = File.expand_path(relative, root)
33
33
  root_real = File.realpath(root)
@@ -11,7 +11,7 @@ require "time"
11
11
  require "yaml"
12
12
  require_relative "control_io"
13
13
 
14
- options = { root: ".", feature: nil, canonical: nil, changed_source: [], registry: ".planning/artifacts/index.yaml", write: false, json: false }
14
+ options = { root: ".", feature: nil, canonical: nil, changed_source: [], registry: ".devflow/planning/artifacts/index.yaml", write: false, json: false }
15
15
  OptionParser.new do |o|
16
16
  o.on("--root PATH") { |v| options[:root] = v }
17
17
  o.on("--feature NAME") { |v| options[:feature] = v }
@@ -42,7 +42,7 @@ lock = nil
42
42
  begin
43
43
  raise ArgumentError, "feature is required" if options[:feature].to_s.empty?
44
44
  raise ArgumentError, "at least one changed source is required" if options[:changed_source].empty?
45
- canonical_path = options[:canonical] || ".planning/business-model/#{options[:feature]}/canonical.json"
45
+ canonical_path = options[:canonical] || ".devflow/planning/business-model/#{options[:feature]}/canonical.json"
46
46
  canonical_absolute, canonical_relative = DevflowControlIO.resolve_control_path(root, canonical_path, :artifact)
47
47
  model = read_json(canonical_absolute)
48
48
  changed = options[:changed_source].uniq
@@ -56,7 +56,7 @@ begin
56
56
  end
57
57
  end
58
58
  affected_ids = affected.map { |item| item["id"].to_s }.to_set
59
- wireframe_relative = ".planning/features/#{options[:feature]}/canonical.json"
59
+ wireframe_relative = ".devflow/planning/features/#{options[:feature]}/canonical.json"
60
60
  wireframe_path, = DevflowControlIO.resolve_control_path(root, wireframe_relative, :artifact)
61
61
  consumers = []
62
62
  if File.file?(wireframe_path)
@@ -70,7 +70,7 @@ begin
70
70
  if options[:write]
71
71
  lock = DevflowControlIO.acquire_project_lock(root)
72
72
  timestamp = Time.now.utc.iso8601
73
- approval_relative = ".planning/features/#{options[:feature]}/approval.json"
73
+ approval_relative = ".devflow/planning/features/#{options[:feature]}/approval.json"
74
74
  approval_path, = DevflowControlIO.resolve_control_path(root, approval_relative, :artifact)
75
75
  if !consumers.empty? && File.file?(approval_path)
76
76
  approval = read_json(approval_path)
@@ -93,7 +93,7 @@ begin
93
93
  DevflowControlIO.atomic_write(registry_path, registry.to_yaml.sub(/\A---\n/, ""))
94
94
  report["registry_path"] = registry_relative
95
95
  end
96
- report_path = File.join(root, ".planning", "business-model", options[:feature], "invalidation.json")
96
+ report_path = File.join(root, ".devflow/planning", "business-model", options[:feature], "invalidation.json")
97
97
  DevflowControlIO.atomic_write(report_path, JSON.pretty_generate(report) + "\n")
98
98
  report["written"] = true
99
99
  else
@@ -43,7 +43,7 @@ module BusinessModelCommit
43
43
  raise ArgumentError, "invalid feature" unless valid_feature?(feature)
44
44
 
45
45
  root_real = File.realpath(root)
46
- relative = File.join(".planning", "business-model", feature)
46
+ relative = File.join(".devflow/planning", "business-model", feature)
47
47
  absolute = File.expand_path(relative, root_real)
48
48
  raise ArgumentError, "business model path escapes project root" unless absolute.start_with?("#{root_real}#{File::SEPARATOR}")
49
49
 
@@ -67,7 +67,7 @@ module BusinessModelCommit
67
67
  raise ArgumentError, "proposal path contains control characters" if value.match?(/[\x00-\x1F\x7F]/)
68
68
 
69
69
  normalized = Pathname.new(value).cleanpath.to_s.tr("\\", "/")
70
- prefix = File.join(".planning", "business-model", feature, "proposals").tr("\\", "/") + "/"
70
+ prefix = File.join(".devflow/planning", "business-model", feature, "proposals").tr("\\", "/") + "/"
71
71
  raise ArgumentError, "proposal path is outside the feature proposal directory" unless normalized.start_with?(prefix)
72
72
  absolute = File.expand_path(normalized, root_real)
73
73
  raise ArgumentError, "proposal path escapes project root" unless absolute.start_with?("#{root_real}#{File::SEPARATOR}")
@@ -255,7 +255,7 @@ module BusinessModelCommit
255
255
  def load_delta(root, feature, raw)
256
256
  raise ArgumentError, "candidate delta path is required" if raw.to_s.empty?
257
257
  path = File.expand_path(raw, root)
258
- feature_root = File.expand_path(File.join(".planning", "business-model", feature, "candidates"), root)
258
+ feature_root = File.expand_path(File.join(".devflow/planning", "business-model", feature, "candidates"), root)
259
259
  raise ArgumentError, "candidate delta is missing" unless File.file?(path)
260
260
  path = File.realpath(path)
261
261
  feature_root = File.realpath(feature_root)
@@ -290,7 +290,7 @@ module BusinessModelCommit
290
290
  def source_registry_fingerprint(root, feature, aggregate)
291
291
  registry_ref = aggregate.dig("merged", "source_registry_ref").to_s
292
292
  return "" if registry_ref.empty?
293
- path = if registry_ref.start_with?(".planning/")
293
+ path = if registry_ref.start_with?(".devflow/planning/")
294
294
  File.expand_path(registry_ref, root)
295
295
  else
296
296
  File.expand_path(registry_ref, feature_dir(root, feature))
@@ -606,7 +606,7 @@ def load_json(path: Path) -> Any:
606
606
 
607
607
 
608
608
  def requirement_nodes(root: Path, feature: str, violations: list[dict[str, Any]]) -> set[str]:
609
- requirements_root = (root / ".planning" / "requirements").resolve()
609
+ requirements_root = (root / ".devflow/planning" / "requirements").resolve()
610
610
  path = (requirements_root / feature / "governance.json").resolve()
611
611
  if not path.is_relative_to(requirements_root):
612
612
  add_violation(violations, "BUSINESS_REQUIREMENT_GRAPH_INVALID", feature, path=str(path), message="feature escapes requirements directory")
@@ -101,7 +101,7 @@ module BusinessSourceResolver
101
101
  output = command(root, "git", "status", "--porcelain=v1", "--untracked-files=all")
102
102
  lines = output.lines.map(&:rstrip).reject do |line|
103
103
  path = line.length > 3 ? line[3..].to_s.strip : ""
104
- path.start_with?(".planning/", ".context/")
104
+ path.start_with?(".devflow/planning/", ".devflow/context/")
105
105
  end
106
106
  "sha256:#{Digest::SHA256.hexdigest(lines.join("\n"))}"
107
107
  end
@@ -237,7 +237,7 @@ module BusinessSourceResolver
237
237
  current_signature = worktree_signature(root)
238
238
  add(errors, "BUSINESS_WORKTREE_SIGNATURE_MISMATCH", "worktree signature is stale", source_id: id) unless source["worktree_signature"].to_s == current_signature
239
239
 
240
- snapshot_path = File.join(root, ".planning", "code-index", "SNAPSHOT.json")
240
+ snapshot_path = File.join(root, ".devflow/planning", "code-index", "SNAPSHOT.json")
241
241
  unless File.file?(snapshot_path)
242
242
  add(errors, "BUSINESS_CODE_INDEX_STALE", "code index snapshot is missing", source_id: id, path: snapshot_path)
243
243
  return
@@ -258,7 +258,7 @@ module BusinessSourceResolver
258
258
  end
259
259
  return if symbol.empty?
260
260
 
261
- symbols_path = File.join(root, ".planning", "code-index", "symbols.jsonl")
261
+ symbols_path = File.join(root, ".devflow/planning", "code-index", "symbols.jsonl")
262
262
  unless File.file?(symbols_path)
263
263
  add(errors, "BUSINESS_CODE_SYMBOL_NOT_FOUND", "symbols index is missing", source_id: id, path: symbols_path)
264
264
  return
@@ -318,7 +318,7 @@ module BusinessSourceResolver
318
318
  raise ArgumentError, "invalid feature" unless valid_feature?(feature)
319
319
  root = File.realpath(root)
320
320
  schema = load_yaml(REGISTRY_SCHEMA)
321
- raw_registry = registry_path || File.join(".planning", "business-model", feature, "source-registry.yaml")
321
+ raw_registry = registry_path || File.join(".devflow/planning", "business-model", feature, "source-registry.yaml")
322
322
  registry_absolute, registry_relative = safe_path(root, raw_registry, "source registry")
323
323
  registry = load_yaml(registry_absolute)
324
324
  errors = []
@@ -60,22 +60,22 @@ module CheckerAdapter
60
60
  when "cross-track-consistency-check"
61
61
  ["ruby", File.join(scripts, "cross_track_consistency_check.rb"), "--feature", feature, "--json"]
62
62
  when "business-cross-model-check"
63
- business = ".planning/business-model/#{feature}/canonical.json"
63
+ business = ".devflow/planning/business-model/#{feature}/canonical.json"
64
64
  return nil unless File.file?(File.join(root, business))
65
65
  command = ["python3", File.join(scripts, "business_cross_model_check.py"), "--business-canonical", business]
66
- wireframe = ".planning/features/#{feature}/canonical.json"
67
- claims = ".planning/features/#{feature}/business-claims.yaml"
68
- traceability = ".planning/requirements/#{feature}/traceability.json"
66
+ wireframe = ".devflow/planning/features/#{feature}/canonical.json"
67
+ claims = ".devflow/planning/features/#{feature}/business-claims.yaml"
68
+ traceability = ".devflow/planning/requirements/#{feature}/traceability.json"
69
69
  command += ["--wireframe", wireframe] if File.file?(File.join(root, wireframe))
70
70
  command += ["--claims", claims] if File.file?(File.join(root, claims))
71
71
  command += ["--traceability", traceability] if File.file?(File.join(root, traceability))
72
72
  command + ["--json"]
73
73
  when "business-claim-reference-check"
74
- claims = ".planning/features/#{feature}/business-claims.yaml"
75
- business = ".planning/business-model/#{feature}/canonical.json"
74
+ claims = ".devflow/planning/features/#{feature}/business-claims.yaml"
75
+ business = ".devflow/planning/business-model/#{feature}/canonical.json"
76
76
  return nil unless File.file?(File.join(root, claims)) && File.file?(File.join(root, business))
77
77
  command = ["python3", File.join(scripts, "business_claim_validate.py"), "--claims", claims, "--business-canonical", business]
78
- traceability = ".planning/requirements/#{feature}/traceability.json"
78
+ traceability = ".devflow/planning/requirements/#{feature}/traceability.json"
79
79
  command += ["--traceability", traceability] if File.file?(File.join(root, traceability))
80
80
  command
81
81
  end
@@ -5,6 +5,7 @@ require "fileutils"
5
5
  require "json"
6
6
  require "pathname"
7
7
  require "securerandom"
8
+ require "time"
8
9
 
9
10
  # Shared durability primitives for every writer in the Devflow control plane.
10
11
  # The project lock serializes state, workflow, registry, and next-intent updates;
@@ -14,10 +15,52 @@ module DevflowControlIO
14
15
 
15
16
  module_function
16
17
 
18
+ def assert_layout_ready(root)
19
+ root_path = File.realpath(root)
20
+ legacy_planning = File.join(root_path, ".planning")
21
+ legacy_context = File.join(root_path, ".context")
22
+ planning_markers = %w[STATE.md PROJECT.md .devflow.lock navigation/INDEX.md code-index/INDEX.md workflows contracts evidence review-runs requirements features handoffs artifacts phase-ownership.yaml]
23
+ context_markers = %w[spec/index.md index.md project/index.md knowledge/index.md]
24
+ legacy_markers = planning_markers.map { |item| File.join(legacy_planning, item) } + context_markers.map { |item| File.join(legacy_context, item) }
25
+ return true unless legacy_markers.any? { |item| File.exist?(item) }
26
+
27
+ manifest = JSON.parse(File.read(File.join(root_path, ".devflow", "project.json")))
28
+ valid_manifest = manifest["schemaVersion"] == 1 &&
29
+ manifest["projectId"].to_s.match?(/\A[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}\z/i) &&
30
+ !manifest["name"].to_s.strip.empty? &&
31
+ !Time.iso8601(manifest["createdAt"].to_s).nil? &&
32
+ [nil, 1, 2].include?(manifest["layoutVersion"])
33
+ raise InvalidControlPath, "DEVFLOW_LEGACY_LAYOUT_CONFIRMATION_REQUIRED: valid project manifest required" unless valid_manifest
34
+
35
+ marker = JSON.parse(File.read(File.join(root_path, ".devflow", "layout-migration.json"))) rescue nil
36
+ migration_complete = marker.is_a?(Hash) && marker["schemaVersion"] == 1 && marker["status"] == "complete" && marker["migrated"].is_a?(Array)
37
+ active = %w[STATE.md workflows contracts evidence review-runs requirements features handoffs artifacts phase-ownership.yaml].find do |item|
38
+ File.exist?(File.join(legacy_planning, item))
39
+ end
40
+ raise InvalidControlPath, "DEVFLOW_ACTIVE_LEGACY_LAYOUT: .planning/#{active} requires dedicated control-plane migration" if active && !migration_complete
41
+ canonical_exists = File.exist?(File.join(root_path, ".devflow", "planning")) || File.exist?(File.join(root_path, ".devflow", "context"))
42
+ if manifest["layoutVersion"] == 2 && !migration_complete
43
+ raise InvalidControlPath, "DEVFLOW_LEGACY_REINTRODUCTION: v2 project cannot import legacy layout"
44
+ end
45
+ if manifest["layoutVersion"] == 2 && migration_complete
46
+ planning_legacy = planning_markers.any? { |item| File.exist?(File.join(legacy_planning, item)) }
47
+ context_legacy = context_markers.any? { |item| File.exist?(File.join(legacy_context, item)) }
48
+ missing_canonical = (planning_legacy && !File.exist?(File.join(root_path, ".devflow", "planning"))) ||
49
+ (context_legacy && !File.exist?(File.join(root_path, ".devflow", "context")))
50
+ raise InvalidControlPath, "DEVFLOW_LEGACY_REINTRODUCTION: v2 project will not backfill a missing canonical directory" if missing_canonical
51
+ end
52
+ raise InvalidControlPath, "DEVFLOW_LAYOUT_CONFLICT: canonical and legacy layouts coexist without migration marker" if canonical_exists && !migration_complete
53
+ raise InvalidControlPath, "DEVFLOW_LAYOUT_MIGRATION_REQUIRED: run project initialization" unless canonical_exists
54
+ true
55
+ rescue Errno::ENOENT, JSON::ParserError, ArgumentError
56
+ raise InvalidControlPath, "DEVFLOW_LEGACY_LAYOUT_CONFIRMATION_REQUIRED: valid project manifest required"
57
+ end
58
+
17
59
  # Control-plane files are not general-purpose CLI file arguments. Keeping
18
60
  # their location fixed prevents a crafted STATE/workflow/registry reference
19
61
  # from turning recovery or synchronization into an out-of-project writer.
20
62
  def resolve_control_path(root, raw, kind)
63
+ assert_layout_ready(root)
21
64
  root_path = File.realpath(root)
22
65
  value = raw.to_s
23
66
  raise InvalidControlPath, "#{kind} path is required" if value.empty?
@@ -27,14 +70,14 @@ module DevflowControlIO
27
70
  normalized = Pathname.new(value).cleanpath.to_s.tr("\\", "/")
28
71
  raise InvalidControlPath, "#{kind} path cannot traverse parent directories" if normalized == ".." || normalized.start_with?("../")
29
72
  allowed = case kind
30
- when :state then normalized == ".planning/STATE.md"
31
- when :workflow then normalized.match?(%r{\A\.planning/workflows/[A-Za-z0-9][A-Za-z0-9_-]*\.yaml\z})
32
- when :registry then normalized == ".planning/artifacts/index.yaml"
33
- when :artifact then normalized.start_with?(".planning/") || normalized.start_with?(".context/")
73
+ when :state then normalized == ".devflow/planning/STATE.md"
74
+ when :workflow then normalized.match?(%r{\A\.devflow/planning/workflows/[A-Za-z0-9][A-Za-z0-9_-]*\.yaml\z})
75
+ when :registry then normalized == ".devflow/planning/artifacts/index.yaml"
76
+ when :artifact then normalized.start_with?(".devflow/planning/") || normalized.start_with?(".devflow/context/")
34
77
  # Feature names are user-facing and may be Unicode. `cleanpath`
35
78
  # and the parent-traversal check above own containment; this
36
79
  # matcher only fixes the handoff namespace and immutable name.
37
- when :handoff then normalized.match?(%r{\A\.planning/handoffs/[^/]+/ROL-[0-9a-f-]+\.json\z})
80
+ when :handoff then normalized.match?(%r{\A\.devflow/planning/handoffs/[^/]+/ROL-[0-9a-f-]+\.json\z})
38
81
  else false
39
82
  end
40
83
  raise InvalidControlPath, "invalid #{kind} control path" unless allowed
@@ -58,7 +101,8 @@ module DevflowControlIO
58
101
  end
59
102
 
60
103
  def acquire_project_lock(root)
61
- planning_dir = File.join(root, ".planning")
104
+ assert_layout_ready(root)
105
+ planning_dir = File.join(root, ".devflow/planning")
62
106
  FileUtils.mkdir_p(planning_dir)
63
107
  handle = File.open(File.join(planning_dir, ".devflow.lock"), File::RDWR | File::CREAT, 0o644)
64
108
  handle.flock(File::LOCK_EX)
@@ -122,7 +166,7 @@ module DevflowControlIO
122
166
  # 独立受控工件登记:与 sync_artifacts 的 workflow-outputs registry 分开,
123
167
  # 避免被 workflow 重建覆盖。按 path 去重,last-write-wins。
124
168
  def register_control_artifact(root, entry)
125
- path = File.join(root, ".planning", "artifacts", "control-artifacts.json")
169
+ path = File.join(root, ".devflow/planning", "artifacts", "control-artifacts.json")
126
170
  existing = File.exist?(path) ? JSON.parse(File.read(path)) : { "schema_version" => 1, "artifacts" => [] }
127
171
  existing["artifacts"] ||= []
128
172
  existing["artifacts"].reject! { |item| item["path"] == entry["path"] }
@@ -16,7 +16,7 @@ feature = options[:feature].to_s
16
16
  raise ArgumentError, "feature contains path separators" if feature.include?("/") || feature.include?("\\")
17
17
 
18
18
  root = Dir.pwd
19
- base = File.join(root, ".planning", "features", feature)
19
+ base = File.join(root, ".devflow/planning", "features", feature)
20
20
  files = {
21
21
  "api_contract" => File.join(base, "api-contract.md"),
22
22
  "api_call_guide" => File.join(base, "api-call-guide.md"),
@@ -0,0 +1,87 @@
1
+ #!/usr/bin/env python3
2
+ """Structural coverage of a frozen TC by its v1 DSL (方案 §6.1, first layer).
3
+
4
+ Every frozen precondition and step must be covered by at least one DSL step;
5
+ the oracle must be covered by at least one non-weak assertion. This only
6
+ detects omissions and obviously weak assertions; semantic adequacy remains the
7
+ job of the human-approved execution plan.
8
+ """
9
+ from __future__ import annotations
10
+
11
+ from typing import Any
12
+
13
+ from dsl_v1 import UI_ASSERTIONS, UI_INTERACTIONS, all_steps
14
+
15
+
16
+ def is_assertion(step: dict[str, Any]) -> bool:
17
+ if step.get("driver") == "ui":
18
+ return step.get("action") in UI_ASSERTIONS
19
+ return step.get("driver") == "api" and (bool(step.get("assertions")) or "expect_status" in step)
20
+
21
+
22
+ def weak_reason(step: dict[str, Any], preceding: list[dict[str, Any]]) -> str | None:
23
+ """MVP weak assertions: assert_visible of a static entry element; 2xx-only API checks."""
24
+ if step.get("driver") == "api":
25
+ status = step.get("expect_status")
26
+ if not step.get("assertions") and (status is None or 200 <= status <= 299):
27
+ return "API assertion only checks a 2xx status without response body assertions"
28
+ return None
29
+ if step.get("action") != "assert_visible":
30
+ return None
31
+ interactions = [item for item in preceding if (item.get("driver") == "ui" and item.get("action") in UI_INTERACTIONS)
32
+ or (item.get("driver") == "api" and item.get("method") != "GET")]
33
+ if not interactions:
34
+ return "assert_visible before any interaction only proves a static entry element is present"
35
+ if any(item.get("target") == step.get("target") for item in interactions):
36
+ return "assert_visible on an element the flow itself interacted with does not verify an outcome"
37
+ return None
38
+
39
+
40
+ def _count(data: dict[str, Any], key: str) -> int:
41
+ value = data.get(key)
42
+ if isinstance(value, list):
43
+ return len(value)
44
+ return 1 if isinstance(value, str) and value.strip() else 0
45
+
46
+
47
+ def check(tc_data: dict[str, Any], dsl: dict[str, Any]) -> list[str]:
48
+ errors: list[str] = []
49
+ counts = {"preconditions": _count(tc_data, "preconditions"), "steps": _count(tc_data, "steps")}
50
+ covered: dict[str, set[int]] = {"preconditions": set(), "steps": set()}
51
+ oracle = tc_data.get("oracle")
52
+ has_oracle = (isinstance(oracle, str) and bool(oracle.strip())) or (isinstance(oracle, list) and bool(oracle))
53
+ oracle_assertions: list[tuple[str, dict[str, Any], str | None]] = []
54
+ main: list[dict[str, Any]] = []
55
+ for phase, path, step in all_steps(dsl):
56
+ covers = step.get("covers") if isinstance(step.get("covers"), dict) else {}
57
+ if phase == "cleanup" and covers:
58
+ errors.append(f"{path}.covers is not allowed on cleanup steps")
59
+ continue
60
+ for key in ("preconditions", "steps"):
61
+ for index in covers.get(key, []):
62
+ if not isinstance(index, int) or isinstance(index, bool) or not 1 <= index <= counts[key]:
63
+ errors.append(f"{path}.covers.{key} index {index} is outside the frozen TC {key} (1..{counts[key]})")
64
+ else:
65
+ covered[key].add(index)
66
+ if covers.get("oracle") is True:
67
+ if not is_assertion(step):
68
+ errors.append(f"{path} covers the oracle but {step.get('action')} is not an assertion")
69
+ elif phase != "main":
70
+ errors.append(f"{path} covers the oracle outside the main steps")
71
+ else:
72
+ oracle_assertions.append((path, step, weak_reason(step, main)))
73
+ if phase == "main":
74
+ main.append(step)
75
+ for key in ("preconditions", "steps"):
76
+ missing = sorted(set(range(1, counts[key] + 1)) - covered[key])
77
+ if missing:
78
+ errors.append(f"frozen TC {key} not covered by any DSL step: {', '.join(map(str, missing))}")
79
+ if has_oracle and not oracle_assertions:
80
+ errors.append("frozen TC oracle is not covered by any assertion step")
81
+ elif oracle_assertions and all(reason for _path, _step, reason in oracle_assertions):
82
+ errors.extend(f"{path}: weak oracle assertion ({reason})" for path, _step, reason in oracle_assertions)
83
+ errors.append("frozen TC oracle is covered only by weak assertions")
84
+ if tc_data.get("execution_surface") == "ui" or (tc_data.get("execution_surface") is None and tc_data.get("test_type") == "page"):
85
+ if oracle_assertions and not any(step.get("driver") == "ui" and not reason for _path, step, reason in oracle_assertions):
86
+ errors.append("UI TC oracle must be covered by a non-weak page assertion; API checks cannot replace it")
87
+ return errors