@guanlin4924/devflow-pi 0.1.0

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 (254) hide show
  1. package/README.md +164 -0
  2. package/docs/OMP-NATIVE-ARCHITECTURE.md +104 -0
  3. package/package.json +40 -0
  4. package/plugins/devflow-core/extensions/devflow-core.ts +1642 -0
  5. package/plugins/devflow-core/package.json +14 -0
  6. package/plugins/devflow-core/runtime/hooks/context_sync_gate.py +174 -0
  7. package/plugins/devflow-core/runtime/hooks/hook_common.py +696 -0
  8. package/plugins/devflow-core/runtime/hooks/index_gate.py +63 -0
  9. package/plugins/devflow-core/runtime/hooks/injection_code_specification.py +7 -0
  10. package/plugins/devflow-core/runtime/hooks/post_tool.py +44 -0
  11. package/plugins/devflow-core/runtime/hooks/start.py +288 -0
  12. package/plugins/devflow-core/skills/workflow-orchestrator/SKILL.md +265 -0
  13. package/plugins/devflow-core/skills/workflow-orchestrator/agents/openai.yaml +4 -0
  14. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/advance_state.rb +520 -0
  15. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/control_io.rb +42 -0
  16. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/init_state.rb +138 -0
  17. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/init_workflow.rb +121 -0
  18. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/inspect_state.rb +553 -0
  19. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/manage_lessons.rb +219 -0
  20. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/sync_artifacts.rb +168 -0
  21. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/update_triage_route.rb +110 -0
  22. package/plugins/devflow-core/skills/workflow-orchestrator/scripts/validate_state.rb +565 -0
  23. package/plugins/devflow-core/skills/workflow-orchestrator/templates/feature-development.yaml +783 -0
  24. package/plugins/devflow-core/skills/workflow-orchestrator/templates/uat-remediation.yaml +143 -0
  25. package/plugins/devflow-core/skills/workflow-orchestrator/templates/workflows-README.md +10 -0
  26. package/plugins/devflow-core/skills/workflow-pipeline/SKILL.md +117 -0
  27. package/plugins/devflow-core/skills/workflow-pipeline/references/pipeline-flow.md +167 -0
  28. package/plugins/devflow-core/skills/workflow-pipeline/references/slice-safety-guide.md +125 -0
  29. package/plugins/devflow-core/skills/workflow-project-context/SKILL.md +819 -0
  30. package/plugins/devflow-core/skills/workflow-project-context/assets/agents-md-template.md +25 -0
  31. package/plugins/devflow-core/skills/workflow-project-context/assets/codebase-backend-spec-template.md +68 -0
  32. package/plugins/devflow-core/skills/workflow-project-context/assets/codebase-frontend-spec-template.md +64 -0
  33. package/plugins/devflow-core/skills/workflow-project-context/assets/codebase-navigation-template.md +168 -0
  34. package/plugins/devflow-core/skills/workflow-project-context/assets/context-domain-index-template.md +43 -0
  35. package/plugins/devflow-core/skills/workflow-project-context/assets/context-spec-index-template.md +45 -0
  36. package/plugins/devflow-core/skills/workflow-project-context/assets/execution-contract-template.md +57 -0
  37. package/plugins/devflow-core/skills/workflow-project-context/assets/navigation-index-template.md +40 -0
  38. package/plugins/devflow-core/skills/workflow-project-context/assets/project-initialization-template.md +109 -0
  39. package/plugins/devflow-core/skills/workflow-project-context/assets/rules-index-template.md +80 -0
  40. package/plugins/devflow-core/skills/workflow-project-context/assets/run-manifest-template.json +40 -0
  41. package/plugins/devflow-core/skills/workflow-project-context/assets/spec-templates/backend/directory-structure.md +46 -0
  42. package/plugins/devflow-core/skills/workflow-project-context/assets/spec-templates/backend/engine.md +46 -0
  43. package/plugins/devflow-core/skills/workflow-project-context/assets/spec-templates/backend/errors.md +46 -0
  44. package/plugins/devflow-core/skills/workflow-project-context/assets/spec-templates/backend/locator.md +46 -0
  45. package/plugins/devflow-core/skills/workflow-project-context/assets/spec-templates/backend/model.md +46 -0
  46. package/plugins/devflow-core/skills/workflow-project-context/assets/spec-templates/backend/repository.md +46 -0
  47. package/plugins/devflow-core/skills/workflow-project-context/assets/spec-templates/backend/router.md +46 -0
  48. package/plugins/devflow-core/skills/workflow-project-context/assets/spec-templates/backend/scheduler.md +46 -0
  49. package/plugins/devflow-core/skills/workflow-project-context/assets/spec-templates/backend/schema.md +46 -0
  50. package/plugins/devflow-core/skills/workflow-project-context/assets/spec-templates/backend/service.md +46 -0
  51. package/plugins/devflow-core/skills/workflow-project-context/assets/spec-templates/backend/testing.md +46 -0
  52. package/plugins/devflow-core/skills/workflow-project-context/assets/spec-templates/frontend/api-client.md +46 -0
  53. package/plugins/devflow-core/skills/workflow-project-context/assets/spec-templates/frontend/case-editor.md +46 -0
  54. package/plugins/devflow-core/skills/workflow-project-context/assets/spec-templates/frontend/components.md +46 -0
  55. package/plugins/devflow-core/skills/workflow-project-context/assets/spec-templates/frontend/directory-structure.md +46 -0
  56. package/plugins/devflow-core/skills/workflow-project-context/assets/spec-templates/frontend/forms.md +46 -0
  57. package/plugins/devflow-core/skills/workflow-project-context/assets/spec-templates/frontend/routing.md +46 -0
  58. package/plugins/devflow-core/skills/workflow-project-context/assets/spec-templates/frontend/state.md +46 -0
  59. package/plugins/devflow-core/skills/workflow-project-context/assets/spec-templates/frontend/testing.md +46 -0
  60. package/plugins/devflow-core/skills/workflow-project-context/assets/stack-spec-template.md +106 -0
  61. package/plugins/devflow-core/skills/workflow-project-context/assets/state-template.md +77 -0
  62. package/plugins/devflow-core/skills/workflow-project-context/assets/toolchain-template.md +37 -0
  63. package/plugins/devflow-core/skills/workflow-project-context/references/navigation-guide.md +262 -0
  64. package/plugins/devflow-core/skills/workflow-project-context/scripts/validate_initialization.py +545 -0
  65. package/plugins/devflow-design/agents/contract-auditor.md +18 -0
  66. package/plugins/devflow-design/extensions/devflow-design.ts +47 -0
  67. package/plugins/devflow-design/package.json +14 -0
  68. package/plugins/devflow-design/skills/workflow-api-call-guide/SKILL.md +142 -0
  69. package/plugins/devflow-design/skills/workflow-api-contract/SKILL.md +150 -0
  70. package/plugins/devflow-design/skills/workflow-api-supplement/SKILL.md +121 -0
  71. package/plugins/devflow-design/skills/workflow-backend-tech-spec/SKILL.md +257 -0
  72. package/plugins/devflow-design/skills/workflow-backend-tech-spec/assets/adr-template.md +57 -0
  73. package/plugins/devflow-design/skills/workflow-backend-tech-spec/assets/backend-spec-template.md +205 -0
  74. package/plugins/devflow-design/skills/workflow-backend-tech-spec/references/affected-module-exploration.md +59 -0
  75. package/plugins/devflow-design/skills/workflow-backend-tech-spec/references/backend-conventions.md +30 -0
  76. package/plugins/devflow-design/skills/workflow-backend-tech-spec/references/code-explore-guide.md +40 -0
  77. package/plugins/devflow-design/skills/workflow-backend-tech-spec/references/project-rule-contract.md +66 -0
  78. package/plugins/devflow-design/skills/workflow-design-rule-pack/SKILL.md +91 -0
  79. package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/index.md +71 -0
  80. package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/recommendations/accessibility.md +31 -0
  81. package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/recommendations/component-library.md +31 -0
  82. package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/recommendations/design-systems.md +47 -0
  83. package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/recommendations/responsive-grid.md +29 -0
  84. package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/recommendations/stack-guidelines.md +31 -0
  85. package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/recommendations/ux-patterns.md +40 -0
  86. package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tokens/project-tokens.md +19 -0
  87. package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tools/ui-ux-pro-max/SKILL.md +377 -0
  88. package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tools/ui-ux-pro-max/data/charts.csv +26 -0
  89. package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tools/ui-ux-pro-max/data/colors.csv +97 -0
  90. package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tools/ui-ux-pro-max/data/icons.csv +101 -0
  91. package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tools/ui-ux-pro-max/data/landing.csv +31 -0
  92. package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tools/ui-ux-pro-max/data/products.csv +97 -0
  93. package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tools/ui-ux-pro-max/data/react-performance.csv +45 -0
  94. package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tools/ui-ux-pro-max/data/stacks/astro.csv +54 -0
  95. package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tools/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
  96. package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tools/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
  97. package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tools/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
  98. package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tools/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
  99. package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tools/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
  100. package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tools/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
  101. package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tools/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
  102. package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tools/ui-ux-pro-max/data/stacks/react.csv +54 -0
  103. package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tools/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
  104. package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tools/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
  105. package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tools/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
  106. package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tools/ui-ux-pro-max/data/stacks/vue.csv +50 -0
  107. package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tools/ui-ux-pro-max/data/styles.csv +68 -0
  108. package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tools/ui-ux-pro-max/data/typography.csv +58 -0
  109. package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tools/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
  110. package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tools/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
  111. package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tools/ui-ux-pro-max/data/web-interface.csv +31 -0
  112. package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tools/ui-ux-pro-max/scripts/core.py +253 -0
  113. package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tools/ui-ux-pro-max/scripts/design_system.py +1067 -0
  114. package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tools/ui-ux-pro-max/scripts/search.py +114 -0
  115. package/plugins/devflow-design/skills/workflow-design-rule-pack/scripts/install.py +67 -0
  116. package/plugins/devflow-design/skills/workflow-feature-breakdown/SKILL.md +370 -0
  117. package/plugins/devflow-design/skills/workflow-feature-breakdown/assets/admin-system-template.md +57 -0
  118. package/plugins/devflow-design/skills/workflow-feature-breakdown/assets/api-service-template.md +42 -0
  119. package/plugins/devflow-design/skills/workflow-feature-breakdown/assets/c-end-system-template.md +25 -0
  120. package/plugins/devflow-design/skills/workflow-feature-breakdown/assets/output-template.md +139 -0
  121. package/plugins/devflow-design/skills/workflow-feature-breakdown/references/bug-rules.md +12 -0
  122. package/plugins/devflow-design/skills/workflow-feature-breakdown/references/exception-checklist.md +31 -0
  123. package/plugins/devflow-design/skills/workflow-feature-breakdown/references/trace-integrity-guide.md +153 -0
  124. package/plugins/devflow-design/skills/workflow-feature-breakdown/references/writing-guide.md +92 -0
  125. package/plugins/devflow-design/skills/workflow-frontend-tech-spec/SKILL.md +223 -0
  126. package/plugins/devflow-design/skills/workflow-frontend-tech-spec/assets/frontend-spec-template.md +204 -0
  127. package/plugins/devflow-design/skills/workflow-frontend-tech-spec/references/affected-module-exploration.md +58 -0
  128. package/plugins/devflow-design/skills/workflow-frontend-tech-spec/references/component-patterns.md +42 -0
  129. package/plugins/devflow-design/skills/workflow-frontend-tech-spec/references/frontend-conventions.md +28 -0
  130. package/plugins/devflow-design/skills/workflow-frontend-tech-spec/references/frontend-stack-slots/common-web.md +53 -0
  131. package/plugins/devflow-design/skills/workflow-frontend-tech-spec/references/frontend-stack-slots/next.md +40 -0
  132. package/plugins/devflow-design/skills/workflow-frontend-tech-spec/references/frontend-stack-slots/react.md +41 -0
  133. package/plugins/devflow-design/skills/workflow-frontend-tech-spec/references/frontend-stack-slots/vue.md +41 -0
  134. package/plugins/devflow-design/skills/workflow-frontend-tech-spec/references/project-rule-contract.md +95 -0
  135. package/plugins/devflow-design/skills/workflow-integration-verify/SKILL.md +172 -0
  136. package/plugins/devflow-design/skills/workflow-ui-spec/SKILL.md +302 -0
  137. package/plugins/devflow-design/skills/workflow-ui-spec/assets/ui-spec-template.md +244 -0
  138. package/plugins/devflow-design/skills/workflow-ui-spec/references/affected-module-exploration.md +55 -0
  139. package/plugins/devflow-implementation/agents/implementation-worker.md +20 -0
  140. package/plugins/devflow-implementation/package.json +6 -0
  141. package/plugins/devflow-implementation/skills/workflow-bug-fix/SKILL.md +124 -0
  142. package/plugins/devflow-implementation/skills/workflow-bug-fix/references/INDEX.md +13 -0
  143. package/plugins/devflow-implementation/skills/workflow-bug-fix/references/adversarial-review.md +35 -0
  144. package/plugins/devflow-implementation/skills/workflow-bug-fix/references/first-principles.md +26 -0
  145. package/plugins/devflow-implementation/skills/workflow-bug-fix/references/lesson-format.md +28 -0
  146. package/plugins/devflow-implementation/skills/workflow-bug-fix/references/root-cause-ladder.md +51 -0
  147. package/plugins/devflow-implementation/skills/workflow-bug-fix/references/seam-analysis.md +30 -0
  148. package/plugins/devflow-implementation/skills/workflow-change-plan/SKILL.md +160 -0
  149. package/plugins/devflow-implementation/skills/workflow-change-plan/references/code-conventions.md +33 -0
  150. package/plugins/devflow-implementation/skills/workflow-change-plan/references/ddl-guidelines.md +60 -0
  151. package/plugins/devflow-implementation/skills/workflow-change-plan/references/output-template.md +217 -0
  152. package/plugins/devflow-implementation/skills/workflow-change-plan/references/project-rule-contract.md +55 -0
  153. package/plugins/devflow-implementation/skills/workflow-execute-phase/SKILL.md +271 -0
  154. package/plugins/devflow-implementation/skills/workflow-execute-phase/references/execute-phase.md +1251 -0
  155. package/plugins/devflow-implementation/skills/workflow-execute-phase/references/ui-brand.md +160 -0
  156. package/plugins/devflow-intel/agents/project-scout.md +27 -0
  157. package/plugins/devflow-intel/extensions/devflow-intel.ts +104 -0
  158. package/plugins/devflow-intel/package.json +14 -0
  159. package/plugins/devflow-intel/skills/code-index-query/SKILL.md +37 -0
  160. package/plugins/devflow-intel/skills/code-index-query/references/query-patterns.md +27 -0
  161. package/plugins/devflow-intel/skills/workflow-code-index/SKILL.md +68 -0
  162. package/plugins/devflow-intel/skills/workflow-code-index/references/adapter-contract.md +38 -0
  163. package/plugins/devflow-intel/skills/workflow-code-index/references/audit-checklist.md +10 -0
  164. package/plugins/devflow-intel/skills/workflow-code-index/references/confidence-rules.md +43 -0
  165. package/plugins/devflow-intel/skills/workflow-code-index/references/data-model.md +74 -0
  166. package/plugins/devflow-intel/skills/workflow-code-index/references/discovery.md +24 -0
  167. package/plugins/devflow-intel/skills/workflow-code-index/references/query-guide.md +20 -0
  168. package/plugins/devflow-intel/skills/workflow-code-index/scripts/adapters/__init__.py +1 -0
  169. package/plugins/devflow-intel/skills/workflow-code-index/scripts/adapters/base.py +30 -0
  170. package/plugins/devflow-intel/skills/workflow-code-index/scripts/adapters/generic_text.py +287 -0
  171. package/plugins/devflow-intel/skills/workflow-code-index/scripts/adapters/registry.py +17 -0
  172. package/plugins/devflow-intel/skills/workflow-code-index/scripts/code_index.py +437 -0
  173. package/plugins/devflow-intel/skills/workflow-code-index/scripts/core/__init__.py +1 -0
  174. package/plugins/devflow-intel/skills/workflow-code-index/scripts/core/discovery.py +139 -0
  175. package/plugins/devflow-intel/skills/workflow-code-index/scripts/core/hashing.py +11 -0
  176. package/plugins/devflow-intel/skills/workflow-code-index/scripts/core/scanner.py +115 -0
  177. package/plugins/devflow-intel/skills/workflow-code-index/scripts/core/schema.py +123 -0
  178. package/plugins/devflow-intel/skills/workflow-code-index/scripts/validators/__init__.py +1 -0
  179. package/plugins/devflow-intel/skills/workflow-code-index/scripts/validators/project_binding_check.py +66 -0
  180. package/plugins/devflow-intel/skills/workflow-code-index/scripts/validators/relation_check.py +36 -0
  181. package/plugins/devflow-intel/skills/workflow-code-index/scripts/validators/schema_validate.py +11 -0
  182. package/plugins/devflow-intel/skills/workflow-code-index/scripts/validators/stale_check.py +42 -0
  183. package/plugins/devflow-intel/skills/workflow-code-index/scripts/writers/__init__.py +1 -0
  184. package/plugins/devflow-intel/skills/workflow-code-index/scripts/writers/jsonl_writer.py +25 -0
  185. package/plugins/devflow-intel/skills/workflow-code-index/scripts/writers/markdown_writer.py +106 -0
  186. package/plugins/devflow-intel/skills/workflow-code-index/scripts/writers/sqlite_writer.py +143 -0
  187. package/plugins/devflow-intel/skills/workflow-context-sync/SKILL.md +381 -0
  188. package/plugins/devflow-intel/skills/workflow-context-sync/agents/openai.yaml +4 -0
  189. package/plugins/devflow-intel/skills/workflow-context-sync/scripts/context_sync_cursor.py +241 -0
  190. package/plugins/devflow-intel/skills/workflow-update-navigation/SKILL.md +186 -0
  191. package/plugins/devflow-intel/skills/workflow-update-navigation/references/incremental-update-guide.md +47 -0
  192. package/plugins/devflow-quality/agents/code-reviewer.md +18 -0
  193. package/plugins/devflow-quality/agents/verification-runner.md +21 -0
  194. package/plugins/devflow-quality/extensions/devflow-quality.ts +59 -0
  195. package/plugins/devflow-quality/package.json +14 -0
  196. package/plugins/devflow-quality/skills/code-review/SKILL.md +288 -0
  197. package/plugins/devflow-quality/skills/code-review/references/cross-layer-checklist.md +70 -0
  198. package/plugins/devflow-quality/skills/code-review/references/dao-checklist.md +70 -0
  199. package/plugins/devflow-quality/skills/code-review/references/handler-checklist.md +48 -0
  200. package/plugins/devflow-quality/skills/code-review/references/repository-checklist.md +44 -0
  201. package/plugins/devflow-quality/skills/code-review/references/service-checklist.md +57 -0
  202. package/plugins/devflow-quality/skills/code-review/references/spec-checklist.md +34 -0
  203. package/plugins/devflow-quality/skills/code-review/references/vo-checklist.md +26 -0
  204. package/plugins/devflow-quality/skills/workflow-audit-milestone/SKILL.md +31 -0
  205. package/plugins/devflow-quality/skills/workflow-audit-milestone/references/audit-milestone.md +328 -0
  206. package/plugins/devflow-quality/skills/workflow-complete-milestone/SKILL.md +132 -0
  207. package/plugins/devflow-quality/skills/workflow-complete-milestone/assets/milestone-archive.md +123 -0
  208. package/plugins/devflow-quality/skills/workflow-complete-milestone/references/complete-milestone.md +775 -0
  209. package/plugins/devflow-quality/skills/workflow-complete-milestone/references/milestone-archive.md +123 -0
  210. package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/SKILL.md +126 -0
  211. package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/references/api-mainflow-rules.md +27 -0
  212. package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/references/codebase-discovery.md +54 -0
  213. package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/references/intermediate-format.md +244 -0
  214. package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/references/mainflow-selection.md +36 -0
  215. package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/references/project-dsl-contract.md +190 -0
  216. package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/references/ui-mainflow-rules.md +110 -0
  217. package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/scripts/compile_dsl.py +583 -0
  218. package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/scripts/discover_codebases.py +199 -0
  219. package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/scripts/normalize_case_payloads.py +177 -0
  220. package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/scripts/validate_case_payloads.py +370 -0
  221. package/plugins/devflow-quality/skills/workflow-verify-work/SKILL.md +106 -0
  222. package/plugins/devflow-quality/skills/workflow-verify-work/assets/UAT.md +265 -0
  223. package/plugins/devflow-quality/skills/workflow-verify-work/references/verify-work.md +759 -0
  224. package/plugins/devflow-requirements/agents/requirements-auditor.md +20 -0
  225. package/plugins/devflow-requirements/package.json +6 -0
  226. package/plugins/devflow-requirements/skills/requirement-feasibility-review/SKILL.md +219 -0
  227. package/plugins/devflow-requirements/skills/requirement-feasibility-review/agents/openai.yaml +4 -0
  228. package/plugins/devflow-requirements/skills/requirement-feasibility-review/references/review-method.md +257 -0
  229. package/plugins/devflow-requirements/skills/requirement-feasibility-review/references/review-template.md +80 -0
  230. package/plugins/devflow-requirements/skills/workflow-demand-clarify/SKILL.md +325 -0
  231. package/plugins/devflow-requirements/skills/workflow-domain-modeling/SKILL.md +163 -0
  232. package/plugins/devflow-requirements/skills/workflow-requirement-baseline/SKILL.md +748 -0
  233. package/plugins/devflow-requirements/skills/workflow-requirement-baseline/assets/baseline-template.md +281 -0
  234. package/plugins/devflow-requirements/skills/workflow-requirement-baseline/references/antipatterns.md +69 -0
  235. package/plugins/devflow-requirements/skills/workflow-requirement-baseline/references/challenge-review-guide.md +158 -0
  236. package/plugins/devflow-requirements/skills/workflow-requirement-baseline/references/decomposition-guide.md +115 -0
  237. package/plugins/devflow-requirements/skills/workflow-requirement-baseline/references/project-context-guide.md +119 -0
  238. package/plugins/devflow-requirements/skills/workflow-requirement-baseline/references/questioning.md +76 -0
  239. package/plugins/devflow-requirements/skills/workflow-requirement-baseline/references/requirement-review-checklist.md +115 -0
  240. package/plugins/devflow-requirements/skills/workflow-requirement-triage/SKILL.md +204 -0
  241. package/plugins/devflow-requirements/skills/workflow-wayfinder/SKILL.md +183 -0
  242. package/src/cli.ts +76 -0
  243. package/src/constants.ts +15 -0
  244. package/src/doctor.ts +66 -0
  245. package/src/paths.ts +37 -0
  246. package/src/platform-extension.ts +46 -0
  247. package/src/project-context.ts +165 -0
  248. package/src/runtime.ts +167 -0
  249. package/src/usage-stats.ts +101 -0
  250. package/templates/commands/start.md +58 -0
  251. package/templates/omp/AGENTS.md +36 -0
  252. package/templates/omp/config.yml +112 -0
  253. package/templates/omp/hook-config.json +18 -0
  254. package/templates/omp/index-policy.json +57 -0
@@ -0,0 +1,565 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "json"
5
+ require "optparse"
6
+ require "yaml"
7
+
8
+ module WorkflowStateValidator
9
+ REQUIRED_STATE_FIELDS = %w[
10
+ current_flow
11
+ current_feature
12
+ current_phase
13
+ current_step
14
+ status
15
+ completed_steps
16
+ pending_steps
17
+ ].freeze
18
+
19
+ TERMINAL_ARTIFACT_STATUSES = %w[approved completed passed].freeze
20
+ NON_TERMINAL_ARTIFACT_STATUSES = %w[planned generated pending_rerun stale failed].freeze
21
+
22
+ module_function
23
+
24
+ def validate(root:, state_path:, state_override: nil, workflow_override: nil, strict_artifact_status: true, strict_registry_revision: true)
25
+ root = File.expand_path(root)
26
+ state_path = File.expand_path(state_path, root)
27
+ issues = []
28
+
29
+ state = state_override || load_state(state_path, issues)
30
+ return result(false, state_path, nil, nil, issues) unless state
31
+
32
+ REQUIRED_STATE_FIELDS.each do |field|
33
+ issues << issue("error", "missing_state_field", "STATE.md is missing required field: #{field}", field: field) unless state.key?(field)
34
+ end
35
+ return result(false, state_path, nil, nil, issues) if issues.any? { |entry| entry["severity"] == "error" }
36
+
37
+ workflow_path = state["workflow_config"] || File.join(".planning", "workflows", "#{state.fetch("current_flow")}.yaml")
38
+ abs_workflow_path = File.expand_path(workflow_path, root)
39
+ workflow = workflow_override || load_yaml(abs_workflow_path, issues, "workflow_config")
40
+ return result(false, state_path, workflow_path, nil, issues) unless workflow
41
+
42
+ registry_path = workflow.dig("artifact_registry", "source")
43
+ artifact_by_path = load_artifacts(
44
+ root,
45
+ registry_path,
46
+ issues,
47
+ state_revision: state.fetch("revision", 0),
48
+ strict_registry_revision: strict_registry_revision
49
+ )
50
+
51
+ steps = Array(workflow["steps"])
52
+ step_by_id = steps.to_h { |step| [step.fetch("id"), step] }
53
+ step_ids = steps.map { |step| step.fetch("id") }
54
+ completed_ids = Array(state["completed_steps"])
55
+ pending_ids = Array(state["pending_steps"])
56
+ tracked_ids = completed_ids + pending_ids
57
+
58
+ validate_step_tracking(issues, state, step_ids, completed_ids, pending_ids, tracked_ids)
59
+ validate_track_scope(issues, state, completed_ids)
60
+ validate_dependencies(issues, step_by_id, completed_ids)
61
+ validate_completed_outputs(issues, root, state, step_by_id, completed_ids, artifact_by_path, strict_artifact_status)
62
+ validate_waiting_checkpoint(issues, root, state, step_by_id, artifact_by_path, strict_artifact_status)
63
+
64
+ ok = issues.none? { |entry| entry["severity"] == "error" }
65
+ result(ok, state_path, workflow_path, registry_path, issues)
66
+ end
67
+
68
+ def load_state(path, issues)
69
+ unless File.exist?(path)
70
+ issues << issue("error", "missing_state_file", "STATE.md does not exist", path: path)
71
+ return nil
72
+ end
73
+
74
+ doc = File.read(path)
75
+ yaml = doc.match(/\A---\n(.*?)\n---\n/m)&.[](1)
76
+ unless yaml
77
+ issues << issue("error", "missing_state_front_matter", "STATE.md is missing YAML front matter", path: path)
78
+ return nil
79
+ end
80
+
81
+ YAML.safe_load(yaml, permitted_classes: [], aliases: false)
82
+ rescue Psych::SyntaxError => e
83
+ issues << issue("error", "invalid_state_yaml", e.message, path: path)
84
+ nil
85
+ end
86
+
87
+ def load_yaml(path, issues, code)
88
+ unless File.exist?(path)
89
+ issues << issue("error", "missing_#{code}", "YAML file does not exist", path: path)
90
+ return nil
91
+ end
92
+
93
+ YAML.safe_load(File.read(path), permitted_classes: [], aliases: false)
94
+ rescue Psych::SyntaxError => e
95
+ issues << issue("error", "invalid_#{code}", e.message, path: path)
96
+ nil
97
+ end
98
+
99
+ def load_artifacts(root, registry_path, issues, state_revision:, strict_registry_revision:)
100
+ return {} unless registry_path
101
+
102
+ abs_registry_path = File.expand_path(registry_path, root)
103
+ unless File.exist?(abs_registry_path)
104
+ issues << issue("error", "missing_artifact_registry", "Artifact registry does not exist", path: registry_path)
105
+ return {}
106
+ end
107
+
108
+ registry = YAML.safe_load(File.read(abs_registry_path), permitted_classes: [], aliases: false)
109
+ if strict_registry_revision && registry.key?("state_revision") && Integer(registry["state_revision"]) != Integer(state_revision)
110
+ issues << issue(
111
+ "error",
112
+ "artifact_registry_revision_mismatch",
113
+ "Artifact registry was derived from a different state revision",
114
+ state_revision: state_revision,
115
+ registry_revision: registry["state_revision"]
116
+ )
117
+ end
118
+ Array(registry["artifacts"]).to_h { |artifact| [artifact.fetch("path"), artifact] }
119
+ rescue ArgumentError, TypeError, Psych::SyntaxError => e
120
+ issues << issue("error", "invalid_artifact_registry", e.message, path: registry_path)
121
+ {}
122
+ end
123
+
124
+ def validate_step_tracking(issues, state, step_ids, completed_ids, pending_ids, tracked_ids)
125
+ duplicate_completed = duplicates(completed_ids)
126
+ duplicate_pending = duplicates(pending_ids)
127
+ overlap = completed_ids & pending_ids
128
+ unknown = tracked_ids.uniq - step_ids
129
+ missing = step_ids - tracked_ids.uniq
130
+
131
+ duplicate_completed.each do |step_id|
132
+ issues << issue("error", "duplicate_completed_step", "Step is duplicated in completed_steps", step: step_id)
133
+ end
134
+ duplicate_pending.each do |step_id|
135
+ issues << issue("error", "duplicate_pending_step", "Step is duplicated in pending_steps", step: step_id)
136
+ end
137
+ overlap.each do |step_id|
138
+ issues << issue("error", "step_in_completed_and_pending", "Step appears in both completed_steps and pending_steps", step: step_id)
139
+ end
140
+ unknown.each do |step_id|
141
+ issues << issue("error", "unknown_tracked_step", "Tracked step is not defined in the active workflow", step: step_id)
142
+ end
143
+ missing.each do |step_id|
144
+ issues << issue("error", "missing_tracked_step", "Workflow step is missing from both completed_steps and pending_steps", step: step_id)
145
+ end
146
+
147
+ current_step = state["current_step"]
148
+ if current_step && !step_ids.include?(current_step)
149
+ issues << issue("error", "unknown_current_step", "current_step is not defined in the active workflow", step: current_step)
150
+ end
151
+
152
+ if state["status"] == "completed"
153
+ if pending_ids.any?
154
+ issues << issue("error", "completed_with_pending_steps", "Workflow status is completed but pending_steps is not empty")
155
+ end
156
+ missing_completed = step_ids - completed_ids
157
+ missing_completed.each do |step_id|
158
+ issues << issue("error", "completed_status_missing_step", "Workflow status is completed but a workflow step is not completed", step: step_id)
159
+ end
160
+ elsif pending_ids.empty?
161
+ issues << issue("error", "non_completed_without_pending_steps", "Workflow has no pending steps but status is not completed")
162
+ end
163
+ end
164
+
165
+ def validate_dependencies(issues, step_by_id, completed_ids)
166
+ completed_ids.each do |step_id|
167
+ step = step_by_id[step_id]
168
+ next unless step
169
+
170
+ Array(step["depends_on"]).each do |dependency|
171
+ next if completed_ids.include?(dependency)
172
+
173
+ issues << issue(
174
+ "error",
175
+ "completed_step_missing_dependency",
176
+ "Completed step depends on an incomplete step",
177
+ step: step_id,
178
+ dependency: dependency
179
+ )
180
+ end
181
+ end
182
+ end
183
+
184
+ def validate_completed_outputs(issues, root, state, step_by_id, completed_ids, artifact_by_path, strict_artifact_status)
185
+ completed_ids.each do |step_id|
186
+ step = step_by_id[step_id]
187
+ next unless step
188
+
189
+ validate_step_outputs(issues, root, state, step, artifact_by_path, strict_artifact_status, waiting_checkpoint_step?(state, step_id))
190
+ validate_meta_output(issues, root, state, step)
191
+ end
192
+ end
193
+
194
+ def validate_waiting_checkpoint(issues, root, state, step_by_id, artifact_by_path, strict_artifact_status)
195
+ return unless state["status"] == "waiting_checkpoint"
196
+
197
+ step = step_by_id[state["current_step"]]
198
+ unless step
199
+ issues << issue("error", "waiting_checkpoint_unknown_step", "Waiting checkpoint current_step is unknown", step: state["current_step"])
200
+ return
201
+ end
202
+
203
+ unless step["checkpoint"]
204
+ issues << issue("error", "waiting_checkpoint_without_step_checkpoint", "State is waiting_checkpoint but current step has no checkpoint", step: step["id"])
205
+ end
206
+
207
+ validate_step_outputs(issues, root, state, step, artifact_by_path, strict_artifact_status, true)
208
+ end
209
+
210
+ def validate_step_outputs(issues, root, state, step, artifact_by_path, strict_artifact_status, waiting_checkpoint)
211
+ Array(step["outputs"]).each do |output|
212
+ next unless output["required"]
213
+
214
+ path = interpolate_path(output.fetch("path"), state)
215
+ abs = File.expand_path(path, root)
216
+ unless File.exist?(abs)
217
+ issues << issue("error", "missing_required_output", "Completed step required output is missing", step: step["id"], path: path)
218
+ next
219
+ end
220
+
221
+ artifact = artifact_by_path[path]
222
+ if artifact.nil?
223
+ issues << issue("error", "output_not_registered", "Completed step output is not registered in artifact registry", step: step["id"], path: path)
224
+ next
225
+ end
226
+
227
+ if artifact["content_valid"] == false
228
+ issues << issue("error", "invalid_registered_output", "Artifact registry marks output content as invalid", step: step["id"], path: path, content_issues: artifact["content_issues"])
229
+ end
230
+
231
+ next unless strict_artifact_status
232
+
233
+ status = artifact["status"]
234
+ allowed = waiting_checkpoint ? (TERMINAL_ARTIFACT_STATUSES + ["generated"]) : TERMINAL_ARTIFACT_STATUSES
235
+ next if allowed.include?(status)
236
+
237
+ code = NON_TERMINAL_ARTIFACT_STATUSES.include?(status) ? "non_terminal_artifact_status" : "unknown_artifact_status"
238
+ issues << issue("error", code, "Completed step output has a non-terminal artifact status", step: step["id"], path: path, status: status)
239
+ end
240
+ end
241
+
242
+ def validate_meta_output(issues, root, state, step)
243
+ meta = step["meta_output"]
244
+ return unless meta
245
+
246
+ path = interpolate_path(meta.fetch("path"), state)
247
+ abs = File.expand_path(path, root)
248
+ unless File.exist?(abs)
249
+ issues << issue("error", "missing_meta_output", "Completed step meta_output is missing", step: step["id"], path: path)
250
+ return
251
+ end
252
+
253
+ data = JSON.parse(File.read(abs))
254
+ Array(meta["fields"]).each do |field, config|
255
+ next unless config.is_a?(Hash) && config["required"]
256
+ next if data.key?(field) && !data[field].nil?
257
+
258
+ issues << issue("error", "missing_meta_field", "Completed step meta_output is missing a required field", step: step["id"], path: path, field: field)
259
+ end
260
+
261
+ validate_requirement_triage_gate(issues, step, data)
262
+ validate_requirement_wayfinder_gate(issues, step, data)
263
+ validate_domain_modeling_gate(issues, step, data)
264
+ validate_requirement_feasibility_review_gate(issues, step, data)
265
+ validate_requirement_baseline_gate(issues, step, data)
266
+ validate_api_contract_gate(issues, step, data)
267
+ validate_api_call_guide_gate(issues, step, data)
268
+ validate_frontend_tech_spec_gate(issues, step, data)
269
+ validate_api_supplement_gate(issues, step, data)
270
+ validate_integration_merge_gate(issues, step, data)
271
+ validate_verification_gate(issues, step, data)
272
+ rescue JSON::ParserError => e
273
+ issues << issue("error", "invalid_meta_json", e.message, step: step["id"], path: path)
274
+ end
275
+
276
+ def validate_requirement_triage_gate(issues, step, data)
277
+ return unless step["id"] == "requirement-triage"
278
+
279
+ allowed_statuses = %w[checked routed blocked superseded]
280
+ unless allowed_statuses.include?(data["status"].to_s)
281
+ issues << issue("error", "triage_invalid_status", "Requirement triage meta status is invalid", step: step["id"], status: data["status"])
282
+ end
283
+
284
+ allowed_routes = %w[
285
+ ready_for_wayfinder
286
+ ready_for_baseline
287
+ needs_demand_clarify
288
+ needs_wayfinder
289
+ needs_info
290
+ ready_for_human
291
+ already_done
292
+ wontfix
293
+ ]
294
+ unless allowed_routes.include?(data["route"].to_s)
295
+ issues << issue("error", "triage_invalid_route", "Requirement triage meta route is invalid", step: step["id"], route: data["route"])
296
+ end
297
+
298
+ return if data["status"] == "routed" && data["route"] == "ready_for_wayfinder"
299
+
300
+ issues << issue(
301
+ "error",
302
+ "triage_not_ready_for_wayfinder",
303
+ "Requirement triage can only complete when status=routed and route=ready_for_wayfinder",
304
+ step: step["id"],
305
+ status: data["status"],
306
+ route: data["route"]
307
+ )
308
+ end
309
+
310
+ def validate_requirement_wayfinder_gate(issues, step, data)
311
+ return unless step["id"] == "requirement-wayfinder"
312
+
313
+ return if data["status"] == "ready_for_baseline" && data["ready_for_baseline"] == true
314
+
315
+ issues << issue(
316
+ "error",
317
+ "wayfinder_not_ready",
318
+ "Requirement wayfinder can only complete when active-slice fog is resolved",
319
+ step: step["id"],
320
+ status: data["status"],
321
+ ready_for_baseline: data["ready_for_baseline"]
322
+ )
323
+ end
324
+
325
+ def validate_domain_modeling_gate(issues, step, data)
326
+ return unless step["id"] == "domain-modeling"
327
+
328
+ return unless data["feature_name"].to_s.empty?
329
+
330
+ issues << issue(
331
+ "error",
332
+ "domain_model_missing_feature",
333
+ "Domain modeling meta must identify the feature it modeled",
334
+ step: step["id"]
335
+ )
336
+ end
337
+
338
+ def validate_requirement_feasibility_review_gate(issues, step, data)
339
+ return unless step["id"] == "requirement-feasibility-review"
340
+
341
+ pass = data["status"] == "ready_for_baseline" && data["baseline_gate"] == "pass"
342
+ pass &&= data["gap_count"].to_i.zero?
343
+ pass &&= Array(data["critical_finding_ids"]).empty?
344
+ return if pass
345
+
346
+ issues << issue(
347
+ "error",
348
+ "feasibility_review_not_passed",
349
+ "Requirement feasibility review must pass before baseline",
350
+ step: step["id"],
351
+ status: data["status"],
352
+ baseline_gate: data["baseline_gate"],
353
+ gap_count: data["gap_count"],
354
+ critical_finding_ids: data["critical_finding_ids"]
355
+ )
356
+ end
357
+
358
+ def validate_requirement_baseline_gate(issues, step, data)
359
+ return unless step["id"] == "requirement-baseline"
360
+
361
+ if data["review_status"] != "passed"
362
+ issues << issue("error", "baseline_review_not_passed", "Requirement baseline meta review_status is not passed", step: step["id"], status: data["review_status"])
363
+ end
364
+
365
+ %w[blocking_pending_count critical_image_missing_count challenge_pending_count code_reality_missing_count].each do |field|
366
+ next if data[field].to_i.zero?
367
+
368
+ issues << issue("error", "baseline_blocking_counter_nonzero", "Requirement baseline has a non-zero blocking counter", step: step["id"], field: field, count: data[field])
369
+ end
370
+ end
371
+
372
+ def validate_api_contract_gate(issues, step, data)
373
+ return unless step["id"] == "api-contract"
374
+
375
+ if data["review_status"] != "passed"
376
+ issues << issue("error", "api_contract_review_not_passed", "API contract meta review_status is not passed", step: step["id"], status: data["review_status"])
377
+ end
378
+
379
+ if data["pending_contract_count"].to_i.positive?
380
+ issues << issue("error", "api_contract_pending_items", "API contract has unresolved pending contract items", step: step["id"], count: data["pending_contract_count"])
381
+ end
382
+
383
+ api_required = data["api_required"]
384
+ endpoint_count = data["endpoint_count"].to_i
385
+ if api_required == false && endpoint_count.positive?
386
+ issues << issue("error", "api_contract_noop_with_endpoints", "API contract is marked api_required=false but endpoint_count is greater than zero", step: step["id"], endpoint_count: endpoint_count)
387
+ elsif api_required != false && endpoint_count.zero?
388
+ issues << issue("error", "api_contract_required_without_endpoints", "API contract is marked as required but endpoint_count is zero", step: step["id"])
389
+ end
390
+ end
391
+
392
+ def validate_api_call_guide_gate(issues, step, data)
393
+ return unless step["id"] == "api-call-guide"
394
+
395
+ api_required = data["api_required"]
396
+ if api_required == false
397
+ pending_items = data["pending_items"]
398
+ if pending_items.is_a?(Array) && pending_items.any?
399
+ issues << issue("error", "api_call_guide_noop_pending_items", "No-op API call guide has pending items", step: step["id"], count: pending_items.length)
400
+ end
401
+ return
402
+ end
403
+
404
+ unless data["frontend_consumable"] == true
405
+ issues << issue("error", "api_call_guide_not_frontend_consumable", "API call guide is not marked frontend_consumable", step: step["id"])
406
+ end
407
+
408
+ unless data["mock_ready"] == true
409
+ issues << issue("error", "api_call_guide_mock_not_ready", "API call guide mock_ready is not true", step: step["id"])
410
+ end
411
+
412
+ pending_items = data["pending_items"]
413
+ if pending_items.is_a?(Array) && pending_items.any?
414
+ issues << issue("error", "api_call_guide_pending_items", "API call guide has unresolved pending items", step: step["id"], count: pending_items.length)
415
+ end
416
+ end
417
+
418
+ def validate_frontend_tech_spec_gate(issues, step, data)
419
+ return unless step["id"] == "frontend-tech-spec"
420
+
421
+ if data["api_gaps_count"].to_i.negative?
422
+ issues << issue("error", "frontend_api_gaps_negative", "frontend-tech-spec api_gaps_count cannot be negative", step: step["id"], count: data["api_gaps_count"])
423
+ end
424
+ end
425
+
426
+ def validate_api_supplement_gate(issues, step, data)
427
+ return unless step["id"] == "api-supplement"
428
+
429
+ supplement_count = data["api_supplement_count"].to_i
430
+ unresolved_count = data["unresolved_supplement_count"].to_i
431
+ contract_updated = data["contract_updated"]
432
+ no_supplement_required = data["no_supplement_required"]
433
+
434
+ if no_supplement_required == true
435
+ if supplement_count.positive? || unresolved_count.positive?
436
+ issues << issue("error", "api_supplement_noop_has_items", "No-op API supplement reports supplement items", step: step["id"], api_supplement_count: supplement_count, unresolved_supplement_count: unresolved_count)
437
+ end
438
+ return
439
+ end
440
+
441
+ if unresolved_count.positive?
442
+ issues << issue("error", "api_supplement_unresolved_items", "API supplement has unresolved items", step: step["id"], count: unresolved_count)
443
+ end
444
+
445
+ if supplement_count.positive? && contract_updated != true
446
+ issues << issue("error", "api_supplement_contract_not_updated", "API supplement items exist but contract_updated is not true", step: step["id"])
447
+ end
448
+ end
449
+
450
+ def validate_integration_merge_gate(issues, step, data)
451
+ return unless step["id"] == "integration-verify"
452
+
453
+ api_required = data["api_required"]
454
+ if api_required == false
455
+ unless %w[passed skipped].include?(data["merge_gate_status"])
456
+ issues << issue("error", "merge_gate_noop_invalid_status", "No-op integration merge gate status must be passed or skipped", step: step["id"], status: data["merge_gate_status"])
457
+ end
458
+ elsif data["merge_gate_status"] != "passed"
459
+ issues << issue("error", "merge_gate_not_passed", "Integration merge gate status is not passed", step: step["id"], status: data["merge_gate_status"])
460
+ end
461
+
462
+ %w[
463
+ contract_backend_mismatch_count
464
+ contract_frontend_mismatch_count
465
+ unhandled_api_supplement_count
466
+ blocking_issue_count
467
+ ].each do |field|
468
+ next if data[field].to_i.zero?
469
+
470
+ issues << issue("error", "merge_gate_counter_nonzero", "Integration merge gate has a non-zero blocking counter", step: step["id"], field: field, count: data[field])
471
+ end
472
+ end
473
+
474
+ def validate_verification_gate(issues, step, data)
475
+ return unless step["id"] == "verify"
476
+
477
+ if data["uat_failed"].to_i.positive?
478
+ issues << issue("error", "verification_uat_failed", "Verification meta reports failed UAT items", step: step["id"], count: data["uat_failed"])
479
+ end
480
+
481
+ gate_passed = data["gate_passed"].to_i
482
+ gate_total = data["gate_total"].to_i
483
+ if gate_total.zero?
484
+ issues << issue("error", "verification_gate_total_zero", "Verification meta gate_total must be greater than zero", step: step["id"])
485
+ elsif gate_passed != gate_total
486
+ issues << issue("error", "verification_gates_not_all_passed", "Verification meta reports incomplete gates", step: step["id"], gate_passed: gate_passed, gate_total: gate_total)
487
+ end
488
+ end
489
+
490
+ def validate_track_scope(issues, state, completed_ids)
491
+ track = state["active_track"].to_s
492
+ return unless %w[A B].include?(track)
493
+
494
+ allowed = case track
495
+ when "A"
496
+ %w[requirement-triage requirement-wayfinder domain-modeling requirement-feasibility-review requirement-baseline api-contract backend-tech-spec api-call-guide]
497
+ when "B"
498
+ %w[requirement-triage requirement-wayfinder domain-modeling requirement-feasibility-review requirement-baseline api-contract ui-spec feature-breakdown frontend-tech-spec api-supplement]
499
+ end
500
+
501
+ illegal = completed_ids - allowed
502
+ illegal.each do |step_id|
503
+ issues << issue(
504
+ "error",
505
+ "active_track_completed_out_of_scope_step",
506
+ "Single-track mode cannot complete steps outside its output scope",
507
+ active_track: track,
508
+ step: step_id
509
+ )
510
+ end
511
+ end
512
+
513
+ def waiting_checkpoint_step?(state, step_id)
514
+ state["status"] == "waiting_checkpoint" && state["current_step"] == step_id
515
+ end
516
+
517
+ def interpolate_path(path, state)
518
+ path
519
+ .gsub("{feature}", state.fetch("current_feature", "").to_s)
520
+ .gsub("{phase}", state.fetch("current_phase", "").to_s)
521
+ end
522
+
523
+ def duplicates(values)
524
+ values.each_with_object(Hash.new(0)) { |value, counts| counts[value] += 1 }
525
+ .select { |_, count| count > 1 }
526
+ .keys
527
+ end
528
+
529
+ def issue(severity, code, message, details = {})
530
+ { "severity" => severity, "code" => code, "message" => message }.merge(details.transform_keys(&:to_s))
531
+ end
532
+
533
+ def result(ok, state_path, workflow_path, registry_path, issues)
534
+ {
535
+ "ok" => ok,
536
+ "state_path" => state_path,
537
+ "workflow_path" => workflow_path,
538
+ "artifact_registry_path" => registry_path,
539
+ "errors" => issues.select { |entry| entry["severity"] == "error" },
540
+ "warnings" => issues.select { |entry| entry["severity"] == "warning" },
541
+ "issues" => issues
542
+ }
543
+ end
544
+ end
545
+
546
+ if __FILE__ == $PROGRAM_NAME
547
+ options = { state: ".planning/STATE.md", strict_artifact_status: true, json: false }
548
+ OptionParser.new do |opts|
549
+ opts.banner = "Usage: validate_state.rb [--state PATH] [--no-strict-artifact-status] [--json]"
550
+ opts.on("--state PATH", "STATE.md path") { |path| options[:state] = path }
551
+ opts.on("--no-strict-artifact-status", "Do not require terminal artifact statuses") { options[:strict_artifact_status] = false }
552
+ opts.on("--json", "Print JSON output") { options[:json] = true }
553
+ end.parse!
554
+
555
+ root = Dir.pwd
556
+ state_path = File.expand_path(options[:state], root)
557
+ validation = WorkflowStateValidator.validate(
558
+ root: root,
559
+ state_path: state_path,
560
+ strict_artifact_status: options[:strict_artifact_status]
561
+ )
562
+
563
+ puts JSON.pretty_generate(validation)
564
+ exit(validation["ok"] ? 0 : 1)
565
+ end