@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
@@ -109,7 +109,7 @@ def validate_authority(root: Path, feature: str, expectations: list) -> tuple[li
109
109
  issues.append(f"{item['id']}: authority_ref must identify a Core graph node and revision")
110
110
  continue
111
111
  node_id, revision = ref[len("core-graph:"):].rsplit("@", 1)
112
- graph_path = f".planning/requirements/{feature}/governance.json"
112
+ graph_path = f".devflow/planning/requirements/{feature}/governance.json"
113
113
  graph_file = safe_file(root, graph_path)
114
114
  authority = read_json(graph_file)
115
115
  node = next((n for n in authority.get("nodes", []) if isinstance(n, dict) and n.get("id") == node_id), None)
@@ -132,7 +132,7 @@ def validate_authority(root: Path, feature: str, expectations: list) -> tuple[li
132
132
 
133
133
 
134
134
  def db_open(root: Path) -> sqlite3.Connection:
135
- planning = root / ".planning"
135
+ planning = root / ".devflow/planning"
136
136
  if planning.is_symlink():
137
137
  raise ValueError("unsafe planning directory")
138
138
  directory = planning / "review-runs"
@@ -174,7 +174,7 @@ def response(status: str, chain_id: str | None, round_no: int, **details: Any) -
174
174
 
175
175
  def locate_index(root: Path, accepted: list, target_paths: list[str], questions: list[str]) -> dict:
176
176
  """Ask the index for bounded leads, never for authoritative conclusions."""
177
- index = root / ".planning" / "code-index"
177
+ index = root / ".devflow/planning" / "code-index"
178
178
  script = Path(__file__).resolve().parents[3].parent / "devflow-intel" / "skills" / "workflow-code-index" / "scripts" / "code_index.py"
179
179
  if not index.exists() or not script.exists():
180
180
  return {"status": "unavailable", "reason": "No local code-index snapshot; source evidence is independent"}
@@ -218,7 +218,7 @@ def verify_core_result(root: Path, feature: str, evidence: Any, expected_status:
218
218
  """Accept only a Core-owned TC result bound to the feature and frozen suite."""
219
219
  if not isinstance(evidence, dict):
220
220
  return False, "missing Core acceptance-test result reference"
221
- relative = f".planning/test-runs/{feature}/acceptance-results.json"
221
+ relative = f".devflow/planning/test-runs/{feature}/acceptance-results.json"
222
222
  if evidence.get("path") != relative or not isinstance(evidence.get("tc_id"), str):
223
223
  return False, "result must reference a Core acceptance TC for this feature"
224
224
  try:
@@ -226,7 +226,7 @@ def verify_core_result(root: Path, feature: str, evidence: Any, expected_status:
226
226
  if digest(result_file.read_bytes()) != evidence.get("sha256"):
227
227
  return False, "acceptance result hash mismatch"
228
228
  payload = read_json(result_file)
229
- suite = read_json(safe_file(root, f".planning/requirements/{feature}/tests.json"))
229
+ suite = read_json(safe_file(root, f".devflow/planning/requirements/{feature}/tests.json"))
230
230
  if payload.get("origin") != "core_acceptance_test_runner" or payload.get("feature") != feature:
231
231
  return False, "not a Core acceptance-test run"
232
232
  if payload.get("test_suite") != {"graph_revision": suite.get("graph_revision"), "fingerprint": suite.get("view_meta", {}).get("fingerprint")}:
@@ -252,7 +252,7 @@ def verify_core_result(root: Path, feature: str, evidence: Any, expected_status:
252
252
  def verify_core_impact(root: Path, feature: str, evidence: dict, impact: str, trigger: str) -> tuple[bool, str]:
253
253
  """A failed TC alone does not establish the reviewer's causal/impact label."""
254
254
  try:
255
- suite = read_json(safe_file(root, f".planning/requirements/{feature}/tests.json"))
255
+ suite = read_json(safe_file(root, f".devflow/planning/requirements/{feature}/tests.json"))
256
256
  node = next((n for n in suite.get("nodes", []) if isinstance(n, dict) and n.get("id") == evidence.get("tc_id")), None)
257
257
  data = node.get("data", {}) if node else {}
258
258
  if data.get("review_impact") == impact and data.get("review_trigger") == trigger:
@@ -263,7 +263,7 @@ def verify_core_impact(root: Path, feature: str, evidence: dict, impact: str, tr
263
263
 
264
264
 
265
265
  def declared_change_paths(root: Path, feature: str) -> tuple[set[str], str, str]:
266
- relative = f".planning/features/{feature}/变更清单.md"
266
+ relative = f".devflow/planning/features/{feature}/变更清单.md"
267
267
  source = safe_file(root, relative)
268
268
  declarations = re.findall(r"^\s*-\s*\*\*文件\*\*\s*[::]\s*(.+)$", source.read_text(encoding="utf-8"), re.MULTILINE)
269
269
  paths = set()
@@ -295,7 +295,7 @@ def verify_coverage(root: Path, feature: str, required: list[str], coverage_evid
295
295
  if not valid:
296
296
  issues.append(f"{tag}: {reason}")
297
297
  continue
298
- suite = read_json(safe_file(root, f".planning/requirements/{feature}/tests.json"))
298
+ suite = read_json(safe_file(root, f".devflow/planning/requirements/{feature}/tests.json"))
299
299
  node = next((n for n in suite.get("nodes", []) if isinstance(n, dict) and n.get("id") == ref["tc_id"]), None)
300
300
  types = {"scenario:normal": {"api", "page"}, "scenario:unauthorized": {"permission"}, "scenario:failure_rollback": {"resilience", "boundary"}, "scenario:compatibility": {"migration"}}
301
301
  data = node.get("data", {}) if node else {}
@@ -310,7 +310,7 @@ def verify_coverage(root: Path, feature: str, required: list[str], coverage_evid
310
310
 
311
311
  def suite_has_failures(root: Path, feature: str) -> bool:
312
312
  try:
313
- payload = read_json(safe_file(root, f".planning/test-runs/{feature}/acceptance-results.json"))
313
+ payload = read_json(safe_file(root, f".devflow/planning/test-runs/{feature}/acceptance-results.json"))
314
314
  return any(isinstance(item, dict) and item.get("status") != "passed" for item in payload.get("results", []))
315
315
  except (OSError, ValueError, TypeError, json.JSONDecodeError):
316
316
  return True
@@ -322,13 +322,13 @@ def gate_status(root: Path, feature: str, contract_id: str | None = None) -> dic
322
322
  if not contract_id:
323
323
  return {"status": "human_confirmation", "reason": "Current Core review contract identity is required"}
324
324
  try:
325
- contract = read_json(safe_file(root, f".planning/contracts/{feature}/{contract_id}.json"))
325
+ contract = read_json(safe_file(root, f".devflow/planning/contracts/{feature}/{contract_id}.json"))
326
326
  if contract.get("origin") != "core_execution_contract" or contract.get("step") != "code-review" or contract.get("feature") != feature or contract.get("contract_id") != contract_id:
327
327
  return {"status": "core_contract_conflict", "reason": "Review contract identity is not a frozen Core code-review contract"}
328
328
  sys.path.insert(0, str(Path(__file__).resolve().parent))
329
329
  from review_preflight import load_state
330
- state = load_state(safe_file(root, ".planning/STATE.md"))
331
- graph = read_json(safe_file(root, f".planning/requirements/{feature}/governance.json"))
330
+ state = load_state(safe_file(root, ".devflow/planning/STATE.md"))
331
+ graph = read_json(safe_file(root, f".devflow/planning/requirements/{feature}/governance.json"))
332
332
  workflow = safe_file(root, contract["workflow_path"])
333
333
  if (state.get("current_feature") != feature or state.get("current_step") != "code-review"
334
334
  or state.get("revision") != contract.get("state_revision")
@@ -337,7 +337,7 @@ def gate_status(root: Path, feature: str, contract_id: str | None = None) -> dic
337
337
  return {"status": "stale_evidence", "reason": "Review contract differs from current Core state, graph, or workflow"}
338
338
  except (OSError, ValueError, KeyError, TypeError, ImportError, json.JSONDecodeError) as exc:
339
339
  return {"status": "human_confirmation", "reason": f"Current Core review contract cannot be verified: {exc}"}
340
- database = root / ".planning" / "review-runs" / "review-runs.sqlite"
340
+ database = root / ".devflow/planning" / "review-runs" / "review-runs.sqlite"
341
341
  if not database.is_file() or database.is_symlink():
342
342
  return {"status": "human_confirmation", "reason": "No Core review round exists"}
343
343
  db = sqlite3.connect(f"file:{database}?mode=ro", uri=True)
@@ -366,7 +366,7 @@ def gate_status(root: Path, feature: str, contract_id: str | None = None) -> dic
366
366
  index_generation = fixed.get("code_index_generation")
367
367
  if index_generation is not None:
368
368
  try:
369
- snapshot = read_json(safe_file(root, ".planning/code-index/SNAPSHOT.json"))
369
+ snapshot = read_json(safe_file(root, ".devflow/planning/code-index/SNAPSHOT.json"))
370
370
  if snapshot.get("generation") != index_generation:
371
371
  return {"status": "stale_evidence", "reason": "Code-index generation changed after review", "chain_id": result.get("chain_id")}
372
372
  except (OSError, ValueError, json.JSONDecodeError):
@@ -415,11 +415,11 @@ def review_markdown(result: dict) -> str:
415
415
 
416
416
  def render_review(root: Path, feature: str, contract_id: str) -> dict:
417
417
  root = root.resolve(strict=True)
418
- contract = read_json(safe_file(root, f".planning/contracts/{feature}/{contract_id}.json"))
418
+ contract = read_json(safe_file(root, f".devflow/planning/contracts/{feature}/{contract_id}.json"))
419
419
  path = next((item for item in contract.get("allowed_paths", []) if isinstance(item, str) and item.endswith("/REVIEW.md")), None)
420
420
  if not path:
421
421
  return {"status": "core_contract_conflict", "reason": "Core contract has no REVIEW.md output"}
422
- database = root / ".planning/review-runs/review-runs.sqlite"
422
+ database = root / ".devflow/planning/review-runs/review-runs.sqlite"
423
423
  if not database.is_file():
424
424
  return {"status": "human_confirmation", "reason": "No Core review round exists"}
425
425
  db = sqlite3.connect(f"file:{database}?mode=ro", uri=True)
@@ -616,7 +616,7 @@ def run(root: Path, request: dict) -> dict:
616
616
  db.commit()
617
617
  return result
618
618
  if index_discovery.get("generation"):
619
- current_snapshot = root / ".planning" / "code-index" / "SNAPSHOT.json"
619
+ current_snapshot = root / ".devflow/planning" / "code-index" / "SNAPSHOT.json"
620
620
  if not current_snapshot.exists() or read_json(current_snapshot).get("generation") != index_discovery["generation"]:
621
621
  result = response("stale_evidence", chain_id, round_no, questions=["Code-index generation changed during review"])
622
622
  db.execute("INSERT INTO events(chain_id,status,detail_json) VALUES(?,?,?)", (chain_id, result["status"], canonical(result)))
@@ -645,7 +645,7 @@ def run(root: Path, request: dict) -> dict:
645
645
  db.commit()
646
646
  return result
647
647
  status = "terminated_p0" if round_no == 3 and summary["P0"] else ("findings" if open_findings else "clean")
648
- core_results = {rel: digest(safe_file(root, rel).read_bytes()) for rel in (f".planning/requirements/{target['feature']}/tests.json", f".planning/test-runs/{target['feature']}/acceptance-results.json")}
648
+ core_results = {rel: digest(safe_file(root, rel).read_bytes()) for rel in (f".devflow/planning/requirements/{target['feature']}/tests.json", f".devflow/planning/test-runs/{target['feature']}/acceptance-results.json")}
649
649
  result = response(status, chain_id, round_no, fixed_versions={"source": versions, "authority": accepted, "core_results": core_results, "change_plan": {"path": change_plan_path, "sha256": change_plan_hash, "declared_paths": sorted(declared_paths)}, "code_index_generation": index_discovery.get("generation")}, index_discovery=index_discovery, coverage={"covered": sorted(covered), "gaps": gaps, "index_gap": index_discovery.get("reason") if index_discovery["status"] != "located" else None}, findings=findings, risk_summary=summary, improvement_plan=[{"finding_id": f["finding_id"], "severity": f["severity"], "action": f["improvement"]} for f in sorted(open_findings, key=lambda x: x["severity"])], all_p0_resolved=summary["P0"] == 0, severity_source="independent_reviewer_core_evidence_bound", semantic_causality_verified=True, automatic_release_allowed=status == "clean", termination_scope="current_task_only" if status == "terminated_p0" else None, reviewer_task={key: binding[key] for key in ("agent", "feature", "contract_id", "task_call_id", "report_sha256")}, history=[{"round": r, "status": json.loads(raw)["status"]} for r, raw in db.execute("SELECT round,result_json FROM rounds WHERE chain_id=? ORDER BY round", (chain_id,))])
650
650
  db.execute("INSERT INTO reviewer_tasks(task_call_id,chain_id,round,report_sha256) VALUES(?,?,?,?)", (binding["task_call_id"], chain_id, round_no, binding["report_sha256"]))
651
651
  db.execute("INSERT INTO rounds(chain_id,round,result_json) VALUES(?,?,?)", (chain_id, round_no, canonical(result)))
@@ -14,8 +14,8 @@ require_relative "control_io"
14
14
 
15
15
  module RuntimeContextCollector
16
16
  SCHEMA_VERSION = 1
17
- HISTORY_DIR = File.join(".context", "runtime-context", "revisions")
18
- POINTER = File.join(".context", "runtime-context.json")
17
+ HISTORY_DIR = File.join(".devflow/context", "runtime-context", "revisions")
18
+ POINTER = File.join(".devflow/context", "runtime-context.json")
19
19
  EXTRACTORS = {
20
20
  "package.json" => :extract_package_json,
21
21
  "requirements.txt" => :extract_requirements_txt,
@@ -170,7 +170,7 @@ module RuntimeContextCollector
170
170
  history = File.join(root, HISTORY_DIR, "#{revision}.json")
171
171
  DevflowControlIO.atomic_create(history, JSON.pretty_generate(snapshot) + "\n")
172
172
  DevflowControlIO.atomic_write(File.join(root, POINTER), JSON.pretty_generate({ "current_revision" => revision, "path" => history.sub("#{root}/", "") }) + "\n")
173
- DevflowControlIO.append_audit(File.join(root, ".context", "runtime-context", "audit.jsonl"), {
173
+ DevflowControlIO.append_audit(File.join(root, ".devflow/context", "runtime-context", "audit.jsonl"), {
174
174
  "event" => "snapshot_collected", "snapshot_revision" => revision,
175
175
  "repository_revision" => repository_revision, "coverage_status" => coverage_status
176
176
  })
@@ -69,7 +69,7 @@ def lease_expiry(seconds)
69
69
  end
70
70
 
71
71
  root = Dir.pwd
72
- state_path, = DevflowControlIO.resolve_control_path(root, ".planning/STATE.md", :state)
72
+ state_path, = DevflowControlIO.resolve_control_path(root, ".devflow/planning/STATE.md", :state)
73
73
  result = catch(:transition_done) do
74
74
  lock = DevflowControlIO.acquire_project_lock(root)
75
75
  begin
@@ -129,7 +129,7 @@ result = catch(:transition_done) do
129
129
  throw :transition_done, result
130
130
  end
131
131
  rollover_id = "ROL-#{SecureRandom.uuid}"
132
- relative_path = ".planning/handoffs/#{state.fetch("current_feature")}/#{rollover_id}.json"
132
+ relative_path = ".devflow/planning/handoffs/#{state.fetch("current_feature")}/#{rollover_id}.json"
133
133
  absolute_path, = DevflowControlIO.resolve_control_path(root, relative_path, :handoff)
134
134
  payload = {
135
135
  "schema_version" => 1,
@@ -144,9 +144,9 @@ result = catch(:transition_done) do
144
144
  "status" => state["status"], "completed_steps" => state["completed_steps"], "pending_steps" => state["pending_steps"]
145
145
  },
146
146
  "references" => {
147
- "state_path" => ".planning/STATE.md",
147
+ "state_path" => ".devflow/planning/STATE.md",
148
148
  "workflow_path" => state["workflow_config"],
149
- "artifact_registry" => ".planning/artifacts/index.yaml"
149
+ "artifact_registry" => ".devflow/planning/artifacts/index.yaml"
150
150
  }
151
151
  }
152
152
  serialized = JSON.generate(payload) + "\n"
@@ -17,9 +17,9 @@ require_relative "control_io"
17
17
  module StaticRuntimeContextCollector
18
18
  SCHEMA_VERSION = 2
19
19
  COLLECTOR_VERSION = "static-runtime-context-v2.1"
20
- ROOT_DIR = File.join(".context", "static-runtime-context")
20
+ ROOT_DIR = File.join(".devflow/context", "static-runtime-context")
21
21
  HISTORY_DIR = File.join(ROOT_DIR, "revisions")
22
- POINTER = ".context/static-runtime-context.json"
22
+ POINTER = ".devflow/context/static-runtime-context.json"
23
23
  AUDIT_PATH = File.join(ROOT_DIR, "audit.jsonl")
24
24
  MAX_COMPOSE_BYTES = 1_048_576
25
25
  EXCLUDED_ROOTS = %w[node_modules vendor dist build .git].freeze
@@ -11,7 +11,7 @@ require_relative "control_io"
11
11
  require_relative "phase_ownership"
12
12
 
13
13
  options = {
14
- state: ".planning/STATE.md",
14
+ state: ".devflow/planning/STATE.md",
15
15
  workflow: nil,
16
16
  output: nil,
17
17
  write: false,
@@ -72,10 +72,10 @@ unless ownership["ok"]
72
72
  puts JSON.pretty_generate(ownership.merge("written" => false))
73
73
  exit 0
74
74
  end
75
- workflow_source = options[:workflow] || state["workflow_config"] || ".planning/workflows/#{state.fetch("current_flow")}.yaml"
75
+ workflow_source = options[:workflow] || state["workflow_config"] || ".devflow/planning/workflows/#{state.fetch("current_flow")}.yaml"
76
76
  workflow_path, = DevflowControlIO.resolve_control_path(root, workflow_source, :workflow)
77
77
  workflow = load_yaml_file(workflow_path)
78
- registry_source = options[:output] || workflow.dig("artifact_registry", "source") || ".planning/artifacts/index.yaml"
78
+ registry_source = options[:output] || workflow.dig("artifact_registry", "source") || ".devflow/planning/artifacts/index.yaml"
79
79
  existing_registry_path, registry_path = DevflowControlIO.resolve_control_path(root, registry_source, :registry)
80
80
  existing_by_path = {}
81
81
  if options[:preserve] && File.exist?(existing_registry_path)
@@ -112,7 +112,7 @@ end
112
112
 
113
113
  def questions_registry_entry(root, state, existing_by_path)
114
114
  feature = state.fetch("current_feature", "").to_s
115
- path = ".planning/features/#{feature}/questions.yaml"
115
+ path = ".devflow/planning/features/#{feature}/questions.yaml"
116
116
  absolute, = DevflowControlIO.resolve_control_path(root, path, :artifact)
117
117
  exists = File.exist?(absolute)
118
118
  entry = {
@@ -180,7 +180,7 @@ artifacts = collect_outputs(workflow).map do |step, output|
180
180
  }.reject { |_, value| value.nil? || value == [] }
181
181
  end
182
182
 
183
- questions_path = ".planning/features/#{state.fetch("current_feature", "")}/questions.yaml"
183
+ questions_path = ".devflow/planning/features/#{state.fetch("current_feature", "")}/questions.yaml"
184
184
  questions_entry = questions_registry_entry(root, state, existing_by_path)
185
185
  question_index = artifacts.index { |artifact| artifact["path"] == questions_path }
186
186
  if question_index
@@ -0,0 +1,132 @@
1
+ #!/usr/bin/env python3
2
+ """RFC 8785 JSON Canonicalization Scheme (JCS) and the single tc_sha256 implementation.
3
+
4
+ tc_sha256 = lowercase hex SHA-256 of JCS(node.data). Generators, validators and
5
+ approval pins must call this module; the Runtime only echoes the value back.
6
+ """
7
+ from __future__ import annotations
8
+
9
+ import argparse
10
+ import hashlib
11
+ import json
12
+ import math
13
+ import sys
14
+ from typing import Any
15
+
16
+
17
+ _ESCAPES = {'"': '\\"', "\\": "\\\\", "\b": "\\b", "\f": "\\f", "\n": "\\n", "\r": "\\r", "\t": "\\t"}
18
+
19
+
20
+ def _string(value: str) -> str:
21
+ out = ['"']
22
+ for char in value:
23
+ if char in _ESCAPES:
24
+ out.append(_ESCAPES[char])
25
+ elif ord(char) < 0x20:
26
+ out.append(f"\\u{ord(char):04x}")
27
+ elif 0xD800 <= ord(char) <= 0xDFFF:
28
+ raise ValueError("lone surrogate cannot be canonicalized")
29
+ else:
30
+ out.append(char)
31
+ out.append('"')
32
+ return "".join(out)
33
+
34
+
35
+ def _number(value: int | float) -> str:
36
+ """ECMAScript Number.prototype.toString for an IEEE-754 double (RFC 8785 §3.2.2.3)."""
37
+ if isinstance(value, int):
38
+ converted = float(value)
39
+ if int(converted) != value:
40
+ raise ValueError(f"integer {value} is not exactly representable as an IEEE-754 double")
41
+ value = converted
42
+ if math.isnan(value) or math.isinf(value):
43
+ raise ValueError("NaN and Infinity are not valid JSON numbers")
44
+ if value == 0:
45
+ return "0"
46
+ sign = "-" if value < 0 else ""
47
+ text = repr(abs(value)) # shortest round-trip digits
48
+ mantissa, _, exponent = text.partition("e")
49
+ integer, _, fraction = mantissa.partition(".")
50
+ raw = integer + fraction
51
+ leading = len(raw) - len(raw.lstrip("0"))
52
+ digits = raw.lstrip("0").rstrip("0")
53
+ point = len(integer) + int(exponent or 0) - leading # value = 0.digits * 10**point
54
+ count = len(digits)
55
+ if count <= point <= 21:
56
+ body = digits + "0" * (point - count)
57
+ elif 0 < point <= 21:
58
+ body = digits[:point] + "." + digits[point:]
59
+ elif -6 < point <= 0:
60
+ body = "0." + "0" * (-point) + digits
61
+ else:
62
+ power = point - 1
63
+ suffix = f"e{'+' if power >= 0 else '-'}{abs(power)}"
64
+ body = (digits if count == 1 else digits[0] + "." + digits[1:]) + suffix
65
+ return sign + body
66
+
67
+
68
+ def _utf16_key(key: str) -> list[int]:
69
+ encoded = key.encode("utf-16-be")
70
+ return [int.from_bytes(encoded[index:index + 2], "big") for index in range(0, len(encoded), 2)]
71
+
72
+
73
+ def _serialize(value: Any, out: list[str]) -> None:
74
+ if value is None:
75
+ out.append("null")
76
+ elif value is True:
77
+ out.append("true")
78
+ elif value is False:
79
+ out.append("false")
80
+ elif isinstance(value, (int, float)):
81
+ out.append(_number(value))
82
+ elif isinstance(value, str):
83
+ out.append(_string(value))
84
+ elif isinstance(value, (list, tuple)):
85
+ out.append("[")
86
+ for index, item in enumerate(value):
87
+ if index:
88
+ out.append(",")
89
+ _serialize(item, out)
90
+ out.append("]")
91
+ elif isinstance(value, dict):
92
+ if not all(isinstance(key, str) for key in value):
93
+ raise ValueError("object keys must be strings")
94
+ out.append("{")
95
+ for index, key in enumerate(sorted(value, key=_utf16_key)):
96
+ if index:
97
+ out.append(",")
98
+ out.append(_string(key))
99
+ out.append(":")
100
+ _serialize(value[key], out)
101
+ out.append("}")
102
+ else:
103
+ raise ValueError(f"unsupported JSON value type: {type(value).__name__}")
104
+
105
+
106
+ def canonicalize(value: Any) -> bytes:
107
+ out: list[str] = []
108
+ _serialize(value, out)
109
+ return "".join(out).encode("utf-8")
110
+
111
+
112
+ def jcs_sha256(value: Any) -> str:
113
+ return hashlib.sha256(canonicalize(value)).hexdigest()
114
+
115
+
116
+ def tc_sha256(data: Any) -> str:
117
+ if not isinstance(data, dict):
118
+ raise ValueError("TC data must be an object")
119
+ return jcs_sha256(data)
120
+
121
+
122
+ def main() -> int:
123
+ parser = argparse.ArgumentParser(description="Print tc_sha256 (JCS SHA-256) of a JSON document read from a file or stdin.")
124
+ parser.add_argument("path", nargs="?")
125
+ args = parser.parse_args()
126
+ text = open(args.path, encoding="utf-8").read() if args.path else sys.stdin.read()
127
+ print(jcs_sha256(json.loads(text)))
128
+ return 0
129
+
130
+
131
+ if __name__ == "__main__":
132
+ raise SystemExit(main())
@@ -92,7 +92,7 @@ def task_binding(root: Path, feature: str, task_id: str) -> tuple[dict[str, Any]
92
92
  validation = validate_bindings(root, feature)
93
93
  if not validation.get("ok"):
94
94
  return None, [str(item) for item in validation.get("errors", ["invalid test bindings"])]
95
- bindings = read_json(root / ".planning" / "features" / feature / "test-bindings.json")
95
+ bindings = read_json(root / ".devflow/planning" / "features" / feature / "test-bindings.json")
96
96
  if bindings is None:
97
97
  return None, ["missing test bindings"]
98
98
  matches = [item for item in bindings.get("tasks", []) if isinstance(item, dict) and item.get("id") == task_id]
@@ -105,7 +105,7 @@ def task_binding(root: Path, feature: str, task_id: str) -> tuple[dict[str, Any]
105
105
 
106
106
 
107
107
  def evidence_path(root: Path, feature: str, task_id: str) -> Path:
108
- return root / ".planning" / "test-runs" / feature / "tdd" / f"{task_id}.json"
108
+ return root / ".devflow/planning" / "test-runs" / feature / "tdd" / f"{task_id}.json"
109
109
 
110
110
 
111
111
  def command_hash(argv: list[str]) -> str:
@@ -233,7 +233,7 @@ def validate_feature(root: Path, feature: str) -> dict[str, Any]:
233
233
  errors = [str(item) for item in binding_result.get("errors", [])]
234
234
  if errors:
235
235
  return response(False, feature=feature, errors=errors)
236
- bindings = read_json(root / ".planning" / "features" / feature / "test-bindings.json")
236
+ bindings = read_json(root / ".devflow/planning" / "features" / feature / "test-bindings.json")
237
237
  assert bindings is not None
238
238
  checked: list[str] = []
239
239
  for task in bindings.get("tasks", []):
@@ -6,18 +6,25 @@ from pathlib import Path
6
6
  from typing import Any
7
7
  import json
8
8
  import os
9
+ import re
9
10
  import sqlite3
10
11
 
12
+ from approval_store import devflow_home
11
13
 
12
- def database_toolchain(root: Path) -> list[str] | None:
14
+
15
+ PACKAGE_RUNNERS = {"npm", "pnpm", "yarn"}
16
+ RUNTIME_MARKERS = ("devflow-quality/runtime/playwright", "runtime-manifest.json", "runner.spec.mjs", "devflow-test-dsl-v1.schema.json")
17
+ MARKDOWN_ROW_RE = re.compile(r"^\|(.+)\|\s*$")
18
+
19
+
20
+ def database_toolchain_facts(root: Path) -> list[dict[str, Any]] | None:
13
21
  manifest_path = root / ".devflow" / "project.json"
14
22
  if not manifest_path.is_file():
15
23
  return None
16
24
  try:
17
25
  project_id = json.loads(manifest_path.read_text(encoding="utf-8"))["projectId"]
18
- data_home = Path(os.environ.get("DEVFLOW_HOME", Path.home() / ".devflow-pi"))
19
- database = data_home / "projects" / project_id / "control.db"
20
- connection = sqlite3.connect(f"file:{database}?mode=ro", uri=True)
26
+ database = devflow_home() / "projects" / project_id / "control.db"
27
+ connection = sqlite3.connect(f"{database.as_uri()}?mode=ro", uri=True)
21
28
  connection.row_factory = sqlite3.Row
22
29
  try:
23
30
  authority = connection.execute("SELECT authority FROM authority_state WHERE project_id=?", (project_id,)).fetchone()
@@ -32,13 +39,87 @@ def database_toolchain(root: Path) -> list[str] | None:
32
39
  ORDER BY c.revision DESC""",
33
40
  (project_id, str(root.resolve())),
34
41
  ).fetchall()
35
- return [str(json.loads(row["value_json"]).get("command", "")) for row in rows]
42
+ facts = [json.loads(row["value_json"]) for row in rows]
43
+ return [fact for fact in facts if isinstance(fact, dict)]
36
44
  finally:
37
45
  connection.close()
38
46
  except (OSError, KeyError, ValueError, json.JSONDecodeError, sqlite3.Error):
39
47
  return None
40
48
 
41
49
 
50
+ def database_toolchain(root: Path) -> list[str] | None:
51
+ facts = database_toolchain_facts(root)
52
+ return None if facts is None else [str(fact.get("command", "")) for fact in facts]
53
+
54
+
55
+ def _root_directory(value: Any) -> bool:
56
+ return value in (None, "", ".", "./")
57
+
58
+
59
+ def registered_scripts(root: Path, facts: list[dict[str, Any]] | None) -> tuple[set[str], str]:
60
+ """Package script names Core may run from the project root, and their source.
61
+
62
+ Toolchain facts (package-json@1) carry {name, command, workingDirectory};
63
+ the compatibility toolchain.md projects them as a 名称/工作目录 table. A
64
+ legacy free-form toolchain.md has no script names, so only then fall back
65
+ to the root package.json scripts.
66
+ """
67
+ if facts is not None:
68
+ return {str(fact["name"]) for fact in facts if isinstance(fact.get("name"), str) and "command" in fact and _root_directory(fact.get("workingDirectory"))}, "toolchain facts"
69
+ names: set[str] = set()
70
+ toolchain = root / ".devflow/planning" / "toolchain.md"
71
+ header: list[str] | None = None
72
+ if toolchain.is_file():
73
+ for line in toolchain.read_text(encoding="utf-8").splitlines():
74
+ match = MARKDOWN_ROW_RE.match(line.strip())
75
+ if not match:
76
+ header = None
77
+ continue
78
+ cells = [cell.strip() for cell in match.group(1).split("|")]
79
+ if header is None:
80
+ header = cells
81
+ elif "名称" in header and "命令" in header and not set("".join(cells)) <= set("-: "):
82
+ row = dict(zip(header, cells))
83
+ if row.get("名称") not in (None, "", "undefined") and row.get("命令") not in (None, "", "undefined") and _root_directory(row.get("工作目录")):
84
+ names.add(row["名称"])
85
+ if names:
86
+ return names, "toolchain.md"
87
+ try:
88
+ scripts = json.loads((root / "package.json").read_text(encoding="utf-8")).get("scripts", {})
89
+ return ({name for name in scripts if isinstance(name, str)} if isinstance(scripts, dict) else set()), "package.json"
90
+ except (OSError, ValueError, AttributeError):
91
+ return set(), "package.json"
92
+
93
+
94
+ def package_script(argv: list[str]) -> tuple[str | None, str | None]:
95
+ """Return (script name, error) for npm/pnpm/yarn test|run argv."""
96
+ if argv[1] == "test":
97
+ rest, name = argv[2:], "test"
98
+ else:
99
+ if len(argv) < 3 or argv[2].startswith("-"):
100
+ return None, f"{Path(argv[0]).name} run must name a script immediately after 'run' (options before the script name are rejected)"
101
+ rest, name = argv[3:], argv[2]
102
+ if rest and rest[0] != "--":
103
+ return None, f"{Path(argv[0]).name} {argv[1]} extra arguments must follow '--'"
104
+ return name, None
105
+
106
+
107
+ def reserved_reference(root: Path, argv: list[str]) -> str | None:
108
+ runtime_dirs: list[str] = []
109
+ try:
110
+ from dsl_v1 import runtime_dir_candidates
111
+ runtime_dirs = [str(path) for path in runtime_dir_candidates()]
112
+ except ImportError:
113
+ pass
114
+ for token in argv:
115
+ if "DEVFLOW_" in token:
116
+ return "test command must not reference DEVFLOW_ reserved variables"
117
+ normalized = token.replace("\\", "/")
118
+ if any(marker in normalized for marker in RUNTIME_MARKERS) or any(directory and directory in token for directory in runtime_dirs):
119
+ return "test command must not reference the Devflow Playwright Runtime; use the devflow_playwright adapter"
120
+ return None
121
+
122
+
42
123
  def runner_marker(argv: list[str]) -> str | None:
43
124
  if not argv:
44
125
  return None
@@ -73,18 +154,31 @@ def runner_marker(argv: list[str]) -> str | None:
73
154
  def validate_test_command(root: Path, argv: Any) -> str | None:
74
155
  if not isinstance(argv, list) or not argv or not all(isinstance(token, str) and token and "\x00" not in token for token in argv):
75
156
  return "test command must be a non-empty argv array"
157
+ reserved = reserved_reference(root, argv)
158
+ if reserved:
159
+ return reserved
76
160
  marker = runner_marker(argv)
77
161
  if marker is None:
162
+ if Path(argv[0]).name in PACKAGE_RUNNERS and len(argv) >= 2 and argv[1].startswith("-"):
163
+ return f"{Path(argv[0]).name} global options before the command are rejected (they can switch to another package)"
78
164
  return "test command runner is not in the Core allowlist"
79
- commands = database_toolchain(root)
80
- if commands is None:
81
- toolchain = root / ".planning" / "toolchain.md"
165
+ facts = database_toolchain_facts(root)
166
+ if facts is None:
167
+ toolchain = root / ".devflow/planning" / "toolchain.md"
82
168
  if not toolchain.is_file():
83
- return "initialized toolchain context (database or .planning/toolchain.md compatibility projection) is required before Core can execute a test command"
169
+ return "initialized toolchain context (database or .devflow/planning/toolchain.md compatibility projection) is required before Core can execute a test command"
84
170
  content = toolchain.read_text(encoding="utf-8").lower()
85
171
  else:
86
- content = "\n".join(commands).lower()
172
+ content = "\n".join(str(fact.get("command", "")) for fact in facts).lower()
87
173
  aliases = {"pytest": ("pytest",), "unittest": ("unittest",), "bun test": ("bun test",), "npm": ("npm",), "pnpm": ("pnpm",), "yarn": ("yarn",), "go test": ("go test",), "newman": ("newman",), "playwright": ("playwright",), "vitest": ("vitest",)}
174
+ if marker in PACKAGE_RUNNERS:
175
+ script, error = package_script(argv)
176
+ if error:
177
+ return error
178
+ names, source = registered_scripts(root, facts)
179
+ if script not in names:
180
+ return f"package script '{script}' is not registered in the initialization toolchain ({source})"
181
+ return None
88
182
  if not any(alias in content for alias in aliases[marker]):
89
183
  return f"test runner '{marker}' was not discovered in the initialization toolchain snapshot"
90
184
  return None
@@ -74,7 +74,7 @@ def view_pin(suite: dict[str, Any]) -> dict[str, Any]:
74
74
 
75
75
 
76
76
  def freeze_attestation_path(root: Path, feature: str) -> Path:
77
- return root / ".planning" / "features" / feature / "test-suite-freeze.json"
77
+ return root / ".devflow/planning" / "features" / feature / "test-suite-freeze.json"
78
78
 
79
79
 
80
80
  def validated_attestation(
@@ -108,8 +108,8 @@ def validated_attestation(
108
108
 
109
109
  def validate(root: Path, feature: str, stage: str = "frozen") -> dict[str, Any]:
110
110
  errors: list[str] = []
111
- suite_path = root / ".planning" / "requirements" / feature / "tests.json"
112
- binding_path = root / ".planning" / "features" / feature / "test-bindings.json"
111
+ suite_path = root / ".devflow/planning" / "requirements" / feature / "tests.json"
112
+ binding_path = root / ".devflow/planning" / "features" / feature / "test-bindings.json"
113
113
  suite = read_json(suite_path, errors, "TC suite")
114
114
  bindings = read_json(binding_path, errors, "test bindings")
115
115
  if suite is None or bindings is None:
@@ -33,7 +33,7 @@ options = {
33
33
  route: nil,
34
34
  reason: nil,
35
35
  blocking_question: nil,
36
- state: ".planning/STATE.md",
36
+ state: ".devflow/planning/STATE.md",
37
37
  write: false,
38
38
  json: false
39
39
  }
@@ -76,7 +76,7 @@ result = if !ROUTE_NEXT_SKILL.key?(options[:route].to_s)
76
76
  if feature.to_s.empty?
77
77
  fail_result("missing_feature", "message" => "Pass --feature or provide current_feature in STATE.md")
78
78
  else
79
- meta_path = File.join(root, ".planning", "requirements", feature, "入口分诊.meta.json")
79
+ meta_path = File.join(root, ".devflow/planning", "requirements", feature, "入口分诊.meta.json")
80
80
  meta = File.exist?(meta_path) ? JSON.parse(File.read(meta_path)) : { "feature_name" => feature }
81
81
  route = options[:route]
82
82
 
@@ -101,7 +101,7 @@ result = if !ROUTE_NEXT_SKILL.key?(options[:route].to_s)
101
101
  {
102
102
  "ok" => true,
103
103
  "written" => options[:write],
104
- "path" => ".planning/requirements/#{feature}/入口分诊.meta.json",
104
+ "path" => ".devflow/planning/requirements/#{feature}/入口分诊.meta.json",
105
105
  "meta" => meta
106
106
  }
107
107
  end