@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
@@ -5,11 +5,11 @@
5
5
  - **来源类型**:{{PRD / 会议纪要 / 用户描述 / 其他}}
6
6
  - **来源文件/说明**:{{来源}}
7
7
  - **生成时间**:{{日期}}
8
- - **项目上下文**:`.planning/PROJECT.md`
9
- - **项目导航**:`.planning/navigation/INDEX.md`
8
+ - **项目上下文**:`.devflow/planning/PROJECT.md`
9
+ - **项目导航**:`.devflow/planning/navigation/INDEX.md`
10
10
  - **功能名称**:{{功能名称}}
11
- - **功能目录名**:{{功能名,用于 .planning/features/{功能名}/}}
12
- - **下游输出目录**:`.planning/features/{{功能名}}/`
11
+ - **功能目录名**:{{功能名,用于 .devflow/planning/features/{功能名}/}}
12
+ - **下游输出目录**:`.devflow/planning/features/{{功能名}}/`
13
13
 
14
14
  ## 二、需求整理摘要
15
15
 
@@ -138,11 +138,11 @@
138
138
 
139
139
  | 来源类型 | 路径/范围 | 结论 |
140
140
  |----------|-----------|------|
141
- | 里程碑 | `.planning/milestones/...` | {{相关/无相关/不存在/未扫描原因}} |
142
- | 历史需求基线 | `.planning/requirements/...` | {{相关/无相关/不存在/未扫描原因}} |
143
- | 经验教训 | `.planning/lessons/...` | {{相关/无相关/不存在/未扫描原因}} |
144
- | 阶段上下文 | `.planning/*/CONTEXT.md` | {{相关/无相关/不存在/未扫描原因}} |
145
- | Legacy/项目规则历史 | `features/` / `.context/lessons/` / `.context/workflow/` | {{如存在则记录;不存在则写“不适用”}} |
141
+ | 里程碑 | `.devflow/planning/milestones/...` | {{相关/无相关/不存在/未扫描原因}} |
142
+ | 历史需求基线 | `.devflow/planning/requirements/...` | {{相关/无相关/不存在/未扫描原因}} |
143
+ | 经验教训 | `.devflow/planning/lessons/...` | {{相关/无相关/不存在/未扫描原因}} |
144
+ | 阶段上下文 | `.devflow/planning/*/CONTEXT.md` | {{相关/无相关/不存在/未扫描原因}} |
145
+ | Legacy/项目规则历史 | `features/` / `.devflow/context/lessons/` / `.devflow/context/workflow/` | {{如存在则记录;不存在则写“不适用”}} |
146
146
 
147
147
  ### 9.2 关联历史功能/里程碑
148
148
 
@@ -169,7 +169,7 @@
169
169
  统一使用以下功能目录,后续 skill 不得重新生成不同目录名:
170
170
 
171
171
  - **功能名**:{{功能名}}
172
- - **输出目录**:`.planning/features/{{功能名}}/`
172
+ - **输出目录**:`.devflow/planning/features/{{功能名}}/`
173
173
  - **当前功能切片**:读取本文档“当前功能切片”中的当前 FP/BR/BC。
174
174
  - **当前执行切片**:读取本文档“3.0a 当前执行切片范围”。非当前切片只能作为依赖上下文,不得生成实现任务。
175
175
  - **跨功能依赖**:读取 `depends_on` 引用的历史 FP/BR/BC 详情,不得只读当前 FP 而忽略依赖项。
@@ -178,37 +178,37 @@
178
178
 
179
179
  - 读取本文档的当前功能切片、`depends_on` 引用详情、功能点详情、业务规则、边界场景。
180
180
  - 输出必须带当前 `Slice ID`,且只展开当前执行切片。
181
- - 输出 `.planning/features/{{功能名}}/功能点梳理.md`。
181
+ - 输出 `.devflow/planning/features/{{功能名}}/功能点梳理.md`。
182
182
 
183
183
  ### 11.1a 给测试指导书
184
184
 
185
- - 读取 `.planning/features/{{功能名}}/功能点梳理.md`(主要输入)和本文档的 FP/BR/BC/CR 关联。
186
- - 同时读取 `.planning/PROJECT.md`。
185
+ - 读取 `.devflow/planning/features/{{功能名}}/功能点梳理.md`(主要输入)和本文档的 FP/BR/BC/CR 关联。
186
+ - 同时读取 `.devflow/planning/PROJECT.md`。
187
187
  - 此步骤为可选,不阻塞下游门禁。
188
- - 输出 `.planning/features/{{功能名}}/测试指导书.md`。
188
+ - 输出 `.devflow/planning/features/{{功能名}}/测试指导书.md`。
189
189
 
190
190
  ### 11.2 给前端技术方案
191
191
 
192
- - 读取 `.planning/features/{{功能名}}/功能点梳理.md` 中的页面/组件/字段/交互拆解。
192
+ - 读取 `.devflow/planning/features/{{功能名}}/功能点梳理.md` 中的页面/组件/字段/交互拆解。
193
193
  - 只为当前执行切片生成前端方案;后置切片只列为依赖或后续范围。
194
194
  - 读取本文档的当前功能切片、跨功能依赖、涉及页面/模块、入口/触发、主流程、边界场景、数据要求。
195
- - 同时读取 `.planning/navigation/INDEX.md` → 筛选前端类型代码库 → 加载对应 navigation 文件。
196
- - 输出 `.planning/features/{{功能名}}/前端技术方案.md`。
195
+ - 同时读取 `.devflow/planning/navigation/INDEX.md` → 筛选前端类型代码库 → 加载对应 navigation 文件。
196
+ - 输出 `.devflow/planning/features/{{功能名}}/前端技术方案.md`。
197
197
 
198
198
  ### 11.3 给后端技术方案
199
199
 
200
- - 读取 `.planning/features/{{功能名}}/功能点梳理.md` 中的 API/服务节点和逻辑维度。
200
+ - 读取 `.devflow/planning/features/{{功能名}}/功能点梳理.md` 中的 API/服务节点和逻辑维度。
201
201
  - 只为当前执行切片生成后端方案;共享能力若服务于后置切片,必须有当前切片可验证门禁。
202
202
  - 读取本文档的当前功能切片、跨功能依赖、业务规则、数据要求、与历史功能/里程碑的关联、兼容性要求、边界场景、代码现实对照。
203
- - 同时读取 `.planning/navigation/INDEX.md` → 筛选后端/服务类型代码库 → 加载对应 navigation 文件。
204
- - 输出 `.planning/features/{{功能名}}/后端技术方案.md`。
203
+ - 同时读取 `.devflow/planning/navigation/INDEX.md` → 筛选后端/服务类型代码库 → 加载对应 navigation 文件。
204
+ - 输出 `.devflow/planning/features/{{功能名}}/后端技术方案.md`。
205
205
 
206
206
  ### 11.4 给变更清单
207
207
 
208
208
  - 读取本文档的功能点、业务规则、边界场景、反向审视与用户拍板。
209
- - 同时读取 `.planning/features/{{功能名}}/前端技术方案.md` 和 `.planning/features/{{功能名}}/后端技术方案.md`。
209
+ - 同时读取 `.devflow/planning/features/{{功能名}}/前端技术方案.md` 和 `.devflow/planning/features/{{功能名}}/后端技术方案.md`。
210
210
  - 变更任务必须标注 `Slice ID`;不得生成后置切片的实现任务。
211
- - 输出 `.planning/features/{{功能名}}/变更清单.md`。
211
+ - 输出 `.devflow/planning/features/{{功能名}}/变更清单.md`。
212
212
 
213
213
  ### 11.5 给测试验收
214
214
 
@@ -35,13 +35,13 @@ Required:
35
35
  Wrong:
36
36
 
37
37
  - Assuming the project keeps outbound-call style `features/*.spec.md` history.
38
- - Treating `.context/lessons/README.md` as the only source of historical product or requirement decisions.
38
+ - Treating `.devflow/context/lessons/README.md` as the only source of historical product or requirement decisions.
39
39
  - Ignoring milestone artifacts because their filenames differ from spec documents.
40
40
 
41
41
  Required:
42
42
 
43
- - Use this workflow's primary history model first: `.planning/milestones/`, `.planning/requirements/`, `.planning/lessons/`, and `.planning/*/CONTEXT.md`.
44
- - Treat `features/`, `.context/lessons/`, and `.context/workflow/` as optional legacy or project-rule evidence when present.
43
+ - Use this workflow's primary history model first: `.devflow/planning/milestones/`, `.devflow/planning/requirements/`, `.devflow/planning/lessons/`, and `.devflow/planning/*/CONTEXT.md`.
44
+ - Treat `features/`, `.devflow/context/lessons/`, and `.devflow/context/workflow/` as optional legacy or project-rule evidence when present.
45
45
  - Record exactly which history sources were checked.
46
46
 
47
47
  ## Implementation Leakage
@@ -25,7 +25,7 @@ Do not:
25
25
 
26
26
  ## Entry Triage Carry-Forward
27
27
 
28
- If `.planning/requirements/{功能名}/入口分诊.md` exists, start challenge review from its findings:
28
+ If `.devflow/planning/requirements/{功能名}/入口分诊.md` exists, start challenge review from its findings:
29
29
 
30
30
  - Duplicate or already-done evidence feeds C1 and C2.
31
31
  - Prior rejection / out-of-scope evidence feeds C3 and may block baseline until the user explicitly reverses it.
@@ -96,8 +96,8 @@ Do not silently choose. The user must decide when the choice changes scope, sema
96
96
 
97
97
  Search available history before claiming there is no precedent:
98
98
 
99
- - Primary workflow history: `.planning/milestones/`, `.planning/requirements/`, `.planning/lessons/`, and `.planning/*/CONTEXT.md`.
100
- - Optional legacy/project-rule history when present: `features/`, `.context/lessons/README.md`, `.context/workflow/`, root `AGENTS.md`, and root `CLAUDE.md`.
99
+ - Primary workflow history: `.devflow/planning/milestones/`, `.devflow/planning/requirements/`, `.devflow/planning/lessons/`, and `.devflow/planning/*/CONTEXT.md`.
100
+ - Optional legacy/project-rule history when present: `features/`, `.devflow/context/lessons/README.md`, `.devflow/context/workflow/`, root `AGENTS.md`, and root `CLAUDE.md`.
101
101
 
102
102
  Do not assume outbound-call style `features/*.spec.md` exists. This workflow's normal long-term memory is milestone/planning based.
103
103
 
@@ -2,20 +2,20 @@
2
2
 
3
3
  ## 加载顺序
4
4
 
5
- 1. `.planning/PROJECT.md` — 项目上下文和已上线能力
6
- 2. `.planning/navigation/INDEX.md` — 代码库注册表(Codebase Registry),从中识别与需求相关的代码库
7
- 3. `.planning/navigation/{name}.md` — 加载 INDEX.md 中标识的相关代码库的导航文件
8
- 4. `.planning/milestones/` — 归档的里程碑记录,是本工作流的主要历史口径
9
- 5. `.planning/requirements/` — 已确认或历史需求基线
10
- 6. `.planning/lessons/` — 跨里程碑经验教训
11
- 7. `.planning/*/CONTEXT.md` — 之前阶段的决策记录
12
- 8. `features/`、`.context/lessons/`、`.context/workflow/` — 仅当目标项目存在时作为兼容历史或项目规则来源,不作为默认历史口径
5
+ 1. `.devflow/planning/PROJECT.md` — 项目上下文和已上线能力
6
+ 2. `.devflow/planning/navigation/INDEX.md` — 代码库注册表(Codebase Registry),从中识别与需求相关的代码库
7
+ 3. `.devflow/planning/navigation/{name}.md` — 加载 INDEX.md 中标识的相关代码库的导航文件
8
+ 4. `.devflow/planning/milestones/` — 归档的里程碑记录,是本工作流的主要历史口径
9
+ 5. `.devflow/planning/requirements/` — 已确认或历史需求基线
10
+ 6. `.devflow/planning/lessons/` — 跨里程碑经验教训
11
+ 7. `.devflow/planning/*/CONTEXT.md` — 之前阶段的决策记录
12
+ 8. `features/`、`.devflow/context/lessons/`、`.devflow/context/workflow/` — 仅当目标项目存在时作为兼容历史或项目规则来源,不作为默认历史口径
13
13
 
14
14
  ## 对比分析要点
15
15
 
16
16
  ### 入口分诊证据复用
17
17
 
18
- - 如果 `.planning/requirements/{功能名}/入口分诊.md` 存在,先读取其中的"已实现/重叠检查"和"历史拒绝/范围检查"。
18
+ - 如果 `.devflow/planning/requirements/{功能名}/入口分诊.md` 存在,先读取其中的"已实现/重叠检查"和"历史拒绝/范围检查"。
19
19
  - 分诊结果只能作为 Phase 4/4.5 的优先证据入口,不能替代源码比差。
20
20
  - 当分诊结论为 `already_done`、`wontfix` 或 `ready_for_human` 时,baseline 不应继续生成通过状态,除非用户明确改变范围或推翻历史决策。
21
21
  - 分诊已搜索的来源必须并入 baseline 的搜索来源记录,避免重复声明"未发现历史"。
@@ -39,8 +39,8 @@
39
39
 
40
40
  ### 历史口径映射
41
41
 
42
- - outbound-call 中的 `features/*.spec.md` 对应本工作流里的 `.planning/milestones/`、`.planning/requirements/baseline.md` 和阶段 `CONTEXT.md`。
43
- - outbound-call 中的 `.context/lessons/README.md` 对应本工作流里的 `.planning/lessons/README.md`;如果目标项目同时存在 `.context/lessons/`,将其标为项目规则/遗留经验来源。
42
+ - outbound-call 中的 `features/*.spec.md` 对应本工作流里的 `.devflow/planning/milestones/`、`.devflow/planning/requirements/baseline.md` 和阶段 `CONTEXT.md`。
43
+ - outbound-call 中的 `.devflow/context/lessons/README.md` 对应本工作流里的 `.devflow/planning/lessons/README.md`;如果目标项目同时存在 `.devflow/context/lessons/`,将其标为项目规则/遗留经验来源。
44
44
  - 输出时必须写清楚实际搜索了哪些目录或文件,不能只写"未发现历史"。
45
45
 
46
46
  ## 三级递进审查
@@ -16,7 +16,7 @@
16
16
  4. 已形成代码路由摘要:可能相关模块、候选源码路径、映射到这些路径的需求词、需要 Phase 4 深查的问题
17
17
  5. 已将问题绑定到来源、现有模块、候选 FP/BR/BC/CR,或图片阻塞点
18
18
 
19
- 如果只读了 `.planning/navigation/*.md` 或只做了 Phase 1.5 轻量路由扫描,不得声称“当前系统已支持/不支持某能力”。只能说“可能相关”,并在 Phase 4 Level 2 下钻源码后再产出行为结论。
19
+ 如果只读了 `.devflow/planning/navigation/*.md` 或只做了 Phase 1.5 轻量路由扫描,不得声称“当前系统已支持/不支持某能力”。只能说“可能相关”,并在 Phase 4 Level 2 下钻源码后再产出行为结论。
20
20
 
21
21
  在 Phase 2 之前,只允许问会阻塞需求理解的输入澄清问题,例如 `critical_image` 无法识别、核心业务目标缺失、需求明显指向多个现有模块但无法判断边界。
22
22
 
@@ -54,7 +54,7 @@ Use this checklist after feature point decomposition and before writing the base
54
54
  - [ ] 每个涉及已有代码的 FP,已从导航 Call Chain Map 提取受影响的文件清单:
55
55
  - 前端:受影响的路由、页面组件、composable、API 模块
56
56
  - 后端:受影响的 handler、service、repository、DAO
57
- - [ ] 如果 `.planning/code-index/` 存在,已通过 `code-index-query` 查询需求关键词、API 路径、页面名、字段名、状态名、表/配置/资源名,并记录使用到的 symbol/relation id
57
+ - [ ] 如果 `.devflow/planning/code-index/` 存在,已通过 `code-index-query` 查询需求关键词、API 路径、页面名、字段名、状态名、表/配置/资源名,并记录使用到的 symbol/relation id
58
58
  - [ ] 调用链重叠类型已判断:扩展已有调用链 vs 新建独立调用链
59
59
  - [ ] 契约影响已预判:修改已有接口/参数时,已检查 Call Chain Map 中的其他调用方
60
60
  - [ ] 受影响的调用链文件、路由、API 路径已写回 FP 的"关联已有模块"
@@ -88,8 +88,8 @@ Level 2 发现"已存在且一致"或"已存在但冲突"时启动。
88
88
  - Historical feature overlap is classified as new, modify, replace, or affect.
89
89
  - Compatibility requirements are recorded.
90
90
  - Reuse opportunities are checked across business capability, installed library, and project pattern layers.
91
- - Historical lessons or prior work are searched using the workflow history model first: `.planning/milestones/`, `.planning/requirements/`, `.planning/lessons/`, and `.planning/*/CONTEXT.md`.
92
- - Legacy history such as `features/` or `.context/lessons/` is used only when present and is labeled as legacy/project-rule evidence.
91
+ - Historical lessons or prior work are searched using the workflow history model first: `.devflow/planning/milestones/`, `.devflow/planning/requirements/`, `.devflow/planning/lessons/`, and `.devflow/planning/*/CONTEXT.md`.
92
+ - Legacy history such as `features/` or `.devflow/context/lessons/` is used only when present and is labeled as legacy/project-rule evidence.
93
93
  - The searched sources are recorded before claiming no related history.
94
94
 
95
95
  ### Challenge Review
@@ -103,7 +103,7 @@ Level 2 发现"已存在且一致"或"已存在但冲突"时启动。
103
103
 
104
104
  ### Downstream Readiness
105
105
 
106
- - One canonical feature name and `.planning/features/{功能名}/` output directory are defined.
106
+ - One canonical feature name and `.devflow/planning/features/{功能名}/` output directory are defined.
107
107
  - Current feature slice and `depends_on` are sufficient for downstream skills to load current scope plus required historical context.
108
108
  - Frontend has enough information to identify pages, interactions, states, and API dependencies.
109
109
  - Backend has enough information to identify data, services, interfaces, rules, and risks.
@@ -11,8 +11,8 @@ description: "Use as the lightweight first step for a new request, bug report, P
11
11
 
12
12
  Always create or update:
13
13
 
14
- - `.planning/requirements/{功能名}/入口分诊.md`
15
- - `.planning/requirements/{功能名}/入口分诊.meta.json`
14
+ - `.devflow/planning/requirements/{功能名}/入口分诊.md`
15
+ - `.devflow/planning/requirements/{功能名}/入口分诊.meta.json`
16
16
 
17
17
  `入口分诊.meta.json` minimum fields:
18
18
 
@@ -89,13 +89,13 @@ Search by domain concept, not just exact words.
89
89
 
90
90
  Required sources:
91
91
 
92
- 1. `.planning/requirements/baseline.md`
93
- 2. `.planning/features/`
94
- 3. `.planning/milestones/`
95
- 4. `.planning/lessons/`
96
- 5. `.planning/*/CONTEXT.md`
97
- 6. `.planning/navigation/INDEX.md` and relevant navigation files
98
- 7. `code-index-query` against `.planning/code-index/` when present, for shallow symbol/entrypoint/resource candidate lookup
92
+ 1. `.devflow/planning/requirements/baseline.md`
93
+ 2. `.devflow/planning/features/`
94
+ 3. `.devflow/planning/milestones/`
95
+ 4. `.devflow/planning/lessons/`
96
+ 5. `.devflow/planning/*/CONTEXT.md`
97
+ 6. `.devflow/planning/navigation/INDEX.md` and relevant navigation files
98
+ 7. `code-index-query` against `.devflow/planning/code-index/` when present, for shallow symbol/entrypoint/resource candidate lookup
99
99
  8. Actual source files only enough to confirm whether a likely capability exists
100
100
 
101
101
  Search strategy:
@@ -128,13 +128,13 @@ Search for prior decisions that intentionally avoided this request.
128
128
 
129
129
  Required sources:
130
130
 
131
- - `.planning/requirements/baseline.md`
132
- - `.planning/features/**/需求梳理.md`
133
- - `.planning/features/**/需求澄清记录.md`
134
- - `.planning/features/**/PROGRESS.md`
135
- - `.planning/milestones/`
136
- - `.planning/lessons/`
137
- - `.planning/*/CONTEXT.md`
131
+ - `.devflow/planning/requirements/baseline.md`
132
+ - `.devflow/planning/features/**/需求梳理.md`
133
+ - `.devflow/planning/features/**/需求澄清记录.md`
134
+ - `.devflow/planning/features/**/PROGRESS.md`
135
+ - `.devflow/planning/milestones/`
136
+ - `.devflow/planning/lessons/`
137
+ - `.devflow/planning/*/CONTEXT.md`
138
138
  - `.out-of-scope/` if present
139
139
 
140
140
  Treat these as prior rejection signals:
@@ -11,11 +11,11 @@ description: "Use when a requirement is too large or foggy for one clarification
11
11
 
12
12
  Always create or update:
13
13
 
14
- - `.planning/requirements/{功能名}/决策地图.md`
15
- - `.planning/requirements/{功能名}/决策地图.meta.json`
16
- - `.planning/requirements/{功能名}/source_units.yaml` (Core-generated)
17
- - `.planning/requirements/{功能名}/coverage.yaml`
18
- - `.planning/requirements/{功能名}/wayfinder/WF-xxx.md` for each ticket
14
+ - `.devflow/planning/requirements/{功能名}/决策地图.md`
15
+ - `.devflow/planning/requirements/{功能名}/决策地图.meta.json`
16
+ - `.devflow/planning/requirements/{功能名}/source_units.yaml` (Core-generated)
17
+ - `.devflow/planning/requirements/{功能名}/coverage.yaml`
18
+ - `.devflow/planning/requirements/{功能名}/wayfinder/WF-xxx.md` for each ticket
19
19
 
20
20
  `决策地图.meta.json` minimum fields:
21
21
 
@@ -75,7 +75,7 @@ Do not merge `Grilling` and `Task`: a question to the user and a local artifact
75
75
 
76
76
  ## Phase 1 — Chart The First Map
77
77
 
78
- 1. Read `.planning/requirements/{功能名}/入口分诊.md`.
78
+ 1. Read `.devflow/planning/requirements/{功能名}/入口分诊.md`.
79
79
  2. Read the raw user input and only the project context needed to understand the uncertainty.
80
80
  3. Run the **Source Coherence Gate** below before declaring Fog or creating any Grilling ticket.
81
81
  4. Write:
@@ -0,0 +1,340 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import type { Database } from "bun:sqlite";
3
+
4
+ /**
5
+ * Core human-approval primitive (control.db, schema v3).
6
+ *
7
+ * `proposeApproval` may be reached from an agent tool. `confirmApproval` must
8
+ * only be called from the runtime extension's interactive UI callback: there
9
+ * is deliberately no CLI or agent-tool entry point for it.
10
+ */
11
+
12
+ export const APPROVAL_KINDS = ["execution_plan", "environment_profile", "mode_override", "human_result"] as const;
13
+ export type ApprovalKind = typeof APPROVAL_KINDS[number];
14
+ export const HUMAN_RESULT_STATUSES = ["passed", "failed", "blocked"] as const;
15
+ export type HumanResultStatus = typeof HUMAN_RESULT_STATUSES[number];
16
+ export type ProposalStatus = "proposed" | "consumed" | "rejected" | "expired";
17
+
18
+ /** An unconfirmed proposal older than this can no longer be confirmed. */
19
+ export const PROPOSAL_TTL_MS = 24 * 60 * 60 * 1000;
20
+ export const APPROVED_VIA = "runtime_ui_confirm";
21
+
22
+ export type ApprovalErrorCode =
23
+ | "approval_requires_database_authority"
24
+ | "invalid_proposal"
25
+ | "invalid_decision"
26
+ | "proposal_not_found"
27
+ | "proposal_not_pending"
28
+ | "proposal_expired"
29
+ | "pins_unavailable"
30
+ | "pins_mismatch"
31
+ | "state_revision_mismatch";
32
+
33
+ export class ApprovalError extends Error {
34
+ constructor(readonly code: ApprovalErrorCode, message: string) {
35
+ super(`${code}: ${message}`);
36
+ this.name = "ApprovalError";
37
+ }
38
+ }
39
+
40
+ export interface ProposalRecord {
41
+ id: string;
42
+ projectId: string;
43
+ feature: string;
44
+ kind: ApprovalKind;
45
+ subjectKey: string;
46
+ payload: Record<string, unknown>;
47
+ pins: Record<string, unknown>;
48
+ stateRevision: number;
49
+ status: ProposalStatus;
50
+ createdAt: string;
51
+ resolvedAt: string | null;
52
+ }
53
+
54
+ export interface ApprovalRecord {
55
+ id: string;
56
+ proposalId: string;
57
+ projectId: string;
58
+ feature: string;
59
+ kind: ApprovalKind;
60
+ subjectKey: string;
61
+ pins: Record<string, unknown>;
62
+ decision: Record<string, unknown>;
63
+ approvedVia: string;
64
+ approvedAt: string;
65
+ supersededAt: string | null;
66
+ }
67
+
68
+ export interface ProposeInput {
69
+ projectId: string;
70
+ feature: string;
71
+ kind: ApprovalKind;
72
+ subjectKey: string;
73
+ payload: Record<string, unknown>;
74
+ pins: Record<string, unknown>;
75
+ stateRevision: number;
76
+ }
77
+
78
+ export interface CurrentPins {
79
+ pins: Record<string, unknown>;
80
+ stateRevision: number;
81
+ }
82
+
83
+ export interface ConfirmInput {
84
+ projectId: string;
85
+ proposalId: string;
86
+ decision: Record<string, unknown>;
87
+ /**
88
+ * Recomputes the current pins for the stored proposal. It runs inside the
89
+ * write transaction (BEGIN IMMEDIATE), so it must be synchronous.
90
+ */
91
+ recompute: (proposal: ProposalRecord) => CurrentPins;
92
+ now?: Date;
93
+ }
94
+
95
+ export type ConfirmResult =
96
+ | { ok: true; approvalId: string; supersededIds: string[] }
97
+ | { ok: false; code: ApprovalErrorCode; message: string };
98
+
99
+ /** Deterministic key-sorted JSON used to compare pins. */
100
+ export function canonicalPinsJson(value: unknown): string {
101
+ if (Array.isArray(value)) return `[${value.map(canonicalPinsJson).join(",")}]`;
102
+ if (value && typeof value === "object") {
103
+ return `{${Object.keys(value as Record<string, unknown>).sort().map(key => `${JSON.stringify(key)}:${canonicalPinsJson((value as Record<string, unknown>)[key])}`).join(",")}}`;
104
+ }
105
+ if (value === undefined) return "null";
106
+ return JSON.stringify(value);
107
+ }
108
+
109
+ function isRecord(value: unknown): value is Record<string, unknown> {
110
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
111
+ }
112
+
113
+ function isKind(value: unknown): value is ApprovalKind {
114
+ return typeof value === "string" && (APPROVAL_KINDS as readonly string[]).includes(value);
115
+ }
116
+
117
+ const PIN_KEYS: Record<ApprovalKind, string[]> = {
118
+ execution_plan: ["dsl_sha256", "suite_fingerprint", "suite_graph_revision", "tc_sha256"],
119
+ environment_profile: ["profile_sha256"],
120
+ mode_override: ["binding_entry_sha256", "from", "suite_fingerprint", "tc_sha256", "to"],
121
+ human_result: ["evidence", "suite_fingerprint", "tc_sha256"],
122
+ };
123
+
124
+ /** Enforces the change-list §1.8 subject_key and pins_json shapes. */
125
+ export function validatePinsShape(kind: ApprovalKind, subjectKey: string, pins: Record<string, unknown>): string[] {
126
+ const errors: string[] = [];
127
+ const keys = Object.keys(pins).sort();
128
+ if (canonicalPinsJson(keys) !== canonicalPinsJson(PIN_KEYS[kind])) errors.push(`${kind} pins must contain exactly: ${PIN_KEYS[kind].join(", ")}`);
129
+ if (kind === "environment_profile") {
130
+ if (!/^[A-Za-z0-9][A-Za-z0-9_.-]{0,63}$/.test(subjectKey)) errors.push("environment_profile subject_key must be a profile name");
131
+ } else if (!/^TC-[A-Za-z0-9_-]+$/.test(subjectKey)) {
132
+ errors.push(`${kind} subject_key must be a TC id`);
133
+ }
134
+ for (const key of keys) {
135
+ const value = pins[key];
136
+ if (key.endsWith("sha256") || key === "suite_fingerprint") {
137
+ if (typeof value !== "string" || value.length === 0) errors.push(`pin ${key} must be a non-empty string`);
138
+ }
139
+ }
140
+ if (kind === "human_result") {
141
+ const evidence = pins.evidence;
142
+ if (!Array.isArray(evidence) || evidence.some(item => !isRecord(item) || typeof item.path !== "string" || typeof item.sha256 !== "string")) {
143
+ errors.push("human_result evidence pins must be [{path, sha256}]");
144
+ }
145
+ }
146
+ return errors;
147
+ }
148
+
149
+ /** Validates a UI decision; human_result verdicts must come from the user. */
150
+ export function validateDecision(kind: ApprovalKind, decision: Record<string, unknown>, pins: Record<string, unknown>): string[] {
151
+ const errors: string[] = [];
152
+ if (kind === "human_result") {
153
+ const keys = Object.keys(decision).sort();
154
+ if (canonicalPinsJson(keys) !== canonicalPinsJson(["actual_result", "status"])) errors.push("human_result decision must contain exactly status and actual_result");
155
+ if (!(HUMAN_RESULT_STATUSES as readonly string[]).includes(String(decision.status))) errors.push("human_result status must be passed, failed, or blocked");
156
+ if (typeof decision.actual_result !== "string" || !decision.actual_result.trim()) errors.push("human_result actual_result is required");
157
+ if (decision.status === "passed" && (!Array.isArray(pins.evidence) || pins.evidence.length === 0)) errors.push("a passed human_result requires at least one pinned evidence file");
158
+ } else if (canonicalPinsJson(decision) !== canonicalPinsJson({ approved: true })) {
159
+ errors.push(`${kind} decision must be {approved: true}`);
160
+ }
161
+ return errors;
162
+ }
163
+
164
+ export function databaseAuthority(db: Database, projectId: string): string | null {
165
+ const row = db.query("SELECT authority FROM authority_state WHERE project_id=?").get(projectId) as { authority: string } | null;
166
+ return row?.authority ?? null;
167
+ }
168
+
169
+ function assertDatabaseAuthority(db: Database, projectId: string): void {
170
+ const authority = databaseAuthority(db, projectId);
171
+ if (authority !== "database") {
172
+ throw new ApprovalError("approval_requires_database_authority", `project authority is ${authority ?? "unregistered"}; approvals require database authority`);
173
+ }
174
+ }
175
+
176
+ function proposalFromRow(row: any): ProposalRecord {
177
+ return {
178
+ id: row.id, projectId: row.project_id, feature: row.feature, kind: row.kind, subjectKey: row.subject_key,
179
+ payload: JSON.parse(row.payload_json), pins: JSON.parse(row.pins_json), stateRevision: row.state_revision,
180
+ status: row.status, createdAt: row.created_at, resolvedAt: row.resolved_at ?? null,
181
+ };
182
+ }
183
+
184
+ function approvalFromRow(row: any): ApprovalRecord {
185
+ return {
186
+ id: row.id, proposalId: row.proposal_id, projectId: row.project_id, feature: row.feature, kind: row.kind,
187
+ subjectKey: row.subject_key, pins: JSON.parse(row.pins_json), decision: JSON.parse(row.decision_json),
188
+ approvedVia: row.approved_via, approvedAt: row.approved_at, supersededAt: row.superseded_at ?? null,
189
+ };
190
+ }
191
+
192
+ function validateProposeInput(input: ProposeInput): void {
193
+ if (!isKind(input.kind)) throw new ApprovalError("invalid_proposal", `unknown approval kind: ${String(input.kind)}`);
194
+ if (!input.feature || /[/\\\x00-\x1f\x7f]/.test(input.feature)) throw new ApprovalError("invalid_proposal", "feature must be a plain feature name");
195
+ if (!isRecord(input.payload)) throw new ApprovalError("invalid_proposal", "payload must be an object");
196
+ if (!isRecord(input.pins)) throw new ApprovalError("invalid_proposal", "pins must be an object");
197
+ if (!Number.isInteger(input.stateRevision) || input.stateRevision < 0) throw new ApprovalError("invalid_proposal", "state_revision must be a non-negative integer");
198
+ const shapeErrors = validatePinsShape(input.kind, input.subjectKey, input.pins);
199
+ if (shapeErrors.length) throw new ApprovalError("invalid_proposal", shapeErrors.join("; "));
200
+ }
201
+
202
+ /** Must run inside a write transaction; expires older open proposals for the subject, then inserts. */
203
+ function insertProposal(db: Database, input: ProposeInput, timestamp: string): { proposalId: string; expiredIds: string[] } {
204
+ assertDatabaseAuthority(db, input.projectId);
205
+ const proposalId = randomUUID();
206
+ const open = db.query(`SELECT id FROM approval_proposals
207
+ WHERE project_id=? AND feature=? AND kind=? AND subject_key=? AND status='proposed'`).all(input.projectId, input.feature, input.kind, input.subjectKey) as Array<{ id: string }>;
208
+ for (const item of open) {
209
+ db.query("UPDATE approval_proposals SET status='expired',resolved_at=? WHERE id=? AND status='proposed'").run(timestamp, item.id);
210
+ }
211
+ db.query(`INSERT INTO approval_proposals(id,project_id,feature,kind,subject_key,payload_json,pins_json,state_revision,status,created_at,resolved_at)
212
+ VALUES (?,?,?,?,?,?,?,?,'proposed',?,NULL)`).run(
213
+ proposalId, input.projectId, input.feature, input.kind, input.subjectKey,
214
+ canonicalPinsJson(input.payload), canonicalPinsJson(input.pins), input.stateRevision, timestamp,
215
+ );
216
+ return { proposalId, expiredIds: open.map(item => item.id) };
217
+ }
218
+
219
+ /**
220
+ * Records a proposal with the pins observed at proposal time. An older open
221
+ * proposal for the same feature/kind/subject is expired so only the newest
222
+ * proposal can be confirmed.
223
+ */
224
+ export function proposeApproval(db: Database, input: ProposeInput, options: { now?: Date } = {}): { proposalId: string; expiredIds: string[] } {
225
+ validateProposeInput(input);
226
+ const timestamp = (options.now ?? new Date()).toISOString();
227
+ return db.transaction(() => insertProposal(db, input, timestamp)).immediate();
228
+ }
229
+
230
+ /**
231
+ * All-or-nothing batch propose: every item is validated first, then all inserts and
232
+ * "expire older open proposal for the same subject" updates run in ONE immediate
233
+ * transaction that rolls back completely on any error.
234
+ */
235
+ export function proposeApprovals(db: Database, inputs: ProposeInput[], options: { now?: Date } = {}): Array<{ proposalId: string; expiredIds: string[] }> {
236
+ if (!Array.isArray(inputs) || inputs.length === 0) throw new ApprovalError("invalid_proposal", "at least one proposal is required");
237
+ for (const input of inputs) validateProposeInput(input);
238
+ const timestamp = (options.now ?? new Date()).toISOString();
239
+ return db.transaction(() => inputs.map(input => insertProposal(db, input, timestamp))).immediate();
240
+ }
241
+
242
+ export function getProposal(db: Database, projectId: string, proposalId: string): ProposalRecord | null {
243
+ const row = db.query("SELECT * FROM approval_proposals WHERE id=? AND project_id=?").get(proposalId, projectId);
244
+ return row ? proposalFromRow(row) : null;
245
+ }
246
+
247
+ export function listProposals(db: Database, projectId: string, filter: { feature?: string; status?: ProposalStatus; kind?: ApprovalKind } = {}): ProposalRecord[] {
248
+ const clauses = ["project_id=?"]; const params: Array<string> = [projectId];
249
+ if (filter.feature) { clauses.push("feature=?"); params.push(filter.feature); }
250
+ if (filter.status) { clauses.push("status=?"); params.push(filter.status); }
251
+ if (filter.kind) { clauses.push("kind=?"); params.push(filter.kind); }
252
+ return (db.query(`SELECT * FROM approval_proposals WHERE ${clauses.join(" AND ")} ORDER BY created_at, id`).all(...params) as any[]).map(proposalFromRow);
253
+ }
254
+
255
+ export function listApprovals(db: Database, projectId: string, filter: { feature?: string; kind?: ApprovalKind; includeSuperseded?: boolean } = {}): ApprovalRecord[] {
256
+ const clauses = ["project_id=?"]; const params: Array<string> = [projectId];
257
+ if (filter.feature) { clauses.push("feature=?"); params.push(filter.feature); }
258
+ if (filter.kind) { clauses.push("kind=?"); params.push(filter.kind); }
259
+ if (!filter.includeSuperseded) clauses.push("superseded_at IS NULL");
260
+ // approved_at has millisecond precision, so confirmations in one transaction
261
+ // window can tie. rowid preserves the actual append order; UUID ordering does not.
262
+ return (db.query(`SELECT * FROM approvals WHERE ${clauses.join(" AND ")} ORDER BY approved_at, rowid`).all(...params) as any[]).map(approvalFromRow);
263
+ }
264
+
265
+ /** The user declined the proposal in the UI; it can never be confirmed afterwards. */
266
+ export function rejectProposal(db: Database, projectId: string, proposalId: string, options: { now?: Date } = {}): boolean {
267
+ const timestamp = (options.now ?? new Date()).toISOString();
268
+ return db.query("UPDATE approval_proposals SET status='rejected',resolved_at=? WHERE id=? AND project_id=? AND status='proposed'")
269
+ .run(timestamp, proposalId, projectId).changes === 1;
270
+ }
271
+
272
+ export function proposalIsExpired(proposal: Pick<ProposalRecord, "createdAt">, now = new Date()): boolean {
273
+ const created = Date.parse(proposal.createdAt);
274
+ return !Number.isFinite(created) || now.getTime() - created > PROPOSAL_TTL_MS;
275
+ }
276
+
277
+ /**
278
+ * Confirms one proposal in a single IMMEDIATE transaction: re-checks database
279
+ * authority, proposal state and TTL, recomputes the pins (CAS), inserts the
280
+ * approval, consumes the proposal and supersedes the previous approval for the
281
+ * same feature/kind/subject. Stale or expired proposals are marked expired and
282
+ * the call fails; nothing else is written in that case.
283
+ */
284
+ export function confirmApproval(db: Database, input: ConfirmInput): ConfirmResult {
285
+ const now = input.now ?? new Date();
286
+ const timestamp = now.toISOString();
287
+ const expire = (proposalId: string) => {
288
+ db.query("UPDATE approval_proposals SET status='expired',resolved_at=? WHERE id=? AND status='proposed'").run(timestamp, proposalId);
289
+ };
290
+ const transaction = db.transaction((): ConfirmResult => {
291
+ const authority = databaseAuthority(db, input.projectId);
292
+ if (authority !== "database") {
293
+ return { ok: false, code: "approval_requires_database_authority", message: `project authority is ${authority ?? "unregistered"}` };
294
+ }
295
+ const row = db.query("SELECT * FROM approval_proposals WHERE id=? AND project_id=?").get(input.proposalId, input.projectId);
296
+ if (!row) return { ok: false, code: "proposal_not_found", message: `unknown proposal: ${input.proposalId}` };
297
+ const proposal = proposalFromRow(row);
298
+ if (proposal.status !== "proposed") return { ok: false, code: "proposal_not_pending", message: `proposal is ${proposal.status}` };
299
+ if (proposalIsExpired(proposal, now)) {
300
+ expire(proposal.id);
301
+ return { ok: false, code: "proposal_expired", message: "proposal is older than the confirmation window; propose again" };
302
+ }
303
+ const decisionErrors = isRecord(input.decision) ? validateDecision(proposal.kind, input.decision, proposal.pins) : ["decision must be an object"];
304
+ if (decisionErrors.length) return { ok: false, code: "invalid_decision", message: decisionErrors.join("; ") };
305
+ let current: CurrentPins;
306
+ try {
307
+ current = input.recompute(proposal);
308
+ } catch (error) {
309
+ return { ok: false, code: "pins_unavailable", message: error instanceof Error ? error.message : String(error) };
310
+ }
311
+ if (!current || !isRecord(current.pins) || canonicalPinsJson(current.pins) !== canonicalPinsJson(proposal.pins)) {
312
+ expire(proposal.id);
313
+ return { ok: false, code: "pins_mismatch", message: "suite, TC, binding, DSL, profile or evidence changed since the proposal; propose again" };
314
+ }
315
+ if (current.stateRevision !== proposal.stateRevision) {
316
+ expire(proposal.id);
317
+ return { ok: false, code: "state_revision_mismatch", message: `workflow state revision changed from ${proposal.stateRevision} to ${current.stateRevision}; propose again` };
318
+ }
319
+ const superseded = db.query(`SELECT id FROM approvals
320
+ WHERE project_id=? AND feature=? AND kind=? AND subject_key=? AND superseded_at IS NULL`).all(proposal.projectId, proposal.feature, proposal.kind, proposal.subjectKey) as Array<{ id: string }>;
321
+ for (const item of superseded) {
322
+ db.query("UPDATE approvals SET superseded_at=? WHERE id=? AND superseded_at IS NULL").run(timestamp, item.id);
323
+ }
324
+ const approvalId = randomUUID();
325
+ db.query(`INSERT INTO approvals(id,proposal_id,project_id,feature,kind,subject_key,pins_json,decision_json,approved_via,approved_at,superseded_at)
326
+ VALUES (?,?,?,?,?,?,?,?,?,?,NULL)`).run(
327
+ approvalId, proposal.id, proposal.projectId, proposal.feature, proposal.kind, proposal.subjectKey,
328
+ canonicalPinsJson(proposal.pins), canonicalPinsJson(input.decision), APPROVED_VIA, timestamp,
329
+ );
330
+ const consumed = db.query("UPDATE approval_proposals SET status='consumed',resolved_at=? WHERE id=? AND status='proposed'").run(timestamp, proposal.id);
331
+ if (consumed.changes !== 1) throw new ApprovalError("proposal_not_pending", "proposal was consumed concurrently");
332
+ return { ok: true, approvalId, supersededIds: superseded.map(item => item.id) };
333
+ });
334
+ try {
335
+ return transaction.immediate();
336
+ } catch (error) {
337
+ if (error instanceof ApprovalError) return { ok: false, code: error.code, message: error.message };
338
+ throw error;
339
+ }
340
+ }