@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,583 @@
1
+ #!/usr/bin/env python3
2
+ """Compile AI-friendly case descriptions into strict DSL JSON.
3
+
4
+ AI 产出简化的用例描述(locator 用 "type:value" 字符串格式),
5
+ 本脚本负责编译成符合系统 DslTarget 严格格式的 DSL JSON。
6
+ 这是硬约束层 —— 所有 target key、strategy、assertion 由脚本决定,AI 无法编造。
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import argparse
12
+ import json
13
+ import re
14
+ from copy import deepcopy
15
+ from datetime import datetime, timezone
16
+ from pathlib import Path
17
+ from typing import Any
18
+
19
+ # ---------------------------------------------------------------------------
20
+ # 硬约束常量 — 唯一权威定义
21
+ # ---------------------------------------------------------------------------
22
+
23
+ VALID_TARGET_KEYS = {"css", "xpath", "label", "placeholder", "role", "name", "near_text", "exact"}
24
+ EXACT_LOCATOR_KEYS = {"css", "xpath", "role"} # 精确匹配,必须有 source evidence
25
+ SEMANTIC_LOCATOR_KEYS = {"label", "placeholder", "near_text"} # 语义匹配,需检查唯一性
26
+
27
+ # 高风险 label — 表格行常见操作文本,用 label 定位时几乎一定不唯一
28
+ HIGH_RISK_LABELS = {
29
+ "编辑", "删除", "查看", "详情", "启用", "禁用", "停用",
30
+ "新增", "添加", "修改", "复制", "移动", "导出", "导入", "下载",
31
+ "上传", "设置", "配置", "操作", "更多", "取消", "确定", "保存",
32
+ "提交", "重置", "刷新", "搜索", "查询", "筛选", "排序",
33
+ }
34
+
35
+ MIN_CSS_LENGTH = 10
36
+
37
+ DEFAULT_UI_STRATEGY = {"mode": "structured_first", "fallback": "midscene"}
38
+ AI_ONLY_STRATEGY = {"mode": "ai_only"}
39
+
40
+ # ---------------------------------------------------------------------------
41
+ # Locator 字符串解析器
42
+ # ---------------------------------------------------------------------------
43
+
44
+ LOCATOR_RE = re.compile(
45
+ r"^(?P<type>text|placeholder|css|xpath|role|near)"
46
+ r":(?P<value>.+)$"
47
+ )
48
+ ROLE_LOCATOR_RE = re.compile(r"^role:(?P<role>[^:]+):(?P<name>.+)$")
49
+ SCOPE_RE = re.compile(r"^row:(?P<row>\d+)$")
50
+
51
+
52
+ def parse_locator(raw: str) -> dict[str, str]:
53
+ """Parse 'type:value' string into flat target dict.
54
+
55
+ Returns {'label': '...'} for text:, {'placeholder': '...'} for placeholder:, etc.
56
+ Raises ValueError on unrecognized format.
57
+ """
58
+ raw = raw.strip()
59
+
60
+ # role:button:确定
61
+ m = ROLE_LOCATOR_RE.match(raw)
62
+ if m:
63
+ return {"role": m.group("role"), "name": m.group("name")}
64
+
65
+ m = LOCATOR_RE.match(raw)
66
+ if not m:
67
+ raise ValueError(
68
+ f"Invalid locator format: '{raw}'. "
69
+ f"Expected: text:<text> | placeholder:<text> | css:<selector> | "
70
+ f"xpath:<expr> | role:<role>:<name> | near:<text>"
71
+ )
72
+
73
+ loc_type = m.group("type")
74
+ value = m.group("value").strip()
75
+
76
+ if not value:
77
+ raise ValueError(f"Locator '{raw}' has empty value.")
78
+
79
+ if loc_type == "text":
80
+ return {"label": value}
81
+ if loc_type == "placeholder":
82
+ return {"placeholder": value}
83
+ if loc_type == "css":
84
+ return {"css": value}
85
+ if loc_type == "xpath":
86
+ return {"xpath": value}
87
+ if loc_type == "near":
88
+ return {"near_text": value}
89
+
90
+ raise ValueError(f"Unknown locator type: {loc_type}")
91
+
92
+
93
+ # ---------------------------------------------------------------------------
94
+ # CSS 编造检测 — 零容忍
95
+ # ---------------------------------------------------------------------------
96
+
97
+ # 明显是 AI 编造的 CSS class 特征
98
+ HALLUCINATED_CSS_PATTERNS: list[tuple[str, str]] = [
99
+ # 包含 % 的伪 Tailwind class(w-100%, h-50% 等)
100
+ (r"\b[a-z]+-\d+%", "contains invented utility class with % (e.g. w-100%)"),
101
+ # 裸的百分比值
102
+ (r"%", "contains '%' — not valid in CSS selector without escaping"),
103
+ # 纯表单容器通用类,不指定具体字段
104
+ (r"^\.el-form-item(__content)?$", "matches all form items, not a specific field"),
105
+ # 明显编造的随机 class 名模式
106
+ (r"\b[a-z]{1,3}-\d{3,}\b", "looks like a made-up class (random letters+numbers)"),
107
+ ]
108
+
109
+ # fill/select 动作在非 placeholder 情况下,CSS 禁止匹配纯容器类
110
+ GENERIC_FORM_CLASSES = [
111
+ ".el-form-item",
112
+ ".el-form-item__content",
113
+ ".el-form-item__label",
114
+ ".ant-form-item",
115
+ ".ant-form-item-control",
116
+ ".form-item",
117
+ ".form-group",
118
+ ]
119
+
120
+
121
+ def _validate_css_not_hallucinated(css_value: str, step_name: str) -> None:
122
+ """Reject CSS selectors that show signs of AI hallucination. Hard gate."""
123
+ errors: list[str] = []
124
+
125
+ # Check against hallucination patterns
126
+ for pattern, description in HALLUCINATED_CSS_PATTERNS:
127
+ if re.search(pattern, css_value):
128
+ errors.append(
129
+ f"CSS selector '{css_value}' rejected: {description}. "
130
+ f"Step: {step_name}"
131
+ )
132
+
133
+ # Check if CSS is purely generic form classes (no specific target)
134
+ stripped = css_value.strip()
135
+ parts = [p.strip() for p in stripped.split() if p.strip()]
136
+ if parts and all(
137
+ any(p == g or p.startswith(g) for g in GENERIC_FORM_CLASSES)
138
+ for p in parts
139
+ ):
140
+ errors.append(
141
+ f"CSS selector '{css_value}' only matches generic form containers, "
142
+ f"not a specific field. Use 'near:<label文本>' instead. "
143
+ f"Step: {step_name}"
144
+ )
145
+
146
+ # Too short = probably made up
147
+ if len(css_value) < MIN_CSS_LENGTH:
148
+ errors.append(
149
+ f"CSS selector '{css_value}' is too generic ({len(css_value)} chars, min {MIN_CSS_LENGTH}). "
150
+ f"Step: {step_name}"
151
+ )
152
+
153
+ if errors:
154
+ raise ValueError("CSS HALLUCINATION DETECTED:\n" + "\n".join(f" - {e}" for e in errors))
155
+
156
+
157
+ # ---------------------------------------------------------------------------
158
+ # Fill 动作 locator 硬决策链
159
+ # ---------------------------------------------------------------------------
160
+
161
+ FILL_ALLOWED_LOCATORS = {"placeholder", "near"} # fill 只能用这两个
162
+
163
+
164
+ def _validate_fill_locator(step_name: str, locator_raw: str) -> None:
165
+ """Hard decision chain for fill actions: placeholder → near → ai_only. CSS/xpath forbidden."""
166
+ if not locator_raw:
167
+ raise ValueError(
168
+ f"Fill step '{step_name}' has no locator. "
169
+ f"Use 'placeholder:<text>', 'near:<label文本>', or change action to 'act' with ai_only."
170
+ )
171
+
172
+ loc_type = locator_raw.split(":", 1)[0].strip()
173
+ if loc_type not in FILL_ALLOWED_LOCATORS:
174
+ raise ValueError(
175
+ f"Fill step '{step_name}' uses locator type '{loc_type}', which is forbidden for fill actions. "
176
+ f"Fill hard chain: placeholder → near → ai_only. "
177
+ f"Got '{locator_raw}'. "
178
+ f"Use 'placeholder:<text>' if the field has a placeholder, "
179
+ f"'near:<label文本>' if there's a label next to the field, "
180
+ f"or change action to 'act' with ai_only strategy."
181
+ )
182
+
183
+
184
+ # ---------------------------------------------------------------------------
185
+ # Target 编译 — 硬约束规则
186
+ # ---------------------------------------------------------------------------
187
+
188
+ def compile_target(
189
+ locator_raw: str,
190
+ scope: str | None = None,
191
+ step_name: str = "",
192
+ ) -> dict[str, Any]:
193
+ """Compile a locator string + scope into a valid DslTarget dict.
194
+
195
+ Rules (in priority order):
196
+ 1. text:<unique_button> + page scope → label + exact
197
+ 2. text:<common_action> + row:N scope → label + css row selector
198
+ 3. text:<text> + dialog scope → label (dialog内默认唯一)
199
+ 4. placeholder:<text> → placeholder
200
+ 5. css:<selector> → css (validated for specificity)
201
+ 6. role:<role>:<name> → role + name
202
+ 7. near:<text> → near_text
203
+ 8. xpath:<expr> → xpath (last resort)
204
+ """
205
+ target = parse_locator(locator_raw)
206
+ errors: list[str] = []
207
+
208
+ # text: → label
209
+ if "label" in target:
210
+ label_value = target["label"]
211
+
212
+ # Determine scope
213
+ if scope:
214
+ scope_match = SCOPE_RE.match(scope)
215
+ if scope_match:
216
+ # row scope: label + css row selector
217
+ row_n = int(scope_match.group("row"))
218
+ target["css"] = (
219
+ f".el-table__body tr:nth-child({row_n}) "
220
+ f"td:last-child .el-button--small"
221
+ )
222
+ elif scope == "dialog":
223
+ # dialog scope: label within dialog, no extra css needed
224
+ pass
225
+ # other scopes just use label as-is
226
+
227
+ # exact match for page-unique items
228
+ if label_value not in HIGH_RISK_LABELS:
229
+ target["exact"] = True
230
+
231
+ # High-risk label without row scope → warn but don't block
232
+ if label_value in HIGH_RISK_LABELS and not (scope and SCOPE_RE.match(scope)):
233
+ # Still produce valid target, but record warning
234
+ pass
235
+
236
+ # css: → hard hallucination check
237
+ if "css" in target:
238
+ css_value = target["css"]
239
+ _validate_css_not_hallucinated(css_value, step_name)
240
+
241
+ # role: → ensure name is present (already handled by parse_locator)
242
+
243
+ if errors:
244
+ raise ValueError("\n".join(errors))
245
+
246
+ return target
247
+
248
+
249
+ # ---------------------------------------------------------------------------
250
+ # Strategy 决策 — 硬约束
251
+ # ---------------------------------------------------------------------------
252
+
253
+ VERIFICATION_ACTIONS = {"verify", "assert_text", "assert_visible", "assert_url_contains", "assert_any_visible"}
254
+
255
+
256
+ def compile_strategy(action: str) -> dict[str, Any]:
257
+ """Decide strategy based on action type. Hard rule: verification → ai_only."""
258
+ if action in VERIFICATION_ACTIONS:
259
+ return deepcopy(AI_ONLY_STRATEGY)
260
+ if action == "act":
261
+ return deepcopy(AI_ONLY_STRATEGY)
262
+ return deepcopy(DEFAULT_UI_STRATEGY)
263
+
264
+
265
+ # ---------------------------------------------------------------------------
266
+ # Step 编译
267
+ # ---------------------------------------------------------------------------
268
+
269
+ def compile_step(step: dict[str, Any], index: int) -> dict[str, Any]:
270
+ """Compile one simplified step into strict DSL step."""
271
+ name = str(step.get("name") or f"Step {index}")
272
+ action = str(step.get("action") or "").lower().strip()
273
+
274
+ compiled: dict[str, Any] = {
275
+ "id": f"s{index:02d}",
276
+ "name": name,
277
+ "depends_on": [],
278
+ "timeout_ms": int(step.get("timeout_ms", 30_000)),
279
+ "on_failure": step.get("on_failure", "stop"),
280
+ }
281
+
282
+ # --- Navigate → web/goto ---
283
+ if action == "navigate":
284
+ compiled["driver"] = "web"
285
+ compiled["action"] = "goto"
286
+ compiled["params"] = {"url": step.get("url", "")}
287
+ return compiled
288
+
289
+ # --- Wait ---
290
+ if action == "wait":
291
+ compiled["driver"] = "web"
292
+ compiled["action"] = "wait"
293
+ compiled["params"] = {"wait_for": step.get("wait_for", "load")}
294
+ compiled["timeout_ms"] = int(step.get("timeout_ms", 15_000))
295
+ return compiled
296
+
297
+ # --- Inject token ---
298
+ if action == "inject_token":
299
+ compiled["driver"] = "web"
300
+ compiled["action"] = "evaluate_js"
301
+ compiled["params"] = {"script": step.get("script", "")}
302
+ return compiled
303
+
304
+ # --- API step ---
305
+ if action in {"get", "post", "put", "patch", "delete"}:
306
+ compiled["driver"] = "api"
307
+ compiled["action"] = action
308
+ compiled["params"] = deepcopy(step.get("params", {}))
309
+ compiled["assertions"] = _compile_api_assertions(step.get("assertions", []))
310
+ compiled["extract_vars"] = deepcopy(step.get("extract_vars", {}))
311
+ return compiled
312
+
313
+ # --- UI action steps ---
314
+ if action in {"click", "fill", "select", "hover"}:
315
+ compiled["driver"] = "ui"
316
+ compiled["action"] = action
317
+ locator_raw = step.get("locator", "")
318
+ if locator_raw:
319
+ compiled["target"] = compile_target(
320
+ locator_raw,
321
+ scope=step.get("scope"),
322
+ step_name=name,
323
+ )
324
+ compiled["strategy"] = compile_strategy(action)
325
+ if action == "fill":
326
+ compiled["params"] = {"value": step.get("value", "")}
327
+ _validate_fill_locator(name, locator_raw)
328
+ return compiled
329
+
330
+ # --- UI verification step ---
331
+ if action == "verify":
332
+ compiled["driver"] = "ui"
333
+ compiled["action"] = "act"
334
+ locator_raw = step.get("locator", "")
335
+ if locator_raw:
336
+ compiled["target"] = compile_target(locator_raw, scope=step.get("scope"), step_name=name)
337
+ compiled["strategy"] = deepcopy(AI_ONLY_STRATEGY)
338
+ expect = step.get("expect", "")
339
+ compiled["prompt"] = _build_verify_prompt(name, expect, step)
340
+ compiled["timeout_ms"] = int(step.get("timeout_ms", 15_000))
341
+ return compiled
342
+
343
+ # --- AI act step (with prompt) ---
344
+ if action == "act":
345
+ compiled["driver"] = "ui"
346
+ compiled["action"] = "act"
347
+ locator_raw = step.get("locator", "")
348
+ if locator_raw:
349
+ compiled["target"] = compile_target(locator_raw, scope=step.get("scope"), step_name=name)
350
+ compiled["strategy"] = deepcopy(AI_ONLY_STRATEGY)
351
+ compiled["prompt"] = step.get("prompt", "")
352
+ compiled["timeout_ms"] = int(step.get("timeout_ms", 15_000))
353
+ return compiled
354
+
355
+ # Fallback
356
+ raise ValueError(f"Unknown action '{action}' in step '{name}'")
357
+
358
+
359
+ def _compile_api_assertions(raw_assertions: list[dict[str, Any]]) -> list[dict[str, Any]]:
360
+ """Compile simplified API assertions into strict format."""
361
+ compiled: list[dict[str, Any]] = []
362
+ for a in raw_assertions:
363
+ atype = str(a.get("type", "status_code"))
364
+ compiled.append({
365
+ "type": atype,
366
+ "expected": a.get("expected"),
367
+ "path": a.get("path"),
368
+ })
369
+ return compiled
370
+
371
+
372
+ def _build_verify_prompt(step_name: str, expect: str, step: dict[str, Any]) -> str:
373
+ """Build AI prompt for verification step."""
374
+ if step.get("prompt"):
375
+ return step["prompt"]
376
+ if expect.startswith("text:"):
377
+ text = expect[5:]
378
+ return f"检查页面是否出现'{text}'的提示消息,确认操作已成功完成"
379
+ if expect == "dialog_visible":
380
+ return "检查对话框是否已打开并显示"
381
+ if expect == "dialog_closed":
382
+ return "检查对话框是否已关闭"
383
+ return f"验证:{expect}"
384
+
385
+
386
+ # ---------------------------------------------------------------------------
387
+ # Auth setup 编译
388
+ # ---------------------------------------------------------------------------
389
+
390
+ def compile_auth_steps(auth: dict[str, Any] | None, base_url: str = "${base_url}") -> list[dict[str, Any]]:
391
+ """Compile auth config into API login + web inject steps."""
392
+ if not auth:
393
+ return []
394
+
395
+ method = str(auth.get("method", "")).lower()
396
+ steps: list[dict[str, Any]] = []
397
+
398
+ if method == "api_login":
399
+ login_url = auth.get("login_url", f"{base_url}/auth/login_by_id")
400
+ login_body = auth.get("login_body", {})
401
+ token_path = auth.get("token_path", "headers.X-Jwt-Token")
402
+ app_id = auth.get("app_id")
403
+
404
+ steps.append({
405
+ "id": "api_auth_login",
406
+ "name": "获取JWT令牌",
407
+ "driver": "api",
408
+ "action": "post",
409
+ "params": {"url": login_url, "json": login_body},
410
+ "assertions": [
411
+ {"type": "status_code", "expected": 200},
412
+ {"type": "json_path_exists", "path": token_path},
413
+ ],
414
+ "extract_vars": {"jwt_token": {"path": token_path, "source": "jsonpath"}},
415
+ "depends_on": [],
416
+ "timeout_ms": 15_000,
417
+ "on_failure": "stop",
418
+ })
419
+
420
+ if app_id:
421
+ steps.append({
422
+ "id": "api_app_token",
423
+ "name": "获取应用访问Token",
424
+ "driver": "api",
425
+ "action": "post",
426
+ "params": {
427
+ "url": auth.get("app_token_url", f"{base_url}/admin/app/access"),
428
+ "json": {"id": app_id},
429
+ "headers": {"Authorization": "Bearer ${jwt_token}"},
430
+ },
431
+ "assertions": [{"type": "status_code", "expected": 200}],
432
+ "extract_vars": {"token_url": {"path": "body.data.url", "source": "jsonpath"}},
433
+ "depends_on": ["api_auth_login"],
434
+ "timeout_ms": 15_000,
435
+ "on_failure": "stop",
436
+ })
437
+
438
+ steps.append({
439
+ "id": "web_auth_inject",
440
+ "name": "Token注入",
441
+ "driver": "web",
442
+ "action": "goto",
443
+ "params": {"url": "${token_url}"},
444
+ "depends_on": ["api_app_token"],
445
+ "timeout_ms": 30_000,
446
+ "on_failure": "stop",
447
+ })
448
+
449
+ return steps
450
+
451
+
452
+ # ---------------------------------------------------------------------------
453
+ # Main compile entry
454
+ # ---------------------------------------------------------------------------
455
+
456
+ def _check_terminology(steps: list[dict[str, Any]]) -> list[str]:
457
+ """Check for terminology hallucination in step names vs locator values."""
458
+ # Commonly hallucinated term pairs: (AI-invented, source-code-actual)
459
+ TERM_PAIRS: list[tuple[str, str]] = [
460
+ ("搜索", "查询"),
461
+ ("搜索", "筛选"),
462
+ ("新增", "添加"),
463
+ ("编辑", "修改"),
464
+ ("删除", "移除"),
465
+ ("保存", "提交"),
466
+ ("关闭", "取消"),
467
+ ]
468
+ warnings: list[str] = []
469
+ for step in steps:
470
+ name = str(step.get("name", ""))
471
+ locator_raw = str(step.get("_locator_raw", ""))
472
+ for ai_term, src_term in TERM_PAIRS:
473
+ if ai_term in name and src_term in locator_raw:
474
+ warnings.append(
475
+ f"Step '{name}' uses '{ai_term}' but locator contains '{src_term}'. "
476
+ f"Verify the button text in source code — use the exact source text."
477
+ )
478
+ return warnings
479
+
480
+
481
+ def compile_case(case_desc: dict[str, Any]) -> dict[str, Any]:
482
+ """Compile one simplified case description into strict DSL."""
483
+ name = str(case_desc.get("name") or "Unnamed Case")
484
+ tags = list(case_desc.get("tags") or ["ui-mainflow"])
485
+ variables = dict(case_desc.get("variables") or {})
486
+ base_url = variables.get("base_url", "${base_url}")
487
+
488
+ # Compile auth
489
+ auth_steps = compile_auth_steps(case_desc.get("auth"), base_url)
490
+
491
+ # Compile business steps
492
+ raw_steps = list(case_desc.get("steps") or [])
493
+ business_steps: list[dict[str, Any]] = []
494
+ for i, raw_step in enumerate(raw_steps):
495
+ compiled_step = compile_step(raw_step, i + 1)
496
+ # Preserve original locator string for terminology checking
497
+ compiled_step["_locator_raw"] = raw_step.get("locator", "")
498
+ business_steps.append(compiled_step)
499
+
500
+ # Terminology check (warning, not error)
501
+ term_warnings = _check_terminology(business_steps)
502
+ if term_warnings:
503
+ for w in term_warnings:
504
+ print(f"TERMINOLOGY WARNING: {w}", file=__import__("sys").stderr)
505
+
506
+ # Merge: auth steps first, then business steps
507
+ all_steps = auth_steps + business_steps
508
+
509
+ # Wire dependencies: auth steps are already wired; business steps depend on previous
510
+ first_business_idx = len(auth_steps)
511
+ for i, step in enumerate(all_steps):
512
+ if i >= first_business_idx and i > 0:
513
+ prev_id = all_steps[i - 1]["id"]
514
+ if not step.get("depends_on"):
515
+ step["depends_on"] = [prev_id]
516
+
517
+ dsl = {
518
+ "name": name,
519
+ "description": case_desc.get("description", ""),
520
+ "tags": tags,
521
+ "variables": variables,
522
+ "steps": all_steps,
523
+ }
524
+
525
+ return {
526
+ "project_id": int(case_desc.get("project_id", 1)),
527
+ "name": name,
528
+ "description": case_desc.get("description", ""),
529
+ "tags": tags,
530
+ "dsl_json": dsl,
531
+ }
532
+
533
+
534
+ def compile_all(payload: dict[str, Any]) -> dict[str, Any]:
535
+ """Compile all cases in the payload."""
536
+ metadata = dict(payload.get("metadata") or {})
537
+ cases = [compile_case(c) for c in payload.get("cases", [])]
538
+
539
+ return {
540
+ "metadata": {
541
+ **metadata,
542
+ "compiled_at": datetime.now(timezone.utc).isoformat(),
543
+ "compiled_by": "compile_dsl.py (hard-constraint layer)",
544
+ },
545
+ "cases": cases,
546
+ }
547
+
548
+
549
+ # ---------------------------------------------------------------------------
550
+ # CLI
551
+ # ---------------------------------------------------------------------------
552
+
553
+ def main() -> int:
554
+ parser = argparse.ArgumentParser(
555
+ description="Compile AI-friendly case descriptions into strict DSL JSON."
556
+ )
557
+ parser.add_argument("input", help="Simplified case descriptions JSON")
558
+ parser.add_argument("--output", required=True, help="Output path for case-import-payloads.json")
559
+ args = parser.parse_args()
560
+
561
+ input_path = Path(args.input)
562
+ output_path = Path(args.output)
563
+
564
+ raw = json.loads(input_path.read_text(encoding="utf-8"))
565
+
566
+ # Accept both array and {cases: [...]} format
567
+ if isinstance(raw, list):
568
+ raw = {"metadata": {}, "cases": raw}
569
+
570
+ try:
571
+ result = compile_all(raw)
572
+ except ValueError as exc:
573
+ print(f"COMPILE ERROR: {exc}", file=__import__("sys").stderr)
574
+ return 1
575
+
576
+ output_path.parent.mkdir(parents=True, exist_ok=True)
577
+ output_path.write_text(json.dumps(result, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
578
+ print(json.dumps({"output": str(output_path), "case_count": len(result["cases"])}, ensure_ascii=False))
579
+ return 0
580
+
581
+
582
+ if __name__ == "__main__":
583
+ raise SystemExit(main())