ai-delivery-workflow 0.3.0 → 0.4.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 (360) hide show
  1. package/README.md +40 -14
  2. package/bin/ai-delivery.mjs +181 -6
  3. package/bin/benchmark-autonomy.mjs +14 -6
  4. package/bin/release-check.mjs +2 -1
  5. package/docs/CLI-PARAMETER-REFERENCE.zh-CN.md +159 -17
  6. package/docs/CODEGRAPH-INTEGRATION.zh-CN.md +89 -0
  7. package/docs/DUAL-REPOSITORY-WORKSPACE.zh-CN.md +2 -2
  8. package/docs/EVOLUTION-MAINTENANCE.zh-CN.md +7 -7
  9. package/docs/EVOLUTION-USER-GUIDE.zh-CN.md +2 -2
  10. package/docs/FILE-REFERENCE.zh-CN.md +108 -38
  11. package/docs/MAINTENANCE-VERIFICATION.zh-CN.md +2 -2
  12. package/docs/MOCK-SYSTEM.zh-CN.md +141 -0
  13. package/docs/PROJECT-MANUAL.zh-CN.md +148 -93
  14. package/docs/PROTOTYPE-MIGRATION.zh-CN.md +164 -0
  15. package/docs/STATE-CLI-MAINTENANCE.zh-CN.md +35 -17
  16. package/docs/STATE-CLI-USER-GUIDE.zh-CN.md +115 -39
  17. package/docs/VIEWER-MAINTENANCE.zh-CN.md +101 -324
  18. package/docs/VIEWER-USER-GUIDE.zh-CN.md +68 -190
  19. package/docs/adr/0001-prototype-first-ui-governance.md +3 -0
  20. package/docs/adr/0002-microcks-as-default-mock-system.md +3 -0
  21. package/docs/adr/0003-workflow-manager-governed-control-surface.md +46 -0
  22. package/docs/adr/0004-operational-carbon-visual-standard.md +9 -0
  23. package/docs/adr/0005-prototype-management-as-routed-pages.md +7 -0
  24. package/docs/agents/domain.md +12 -0
  25. package/docs/agents/issue-tracker.md +27 -0
  26. package/docs/agents/triage-labels.md +11 -0
  27. package/docs/agents/workflow-manager-acceptance-matrix.md +93 -0
  28. package/docs/agents/workflow-manager-agent-interface.md +145 -0
  29. package/docs/agents/workflow-manager-current-state.md +205 -0
  30. package/lib/artifact-files.mjs +47 -0
  31. package/lib/codegraph.mjs +405 -0
  32. package/lib/delivery-state.mjs +3079 -198
  33. package/lib/frontend-guard.mjs +288 -0
  34. package/lib/fs-utils.mjs +53 -0
  35. package/lib/history-anchor.mjs +98 -0
  36. package/lib/mock-scenario-pack.mjs +687 -0
  37. package/lib/mock-system.mjs +897 -0
  38. package/lib/npm-package-result.mjs +11 -0
  39. package/lib/png-evidence.mjs +149 -0
  40. package/lib/project-bootstrap.mjs +96 -55
  41. package/lib/project-installer.mjs +1484 -164
  42. package/lib/project-migration.mjs +1193 -0
  43. package/lib/prototype-migration.mjs +713 -0
  44. package/lib/prototype-page-review.mjs +384 -0
  45. package/lib/prototype-review-target.mjs +334 -0
  46. package/lib/prototype-revision.mjs +812 -0
  47. package/lib/stable-value.mjs +15 -0
  48. package/lib/toml-hooks.mjs +69 -0
  49. package/lib/ui-acceptance.mjs +565 -0
  50. package/lib/visual-standard.mjs +232 -0
  51. package/lib/workflow-manager-contracts.mjs +367 -0
  52. package/lib/workflow-manager-facts.mjs +778 -0
  53. package/lib/workflow-manager-governance.mjs +514 -0
  54. package/lib/workflow-manager-mock.mjs +183 -0
  55. package/lib/workflow-manager-prototypes.mjs +1847 -0
  56. package/lib/workflow-manager-public/assets/ibm-plex-mono-latin-400-normal-CvHOgSBP.woff +0 -0
  57. package/lib/workflow-manager-public/assets/ibm-plex-mono-latin-400-normal-DMJ8VG8y.woff2 +0 -0
  58. package/lib/workflow-manager-public/assets/ibm-plex-sans-latin-400-normal-CDDApCn2.woff2 +0 -0
  59. package/lib/workflow-manager-public/assets/ibm-plex-sans-latin-400-normal-CYLoc0-x.woff +0 -0
  60. package/lib/workflow-manager-public/assets/ibm-plex-sans-latin-500-normal-6ng42L7E.woff2 +0 -0
  61. package/lib/workflow-manager-public/assets/ibm-plex-sans-latin-500-normal-BgVn5rGT.woff +0 -0
  62. package/lib/workflow-manager-public/assets/ibm-plex-sans-latin-600-normal-Cu4Hd6ag.woff +0 -0
  63. package/lib/workflow-manager-public/assets/ibm-plex-sans-latin-600-normal-CuJfVYMP.woff2 +0 -0
  64. package/lib/workflow-manager-public/assets/index-Chlg6r8f.css +1 -0
  65. package/lib/workflow-manager-public/assets/index-E-hGB5ZD.js +13 -0
  66. package/lib/workflow-manager-public/fonts/OFL-1.1.txt +90 -0
  67. package/lib/workflow-manager-public/index.html +14 -0
  68. package/lib/workflow-manager-systems.mjs +519 -0
  69. package/lib/workflow-manager-transaction.mjs +397 -0
  70. package/lib/workflow-manager.mjs +745 -0
  71. package/package.json +6 -2
  72. package/skills/ai-delivery-assemble-release/agents/openai.yaml +3 -3
  73. package/skills/ai-delivery-assemble-release/assets/release-material-index.csv +1 -1
  74. package/skills/ai-delivery-assemble-release/assets/version-inclusion.csv +1 -1
  75. package/skills/ai-delivery-bootstrap/SKILL.md +4 -4
  76. package/skills/ai-delivery-bootstrap/agents/openai.yaml +3 -3
  77. package/skills/ai-delivery-bootstrap/references/bootstrap-contract.md +4 -2
  78. package/skills/ai-delivery-checkpoint-task/SKILL.md +17 -3
  79. package/skills/ai-delivery-checkpoint-task/agents/openai.yaml +3 -3
  80. package/skills/ai-delivery-checkpoint-task/assets/runtime-template/task.json +7 -1
  81. package/skills/ai-delivery-checkpoint-task/references/checkpoint-contract.md +22 -8
  82. package/skills/ai-delivery-checkpoint-task/scripts/hook-event.mjs +91 -0
  83. package/skills/ai-delivery-checkpoint-task/scripts/task-state.mjs +1086 -51
  84. package/skills/ai-delivery-close-version/SKILL.md +9 -8
  85. package/skills/ai-delivery-close-version/agents/openai.yaml +3 -3
  86. package/skills/ai-delivery-close-version/assets/version-lineage.yaml +1 -1
  87. package/skills/ai-delivery-close-version/references/version-closeout-contract.md +2 -2
  88. package/skills/ai-delivery-define-product/SKILL.md +8 -4
  89. package/skills/ai-delivery-define-product/agents/openai.yaml +4 -4
  90. package/skills/ai-delivery-define-product/references/product-contract.md +2 -2
  91. package/skills/ai-delivery-deploy-production/agents/openai.yaml +3 -3
  92. package/skills/ai-delivery-design-architecture/SKILL.md +9 -5
  93. package/skills/ai-delivery-design-architecture/assets/architecture-template/prototype-architecture-validation.yaml +16 -16
  94. package/skills/ai-delivery-design-architecture/references/architecture-contract.md +1 -1
  95. package/skills/ai-delivery-design-experience/SKILL.md +36 -30
  96. package/skills/ai-delivery-design-experience/agents/openai.yaml +4 -4
  97. package/skills/ai-delivery-design-experience/assets/experience-template/LEGACY-COMPATIBILITY.md +16 -0
  98. package/skills/ai-delivery-design-experience/assets/experience-template/design-reference-selection.yaml +32 -0
  99. package/skills/ai-delivery-design-experience/assets/experience-template/experience-baseline.yaml +2 -2
  100. package/skills/ai-delivery-design-experience/assets/experience-template/formal-ui-confirmation.yaml +16 -3
  101. package/skills/ai-delivery-design-experience/assets/experience-template/frontend-change-scope.yaml +30 -0
  102. package/skills/ai-delivery-design-experience/assets/experience-template/interaction-contract.csv +1 -1
  103. package/skills/ai-delivery-design-experience/assets/experience-template/mock-admin-export.yaml +8 -0
  104. package/skills/ai-delivery-design-experience/assets/experience-template/mock-scenario-mappings.csv +1 -0
  105. package/skills/ai-delivery-design-experience/assets/experience-template/mock-scenario-pack-request.yaml +24 -0
  106. package/skills/ai-delivery-design-experience/assets/experience-template/product-prototype-reconciliation.yaml +2 -1
  107. package/skills/ai-delivery-design-experience/assets/experience-template/prototype-adjustment-log.csv +1 -1
  108. package/skills/ai-delivery-design-experience/assets/experience-template/prototype-component-bindings.csv +1 -0
  109. package/skills/ai-delivery-design-experience/assets/experience-template/prototype-component-candidates.csv +1 -0
  110. package/skills/ai-delivery-design-experience/assets/experience-template/prototype-components.csv +1 -0
  111. package/skills/ai-delivery-design-experience/assets/experience-template/prototype-confirmation.yaml +18 -18
  112. package/skills/ai-delivery-design-experience/assets/experience-template/prototype-data-contracts.csv +1 -0
  113. package/skills/ai-delivery-design-experience/assets/experience-template/prototype-impact-assessment.yaml +5 -5
  114. package/skills/ai-delivery-design-experience/assets/experience-template/prototype-implementation-bindings.csv +1 -0
  115. package/skills/ai-delivery-design-experience/assets/experience-template/prototype-manifest.yaml +2 -0
  116. package/skills/ai-delivery-design-experience/assets/experience-template/prototype-pages.csv +1 -0
  117. package/skills/ai-delivery-design-experience/assets/experience-template/prototype-product-coverage.csv +1 -1
  118. package/skills/ai-delivery-design-experience/assets/experience-template/prototype-review-comments.csv +1 -1
  119. package/skills/ai-delivery-design-experience/assets/experience-template/prototype-review-decision.yaml +13 -12
  120. package/skills/ai-delivery-design-experience/assets/experience-template/prototype-review-scenes.csv +1 -0
  121. package/skills/ai-delivery-design-experience/assets/experience-template/prototype-review-sessions.csv +1 -1
  122. package/skills/ai-delivery-design-experience/assets/experience-template/prototype-review-unit-pages.csv +1 -0
  123. package/skills/ai-delivery-design-experience/assets/experience-template/prototype-review-units.csv +1 -0
  124. package/skills/ai-delivery-design-experience/assets/experience-template/prototype-revision.yaml +88 -0
  125. package/skills/ai-delivery-design-experience/assets/experience-template/prototype-routes.csv +1 -0
  126. package/skills/ai-delivery-design-experience/assets/experience-template/prototype-set.yaml +2 -0
  127. package/skills/ai-delivery-design-experience/assets/experience-template/prototype-source-inspection-snapshots.csv +1 -0
  128. package/skills/ai-delivery-design-experience/assets/experience-template/prototype-terminals.csv +1 -0
  129. package/skills/ai-delivery-design-experience/assets/experience-template/prototype-tool-candidates.csv +1 -1
  130. package/skills/ai-delivery-design-experience/assets/experience-template/prototype-tool-selection.yaml +2 -3
  131. package/skills/ai-delivery-design-experience/assets/experience-template/prototype-traceability.csv +1 -1
  132. package/skills/ai-delivery-design-experience/assets/experience-template/prototype-trigger-conditions.csv +1 -0
  133. package/skills/ai-delivery-design-experience/assets/experience-template/prototype.yaml +6 -0
  134. package/skills/ai-delivery-design-experience/assets/experience-template/ui-framework-selection.yaml +17 -1
  135. package/skills/ai-delivery-design-experience/assets/experience-template/ui-handoff.yaml +6 -5
  136. package/skills/ai-delivery-design-experience/assets/experience-template/ui-mapping.csv +1 -0
  137. package/skills/ai-delivery-design-experience/assets/experience-template/visual-direction.yaml +4 -0
  138. package/skills/ai-delivery-design-experience/assets/experience-template/visual-reference-manifest.yaml +23 -0
  139. package/skills/ai-delivery-design-experience/assets/experience-template/visual-reference.html +163 -0
  140. package/skills/ai-delivery-design-experience/assets/experience-template/visual-system-confirmation.yaml +11 -0
  141. package/skills/ai-delivery-design-experience/references/experience-contract.md +26 -27
  142. package/skills/ai-delivery-design-experience/references/prototype-management-contract.md +42 -21
  143. package/skills/ai-delivery-design-tests/SKILL.md +13 -7
  144. package/skills/ai-delivery-design-tests/assets/test-design-template/prototype-test-scope.csv +1 -1
  145. package/skills/ai-delivery-design-tests/assets/test-design-template/prototype-test-validation.yaml +17 -16
  146. package/skills/ai-delivery-design-tests/references/test-design-contract.md +7 -5
  147. package/skills/ai-delivery-develop-iteration/SKILL.md +18 -11
  148. package/skills/ai-delivery-develop-iteration/agents/openai.yaml +3 -3
  149. package/skills/ai-delivery-develop-iteration/assets/development-template/candidate-manifest.yaml +36 -0
  150. package/skills/ai-delivery-develop-iteration/assets/development-template/task-prototype-traceability.csv +1 -1
  151. package/skills/ai-delivery-develop-iteration/references/development-contract.md +5 -3
  152. package/skills/ai-delivery-evolve-workflow/agents/openai.yaml +3 -3
  153. package/skills/ai-delivery-execute-test/SKILL.md +6 -2
  154. package/skills/ai-delivery-execute-test/agents/openai.yaml +4 -4
  155. package/skills/ai-delivery-execute-work-package/SKILL.md +10 -3
  156. package/skills/ai-delivery-execute-work-package/agents/openai.yaml +4 -4
  157. package/skills/ai-delivery-execute-work-package/references/work-package-contract.md +1 -1
  158. package/skills/ai-delivery-manage-git/agents/openai.yaml +3 -3
  159. package/skills/ai-delivery-manage-standards/agents/openai.yaml +4 -4
  160. package/skills/ai-delivery-orchestrate/SKILL.md +47 -29
  161. package/skills/ai-delivery-orchestrate/agents/openai.yaml +3 -3
  162. package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/control/migrations/.gitkeep +0 -0
  163. package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/control/repairs/.gitkeep +0 -0
  164. package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/delivery/project.yaml +1 -0
  165. package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/delivery/workflow-state.yaml +2 -0
  166. package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/tools/frontend-guard/frontend-guard.mjs +50 -0
  167. package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/tools/hooks/hook-event.mjs +91 -0
  168. package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/tools/manager/manager.mjs +64 -0
  169. package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/tools/manager/start.cmd +4 -0
  170. package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/tools/manager/start.ps1 +2 -0
  171. package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/tools/{viewer → manager}/start.sh +1 -1
  172. package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/tools/mock/mock.mjs +50 -0
  173. package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/tools/ui-acceptance/ui-acceptance.mjs +37 -0
  174. package/skills/ai-delivery-orchestrate/assets/project-template/AGENTS.md +32 -6
  175. package/skills/ai-delivery-orchestrate/assets/project-template/gitignore.template +1 -0
  176. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/CONTRIBUTING.md +25 -0
  177. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/LICENSE +21 -0
  178. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/README.md +250 -0
  179. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/UPSTREAM.yaml +19 -0
  180. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/airbnb/DESIGN.md +545 -0
  181. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/airbnb/README.md +5 -0
  182. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/airtable/DESIGN.md +554 -0
  183. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/airtable/README.md +5 -0
  184. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/apple/DESIGN.md +562 -0
  185. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/apple/README.md +5 -0
  186. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/binance/DESIGN.md +634 -0
  187. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/binance/README.md +5 -0
  188. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/bmw/DESIGN.md +544 -0
  189. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/bmw/README.md +5 -0
  190. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/bmw-m/DESIGN.md +503 -0
  191. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/bmw-m/README.md +5 -0
  192. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/bugatti/DESIGN.md +454 -0
  193. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/bugatti/README.md +5 -0
  194. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/cal/DESIGN.md +542 -0
  195. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/cal/README.md +5 -0
  196. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/claude/DESIGN.md +589 -0
  197. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/claude/README.md +5 -0
  198. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/clay/DESIGN.md +541 -0
  199. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/clay/README.md +5 -0
  200. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/clickhouse/DESIGN.md +544 -0
  201. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/clickhouse/README.md +5 -0
  202. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/cohere/DESIGN.md +451 -0
  203. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/cohere/README.md +5 -0
  204. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/coinbase/DESIGN.md +570 -0
  205. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/coinbase/README.md +5 -0
  206. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/composio/DESIGN.md +506 -0
  207. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/composio/README.md +5 -0
  208. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/cursor/DESIGN.md +537 -0
  209. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/cursor/README.md +5 -0
  210. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/dell-1996/DESIGN.md +632 -0
  211. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/dell-1996/README.md +5 -0
  212. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/elevenlabs/DESIGN.md +504 -0
  213. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/elevenlabs/README.md +5 -0
  214. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/expo/DESIGN.md +526 -0
  215. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/expo/README.md +5 -0
  216. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/ferrari/DESIGN.md +531 -0
  217. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/ferrari/README.md +5 -0
  218. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/figma/DESIGN.md +578 -0
  219. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/figma/README.md +5 -0
  220. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/framer/DESIGN.md +544 -0
  221. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/framer/README.md +5 -0
  222. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/hashicorp/DESIGN.md +575 -0
  223. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/hashicorp/README.md +5 -0
  224. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/hp/DESIGN.md +670 -0
  225. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/hp/README.md +5 -0
  226. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/ibm/DESIGN.md +550 -0
  227. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/ibm/README.md +5 -0
  228. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/intercom/DESIGN.md +546 -0
  229. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/intercom/README.md +5 -0
  230. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/kraken/DESIGN.md +125 -0
  231. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/kraken/README.md +5 -0
  232. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/lamborghini/DESIGN.md +288 -0
  233. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/lamborghini/README.md +5 -0
  234. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/linear.app/DESIGN.md +548 -0
  235. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/linear.app/README.md +5 -0
  236. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/lovable/DESIGN.md +298 -0
  237. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/lovable/README.md +5 -0
  238. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/mastercard/DESIGN.md +365 -0
  239. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/mastercard/README.md +5 -0
  240. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/meta/DESIGN.md +683 -0
  241. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/meta/README.md +5 -0
  242. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/minimax/DESIGN.md +746 -0
  243. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/minimax/README.md +5 -0
  244. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/mintlify/DESIGN.md +852 -0
  245. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/mintlify/README.md +5 -0
  246. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/miro/DESIGN.md +825 -0
  247. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/miro/README.md +5 -0
  248. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/mistral.ai/DESIGN.md +773 -0
  249. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/mistral.ai/README.md +5 -0
  250. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/mongodb/DESIGN.md +767 -0
  251. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/mongodb/README.md +5 -0
  252. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/nike/DESIGN.md +575 -0
  253. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/nike/README.md +5 -0
  254. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/nintendo-2001/DESIGN.md +649 -0
  255. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/nintendo-2001/README.md +5 -0
  256. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/notion/DESIGN.md +821 -0
  257. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/notion/README.md +5 -0
  258. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/nvidia/DESIGN.md +640 -0
  259. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/nvidia/README.md +5 -0
  260. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/ollama/DESIGN.md +539 -0
  261. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/ollama/README.md +5 -0
  262. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/opencode.ai/DESIGN.md +521 -0
  263. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/opencode.ai/README.md +5 -0
  264. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/pinterest/DESIGN.md +597 -0
  265. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/pinterest/README.md +5 -0
  266. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/playstation/DESIGN.md +661 -0
  267. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/playstation/README.md +5 -0
  268. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/posthog/DESIGN.md +690 -0
  269. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/posthog/README.md +5 -0
  270. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/raycast/DESIGN.md +669 -0
  271. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/raycast/README.md +5 -0
  272. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/renault/DESIGN.md +589 -0
  273. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/renault/README.md +5 -0
  274. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/replicate/DESIGN.md +616 -0
  275. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/replicate/README.md +5 -0
  276. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/resend/DESIGN.md +585 -0
  277. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/resend/README.md +5 -0
  278. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/revolut/DESIGN.md +636 -0
  279. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/revolut/README.md +5 -0
  280. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/runwayml/DESIGN.md +244 -0
  281. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/runwayml/README.md +5 -0
  282. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/sanity/DESIGN.md +357 -0
  283. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/sanity/README.md +5 -0
  284. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/sentry/DESIGN.md +551 -0
  285. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/sentry/README.md +5 -0
  286. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/shopify/DESIGN.md +516 -0
  287. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/shopify/README.md +5 -0
  288. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/slack/DESIGN.md +482 -0
  289. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/spacex/DESIGN.md +363 -0
  290. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/spacex/README.md +5 -0
  291. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/spotify/DESIGN.md +246 -0
  292. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/spotify/README.md +5 -0
  293. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/starbucks/DESIGN.md +580 -0
  294. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/starbucks/README.md +5 -0
  295. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/stripe/DESIGN.md +487 -0
  296. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/stripe/README.md +5 -0
  297. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/supabase/DESIGN.md +462 -0
  298. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/supabase/README.md +5 -0
  299. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/superhuman/DESIGN.md +448 -0
  300. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/superhuman/README.md +5 -0
  301. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/tesla/DESIGN.md +286 -0
  302. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/tesla/README.md +5 -0
  303. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/theverge/DESIGN.md +339 -0
  304. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/theverge/README.md +5 -0
  305. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/together.ai/DESIGN.md +633 -0
  306. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/together.ai/README.md +5 -0
  307. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/uber/DESIGN.md +636 -0
  308. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/uber/README.md +5 -0
  309. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/vercel/DESIGN.md +736 -0
  310. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/vercel/README.md +5 -0
  311. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/vodafone/DESIGN.md +538 -0
  312. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/vodafone/README.md +5 -0
  313. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/voltagent/DESIGN.md +521 -0
  314. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/voltagent/README.md +5 -0
  315. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/warp/DESIGN.md +526 -0
  316. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/warp/README.md +5 -0
  317. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/webflow/DESIGN.md +588 -0
  318. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/webflow/README.md +5 -0
  319. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/wired/DESIGN.md +497 -0
  320. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/wired/README.md +5 -0
  321. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/wise/DESIGN.md +544 -0
  322. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/wise/README.md +5 -0
  323. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/x.ai/DESIGN.md +465 -0
  324. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/x.ai/README.md +5 -0
  325. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/zapier/DESIGN.md +537 -0
  326. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/zapier/README.md +5 -0
  327. package/skills/ai-delivery-orchestrate/references/formal-state-contract.md +65 -20
  328. package/skills/ai-delivery-orchestrate/references/workflow-model.md +7 -5
  329. package/skills/ai-delivery-orchestrate-release/SKILL.md +2 -2
  330. package/skills/ai-delivery-orchestrate-release/agents/openai.yaml +4 -4
  331. package/skills/ai-delivery-orchestrate-release/references/release-workflow-contract.md +1 -1
  332. package/skills/ai-delivery-plan-iteration/SKILL.md +11 -4
  333. package/skills/ai-delivery-plan-iteration/agents/openai.yaml +4 -4
  334. package/skills/ai-delivery-plan-iteration/assets/planning-template/scope-manifest.yaml +17 -0
  335. package/skills/ai-delivery-plan-iteration/assets/planning-template/slice-prototype-traceability.csv +1 -1
  336. package/skills/ai-delivery-plan-iteration/references/planning-contract.md +8 -2
  337. package/skills/ai-delivery-prepare-platform/SKILL.md +5 -1
  338. package/skills/ai-delivery-prepare-platform/agents/openai.yaml +4 -4
  339. package/skills/ai-delivery-prepare-release/agents/openai.yaml +4 -4
  340. package/skills/ai-delivery-review-change/SKILL.md +14 -4
  341. package/skills/ai-delivery-review-change/agents/openai.yaml +4 -4
  342. package/skills/ai-delivery-review-change/references/review-contract.md +6 -0
  343. package/skills/ai-delivery-triage-failure/SKILL.md +5 -1
  344. package/skills/ai-delivery-triage-failure/agents/openai.yaml +4 -4
  345. package/skills/ai-delivery-validate-artifacts/SKILL.md +6 -3
  346. package/skills/ai-delivery-validate-artifacts/agents/openai.yaml +4 -4
  347. package/skills/ai-delivery-validate-artifacts/references/artifact-contract.md +13 -13
  348. package/skills/ai-delivery-verify-candidate/SKILL.md +13 -6
  349. package/skills/ai-delivery-verify-candidate/agents/openai.yaml +3 -3
  350. package/skills/ai-delivery-verify-candidate/assets/verification-template/ui-acceptance-request.yaml +19 -0
  351. package/skills/ai-delivery-verify-candidate/assets/verification-template/ui-acceptance-results.yaml +53 -0
  352. package/skills/ai-delivery-verify-candidate/references/candidate-verification-contract.md +10 -2
  353. package/skills/ai-delivery-verify-production/agents/openai.yaml +3 -3
  354. package/skills/ai-delivery-design-experience/assets/experience-template/low-fidelity-confirmation.yaml +0 -32
  355. package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/tools/viewer/public/app.js +0 -546
  356. package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/tools/viewer/public/index.html +0 -199
  357. package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/tools/viewer/public/styles.css +0 -529
  358. package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/tools/viewer/server.mjs +0 -780
  359. package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/tools/viewer/start.cmd +0 -4
  360. package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/tools/viewer/start.ps1 +0 -2
@@ -0,0 +1,897 @@
1
+ import { spawnSync } from "node:child_process";
2
+ import crypto from "node:crypto";
3
+ import fs from "node:fs";
4
+ import path from "node:path";
5
+ import { assertPathInside, atomicWrite } from "./fs-utils.mjs";
6
+ import { freezeMockScenarioPack } from "./mock-scenario-pack.mjs";
7
+ import { parse as parseYaml, stringify as stringifyYaml } from "./yaml-runtime.mjs";
8
+ import { readWorkspaceConfiguration } from "./workspace.mjs";
9
+
10
+ export const MICROCKS_IMAGE = "quay.io/microcks/microcks-uber:1.15.0"
11
+ + "@sha256:97e74ff545d020f9f20141a0edc4ec1a99f32b7bfeacc81aadd47d8ffc642ffe";
12
+
13
+ function defaultRunner(command, args, options = {}) {
14
+ return spawnSync(command, args, {
15
+ cwd: options.cwd,
16
+ encoding: "utf8",
17
+ windowsHide: true,
18
+ timeout: options.timeout,
19
+ });
20
+ }
21
+
22
+ function selectContainerEngine(runner, projectRoot) {
23
+ const args = ["version", "--format", "{{.Client.Version}}"];
24
+ for (const command of ["docker", "podman"]) {
25
+ const probe = runner(command, args, { cwd: projectRoot, timeout: 5000 });
26
+ if (probe?.status === 0) return { command, version: probe.stdout.trim() || null };
27
+ }
28
+ throw new Error(
29
+ "Docker or Podman is unavailable; install and start one explicitly before using the Mock System. "
30
+ + "The workflow will not install a container engine automatically.",
31
+ );
32
+ }
33
+
34
+ function commandFailure(result) {
35
+ return String(result?.stderr || result?.stdout || result?.error?.message || "no output")
36
+ .replace(/\s+/g, " ")
37
+ .trim()
38
+ .slice(0, 500);
39
+ }
40
+
41
+ function requireCommand(result, description) {
42
+ if (result?.status !== 0) throw new Error(`${description} failed: ${commandFailure(result)}`);
43
+ }
44
+
45
+ const MOCK_CATALOG_DEFINITIONS = Object.freeze([
46
+ Object.freeze({
47
+ kind: "external-dependency",
48
+ label: "External Dependency Mock",
49
+ catalogRef: ".workflow/mock-system/external-dependencies.yaml",
50
+ collection: "external_dependencies",
51
+ definitionPrefix: ".workflow/mock-system/definitions/external/",
52
+ }),
53
+ Object.freeze({
54
+ kind: "product-backend",
55
+ label: "Product Backend Mock",
56
+ catalogRef: ".workflow/mock-system/product-backends.yaml",
57
+ collection: "product_backends",
58
+ definitionPrefix: ".workflow/mock-system/definitions/product-backend/",
59
+ }),
60
+ ]);
61
+ const MOCK_CATALOG_DEFINITIONS_BY_KIND = Object.freeze(Object.fromEntries(
62
+ MOCK_CATALOG_DEFINITIONS.map((definition) => [definition.kind, definition]),
63
+ ));
64
+
65
+ function mockKindLabel(kind) {
66
+ return MOCK_CATALOG_DEFINITIONS_BY_KIND[kind]?.label || `Mock (${kind})`;
67
+ }
68
+
69
+ function mockContractLabel(contractRef) {
70
+ return MOCK_CATALOG_DEFINITIONS.find((definition) =>
71
+ contractRef.startsWith(definition.definitionPrefix))?.label || "Mock";
72
+ }
73
+
74
+ function initializeMockCatalogs(projectRoot) {
75
+ const mockRoot = path.join(projectRoot, ".workflow", "mock-system");
76
+ assertPathInside(projectRoot, mockRoot);
77
+ const catalogPaths = {};
78
+ for (const definition of MOCK_CATALOG_DEFINITIONS) {
79
+ const definitionsRoot = path.join(
80
+ projectRoot,
81
+ ...definition.definitionPrefix.slice(0, -1).split("/"),
82
+ );
83
+ const catalogFile = path.join(projectRoot, ...definition.catalogRef.split("/"));
84
+ assertPathInside(projectRoot, definitionsRoot);
85
+ assertPathInside(projectRoot, catalogFile);
86
+ fs.mkdirSync(definitionsRoot, { recursive: true });
87
+ const marker = path.join(definitionsRoot, ".gitkeep");
88
+ if (!fs.existsSync(marker)) atomicWrite(marker, "");
89
+ if (!fs.existsSync(catalogFile)) {
90
+ atomicWrite(catalogFile, stringifyYaml({
91
+ schema_version: 1,
92
+ mock_system: {
93
+ provider: "microcks",
94
+ image: MICROCKS_IMAGE,
95
+ management_url: "http://127.0.0.1:8585",
96
+ },
97
+ [definition.collection]: [],
98
+ }, { lineWidth: 0 }));
99
+ }
100
+ catalogPaths[definition.kind] = definition.catalogRef;
101
+ }
102
+ return catalogPaths;
103
+ }
104
+
105
+ function mockRuntime(projectRoot) {
106
+ const workspace = readWorkspaceConfiguration(projectRoot);
107
+ const workspaceSlug = String(workspace.configuration.workspace_id)
108
+ .toLowerCase()
109
+ .replace(/[^a-z0-9]+/g, "-")
110
+ .replace(/^-+|-+$/g, "")
111
+ .slice(0, 40);
112
+ const containerName = `ai-delivery-${workspaceSlug}-microcks`;
113
+ const managementUrl = "http://127.0.0.1:8585";
114
+ const catalogFile = path.join(projectRoot, ".workflow", "mock-system", "external-dependencies.yaml");
115
+ if (!fs.existsSync(catalogFile)) {
116
+ throw new Error("Mock System is not initialized; run ai-delivery mock setup first");
117
+ }
118
+ return {
119
+ workspaceId: workspace.configuration.workspace_id,
120
+ containerName,
121
+ managementUrl,
122
+ runArgs: [
123
+ "run", "--detach", "--rm", "--pull=never",
124
+ "--name", containerName,
125
+ "--label", "io.ai-delivery.mock-system=microcks",
126
+ "--label", `io.ai-delivery.workspace-id=${workspace.configuration.workspace_id}`,
127
+ "--publish", "127.0.0.1:8585:8080",
128
+ MICROCKS_IMAGE,
129
+ ],
130
+ };
131
+ }
132
+
133
+ async function waitForHealth(url, options = {}) {
134
+ const request = options.request || globalThis.fetch;
135
+ const pause = options.sleep || ((milliseconds) =>
136
+ new Promise((resolve) => setTimeout(resolve, milliseconds)));
137
+ const attempts = options.healthAttempts || 60;
138
+ let detail = "no response";
139
+ for (let attempt = 0; attempt < attempts; attempt += 1) {
140
+ try {
141
+ const response = await request(url, { method: "GET" });
142
+ if (response?.status === 200) return;
143
+ detail = `HTTP ${response?.status ?? "unknown"}`;
144
+ } catch (error) {
145
+ detail = error.message;
146
+ }
147
+ if (attempt + 1 < attempts) await pause(options.healthDelayMs ?? 1000);
148
+ }
149
+ throw new Error(`Microcks health check failed at ${url}: ${detail}`);
150
+ }
151
+
152
+ async function inspectHealth(url, request = globalThis.fetch) {
153
+ try {
154
+ const response = await request(url, { method: "GET" });
155
+ return response?.status === 200;
156
+ } catch {
157
+ return false;
158
+ }
159
+ }
160
+
161
+ function requireLoopbackUrl(value) {
162
+ let parsed;
163
+ try {
164
+ parsed = new URL(value);
165
+ } catch {
166
+ throw new Error(`Mock System URL is invalid: ${value}`);
167
+ }
168
+ const loopbackHosts = new Set(["127.0.0.1", "localhost", "[::1]"]);
169
+ if (parsed.protocol !== "http:"
170
+ || !loopbackHosts.has(parsed.hostname)
171
+ || parsed.username
172
+ || parsed.password
173
+ || !new Set(["", "/"]).has(parsed.pathname)
174
+ || parsed.search
175
+ || parsed.hash) {
176
+ throw new Error(`Mock System URL must be a credential-free loopback HTTP origin: ${value}`);
177
+ }
178
+ return parsed.origin;
179
+ }
180
+
181
+ function readContractDefinition(contractFile, contractRef) {
182
+ try {
183
+ return parseYaml(fs.readFileSync(contractFile, "utf8"));
184
+ } catch (error) {
185
+ throw new Error(`${mockContractLabel(contractRef)} contract is invalid YAML: ${contractRef}: ${error.message}`);
186
+ }
187
+ }
188
+
189
+ function resolveLocalReference(definition, value, contractRef) {
190
+ let resolved = value;
191
+ const visited = new Set();
192
+ while (resolved && typeof resolved === "object" && typeof resolved.$ref === "string") {
193
+ const reference = resolved.$ref;
194
+ if (!reference.startsWith("#/")) {
195
+ throw new Error(`${mockContractLabel(contractRef)} contract uses an unsupported external reference in ${contractRef}: ${reference}`);
196
+ }
197
+ if (visited.has(reference)) {
198
+ throw new Error(`${mockContractLabel(contractRef)} contract has a circular reference in ${contractRef}: ${reference}`);
199
+ }
200
+ visited.add(reference);
201
+ resolved = reference.slice(2).split("/").reduce((node, segment) => {
202
+ const key = segment.replaceAll("~1", "/").replaceAll("~0", "~");
203
+ return node?.[key];
204
+ }, definition);
205
+ if (resolved === undefined) {
206
+ throw new Error(`${mockContractLabel(contractRef)} contract reference is missing in ${contractRef}: ${reference}`);
207
+ }
208
+ }
209
+ return resolved;
210
+ }
211
+
212
+ function openApiResponseScenarios(definition, operation, contractRef) {
213
+ const scenarios = new Set();
214
+ for (const responseValue of Object.values(operation.responses || {})) {
215
+ const response = resolveLocalReference(definition, responseValue, contractRef);
216
+ for (const scenarioId of response?.["x-microcks-refs"] || []) scenarios.add(scenarioId);
217
+ for (const mediaValue of Object.values(response?.content || {})) {
218
+ const media = resolveLocalReference(definition, mediaValue, contractRef);
219
+ const examples = resolveLocalReference(definition, media?.examples, contractRef);
220
+ if (examples && typeof examples === "object") {
221
+ for (const scenarioId of Object.keys(examples)) scenarios.add(scenarioId);
222
+ }
223
+ }
224
+ }
225
+ return scenarios;
226
+ }
227
+
228
+ function hasNamedParameterExample(definition, parameter, scenarioId, contractRef) {
229
+ const examples = resolveLocalReference(definition, parameter?.examples, contractRef);
230
+ if (!examples || typeof examples !== "object" || !Object.hasOwn(examples, scenarioId)) return false;
231
+ const example = resolveLocalReference(definition, examples[scenarioId], contractRef);
232
+ return example && typeof example === "object"
233
+ && (Object.hasOwn(example, "value") || typeof example.externalValue === "string");
234
+ }
235
+
236
+ function dispatcherRuleNames(rules, dispatcher, entry) {
237
+ if (typeof rules !== "string" || !rules.trim()) {
238
+ throw new Error(
239
+ `${mockKindLabel(entry.mock_kind)} dispatcher ${dispatcher} requires dispatcherRules in ${entry.operation_or_channel}`,
240
+ );
241
+ }
242
+ return rules.split(/\s*&&\s*/).map((name) => name.trim()).filter(Boolean);
243
+ }
244
+
245
+ function requireDispatcherInputs(definition, parameters, names, location, entry) {
246
+ for (const name of names) {
247
+ const parameter = parameters.find((candidate) =>
248
+ candidate?.in === location && candidate?.name === name);
249
+ if (!hasNamedParameterExample(definition, parameter, entry.scenario_id, entry.contract_ref)) {
250
+ throw new Error(
251
+ `${mockKindLabel(entry.mock_kind)} dispatcher input ${location} parameter ${name} has no example for ${entry.scenario_id}`,
252
+ );
253
+ }
254
+ }
255
+ }
256
+
257
+ function validateOpenApiOperation(definition, entry) {
258
+ const match = /^([A-Za-z]+) (\/\S+)$/.exec(entry.operation_or_channel);
259
+ const method = match?.[1]?.toLowerCase();
260
+ const route = match?.[2];
261
+ const pathItem = route
262
+ ? resolveLocalReference(definition, definition?.paths?.[route], entry.contract_ref)
263
+ : undefined;
264
+ const operation = resolveLocalReference(definition, pathItem?.[method], entry.contract_ref);
265
+ if (!operation || typeof operation !== "object" || Array.isArray(operation)) {
266
+ throw new Error(
267
+ `${mockKindLabel(entry.mock_kind)} operation_or_channel ${entry.operation_or_channel} is not present in ${entry.contract_ref}`,
268
+ );
269
+ }
270
+ const responseScenarios = openApiResponseScenarios(definition, operation, entry.contract_ref);
271
+ if (!responseScenarios.has(entry.scenario_id)) {
272
+ throw new Error(
273
+ `${mockKindLabel(entry.mock_kind)} scenario_id ${entry.scenario_id} is not present in ${entry.operation_or_channel}`,
274
+ );
275
+ }
276
+ const parameters = [...(pathItem?.parameters || []), ...(operation.parameters || [])]
277
+ .map((parameter) => resolveLocalReference(definition, parameter, entry.contract_ref));
278
+ const operationParameters = (operation.parameters || [])
279
+ .map((parameter) => resolveLocalReference(definition, parameter, entry.contract_ref));
280
+ const pathVariables = [...route.matchAll(/\{([^{}]+)\}/g)].map((matchValue) => matchValue[1]);
281
+ const queryParameters = operationParameters.filter((parameter) => parameter?.in === "query");
282
+ const dispatcherMetadata = operation["x-microcks-operation"];
283
+ const configuredDispatcher = typeof dispatcherMetadata?.dispatcher === "string"
284
+ ? dispatcherMetadata.dispatcher.trim().toUpperCase()
285
+ : null;
286
+ const effectiveDispatcher = configuredDispatcher
287
+ || (pathVariables.length > 0 && queryParameters.length > 0 ? "URI_ELEMENTS"
288
+ : pathVariables.length > 0 ? "URI_PARTS"
289
+ : queryParameters.length > 0 ? "URI_PARAMS"
290
+ : null);
291
+
292
+ if (effectiveDispatcher === "URI_PARTS") {
293
+ const names = configuredDispatcher
294
+ ? dispatcherRuleNames(dispatcherMetadata.dispatcherRules, effectiveDispatcher, entry)
295
+ : pathVariables;
296
+ requireDispatcherInputs(definition, parameters, names, "path", entry);
297
+ } else if (effectiveDispatcher === "URI_PARAMS") {
298
+ const names = configuredDispatcher
299
+ ? dispatcherRuleNames(dispatcherMetadata.dispatcherRules, effectiveDispatcher, entry)
300
+ : queryParameters.map((parameter) => parameter.name);
301
+ requireDispatcherInputs(definition, operationParameters, names, "query", entry);
302
+ } else if (effectiveDispatcher === "URI_ELEMENTS") {
303
+ let pathNames = pathVariables;
304
+ let queryNames = queryParameters.map((parameter) => parameter.name);
305
+ if (configuredDispatcher) {
306
+ const ruleParts = String(dispatcherMetadata.dispatcherRules || "").split(/\s*\?\?\s*/);
307
+ if (ruleParts.length !== 2) {
308
+ throw new Error(
309
+ `${mockKindLabel(entry.mock_kind)} dispatcher URI_ELEMENTS requires path ?? query dispatcherRules in ${entry.operation_or_channel}`,
310
+ );
311
+ }
312
+ pathNames = dispatcherRuleNames(ruleParts[0], effectiveDispatcher, entry);
313
+ queryNames = dispatcherRuleNames(ruleParts[1], effectiveDispatcher, entry);
314
+ }
315
+ requireDispatcherInputs(definition, parameters, pathNames, "path", entry);
316
+ requireDispatcherInputs(definition, operationParameters, queryNames, "query", entry);
317
+ } else if (effectiveDispatcher === "QUERY_HEADER") {
318
+ const names = dispatcherRuleNames(dispatcherMetadata.dispatcherRules, effectiveDispatcher, entry);
319
+ requireDispatcherInputs(definition, operationParameters, names, "header", entry);
320
+ } else if (effectiveDispatcher === "RANDOM" || effectiveDispatcher === "SEQUENCE") {
321
+ if (responseScenarios.size > 1) {
322
+ throw new Error(
323
+ `${mockKindLabel(entry.mock_kind)} ${entry.operation_or_channel} has ${responseScenarios.size} named scenarios but dispatcher ${effectiveDispatcher} is not deterministic`,
324
+ );
325
+ }
326
+ } else if (effectiveDispatcher) {
327
+ throw new Error(
328
+ `${mockKindLabel(entry.mock_kind)} dispatcher ${effectiveDispatcher} cannot be validated locally for deterministic scenario selection`,
329
+ );
330
+ } else if (responseScenarios.size > 1) {
331
+ throw new Error(
332
+ `${mockKindLabel(entry.mock_kind)} ${entry.operation_or_channel} has ${responseScenarios.size} named scenarios but no deterministic dispatcher`,
333
+ );
334
+ }
335
+ }
336
+
337
+ function asyncApiOperationHasScenario(definition, operation, scenarioId, contractRef) {
338
+ for (const messageValue of operation?.messages || []) {
339
+ const message = resolveLocalReference(definition, messageValue, contractRef);
340
+ for (const exampleValue of message?.examples || []) {
341
+ const example = resolveLocalReference(definition, exampleValue, contractRef);
342
+ if (example?.name === scenarioId) return true;
343
+ if (example && typeof example === "object" && Object.hasOwn(example, scenarioId)) return true;
344
+ }
345
+ }
346
+ return false;
347
+ }
348
+
349
+ function validateAsyncApiIdentity(definition, entry) {
350
+ const channels = Object.entries(definition.channels || {}).map(([key, channelValue]) => ({
351
+ key,
352
+ channel: resolveLocalReference(definition, channelValue, entry.contract_ref),
353
+ }));
354
+ const majorVersion = Number.parseInt(definition.asyncapi, 10);
355
+ const operations = majorVersion >= 3
356
+ ? Object.entries(definition.operations || {}).map(([key, operationValue]) => {
357
+ const operation = resolveLocalReference(definition, operationValue, entry.contract_ref);
358
+ return {
359
+ key,
360
+ identity: `${String(operation?.action || "").toUpperCase()} ${key}`,
361
+ operation,
362
+ channel: resolveLocalReference(definition, operation?.channel, entry.contract_ref),
363
+ };
364
+ })
365
+ : channels.flatMap(({ key, channel }) => ["publish", "subscribe"].flatMap((action) => {
366
+ const operation = resolveLocalReference(definition, channel?.[action], entry.contract_ref);
367
+ if (!operation) return [];
368
+ return [{
369
+ key,
370
+ identity: `${action.toUpperCase()} ${key}`,
371
+ operation: { ...operation, action, messages: [operation.message] },
372
+ channel,
373
+ }];
374
+ }));
375
+ const directOperation = operations.find(({ key, identity }) =>
376
+ entry.operation_or_channel === identity
377
+ || (majorVersion >= 3 && entry.operation_or_channel === key));
378
+ const candidates = directOperation ? [directOperation] : (() => {
379
+ const selectedChannel = channels.find(({ key, channel }) =>
380
+ entry.operation_or_channel === key || entry.operation_or_channel === channel?.address);
381
+ return selectedChannel
382
+ ? operations.filter(({ channel }) => channel === selectedChannel.channel)
383
+ : [];
384
+ })();
385
+ if (candidates.length === 0) {
386
+ throw new Error(
387
+ `${mockKindLabel(entry.mock_kind)} operation_or_channel ${entry.operation_or_channel} is not present in ${entry.contract_ref}`,
388
+ );
389
+ }
390
+ const selectedOperation = candidates.find(({ operation }) => asyncApiOperationHasScenario(
391
+ definition, operation, entry.scenario_id, entry.contract_ref,
392
+ ));
393
+ if (!selectedOperation) {
394
+ throw new Error(
395
+ `${mockKindLabel(entry.mock_kind)} scenario_id ${entry.scenario_id} is not present in ${entry.operation_or_channel}`,
396
+ );
397
+ }
398
+ }
399
+
400
+ export function validateMockDefinition(definition, entry) {
401
+ mockProtocolHandler(definition, entry).validate(definition, entry);
402
+ }
403
+
404
+ function inlineExampleValue(definition, examplesValue, scenarioId, contractRef, label) {
405
+ const examples = resolveLocalReference(definition, examplesValue, contractRef);
406
+ if (!examples || !Object.hasOwn(examples, scenarioId)) return undefined;
407
+ const example = resolveLocalReference(definition, examples[scenarioId], contractRef);
408
+ if (!example || typeof example !== "object" || !Object.hasOwn(example, "value")) {
409
+ throw new Error(`${label} requires an inline value for UI Acceptance`);
410
+ }
411
+ return example.value;
412
+ }
413
+
414
+ function openApiProtocolExpectation(definition, entry) {
415
+ validateOpenApiOperation(definition, entry);
416
+ const match = /^([A-Za-z]+) (\/\S+)$/.exec(entry.operation_or_channel);
417
+ const method = match?.[1]?.toLowerCase();
418
+ const route = match?.[2];
419
+ const pathItem = resolveLocalReference(definition, definition?.paths?.[route], entry.contract_ref);
420
+ const operation = resolveLocalReference(definition, pathItem?.[method], entry.contract_ref);
421
+ for (const [statusValue, responseValue] of Object.entries(operation.responses || {})) {
422
+ const status = Number(statusValue);
423
+ if (!Number.isInteger(status) || status < 100 || status > 599) continue;
424
+ const response = resolveLocalReference(definition, responseValue, entry.contract_ref);
425
+ for (const [contentType, mediaValue] of Object.entries(response?.content || {})) {
426
+ const media = resolveLocalReference(definition, mediaValue, entry.contract_ref);
427
+ const responseBody = inlineExampleValue(
428
+ definition,
429
+ media?.examples,
430
+ entry.scenario_id,
431
+ entry.contract_ref,
432
+ `${mockKindLabel(entry.mock_kind)} scenario ${entry.scenario_id} response`,
433
+ );
434
+ if (responseBody === undefined) continue;
435
+ const parameters = [...(pathItem?.parameters || []), ...(operation.parameters || [])]
436
+ .map((parameter) => resolveLocalReference(definition, parameter, entry.contract_ref));
437
+ const request = { method: method.toUpperCase(), path: route };
438
+ for (const location of ["path", "query", "header"]) {
439
+ const values = {};
440
+ for (const parameter of parameters.filter((item) => item?.in === location)) {
441
+ const value = inlineExampleValue(
442
+ definition,
443
+ parameter.examples,
444
+ entry.scenario_id,
445
+ entry.contract_ref,
446
+ `${mockKindLabel(entry.mock_kind)} ${location} parameter ${parameter.name}`,
447
+ );
448
+ if (value !== undefined) values[parameter.name] = value;
449
+ }
450
+ if (Object.keys(values).length) request[`${location}_parameters`] = values;
451
+ }
452
+ const requestBody = resolveLocalReference(definition, operation.requestBody, entry.contract_ref);
453
+ for (const [requestContentType, requestMediaValue] of Object.entries(requestBody?.content || {})) {
454
+ const requestMedia = resolveLocalReference(definition, requestMediaValue, entry.contract_ref);
455
+ const body = inlineExampleValue(
456
+ definition,
457
+ requestMedia?.examples,
458
+ entry.scenario_id,
459
+ entry.contract_ref,
460
+ `${mockKindLabel(entry.mock_kind)} scenario ${entry.scenario_id} request body`,
461
+ );
462
+ if (body !== undefined) {
463
+ request.content_type = requestContentType;
464
+ request.body = body;
465
+ break;
466
+ }
467
+ }
468
+ return {
469
+ request,
470
+ response: { status, content_type: contentType, body: responseBody },
471
+ };
472
+ }
473
+ }
474
+ throw new Error(
475
+ `${mockKindLabel(entry.mock_kind)} scenario ${entry.scenario_id} has no deterministic response example for UI Acceptance`,
476
+ );
477
+ }
478
+
479
+ function asyncApiProtocolExpectation(definition, entry) {
480
+ validateAsyncApiIdentity(definition, entry);
481
+ const candidates = [];
482
+ const collect = (messageValue) => {
483
+ const message = resolveLocalReference(definition, messageValue, entry.contract_ref);
484
+ for (const exampleValue of message?.examples || []) {
485
+ const example = resolveLocalReference(definition, exampleValue, entry.contract_ref);
486
+ if (example?.name === entry.scenario_id && Object.hasOwn(example, "payload")) {
487
+ candidates.push(example.payload);
488
+ } else if (example && typeof example === "object"
489
+ && Object.hasOwn(example, entry.scenario_id)) {
490
+ const named = resolveLocalReference(definition, example[entry.scenario_id], entry.contract_ref);
491
+ candidates.push(named?.payload ?? named?.value ?? named);
492
+ }
493
+ }
494
+ };
495
+ const majorVersion = Number.parseInt(definition.asyncapi, 10);
496
+ if (majorVersion >= 3) {
497
+ for (const operationValue of Object.values(definition.operations || {})) {
498
+ const operation = resolveLocalReference(definition, operationValue, entry.contract_ref);
499
+ for (const message of operation?.messages || []) collect(message);
500
+ }
501
+ } else {
502
+ for (const channelValue of Object.values(definition.channels || {})) {
503
+ const channel = resolveLocalReference(definition, channelValue, entry.contract_ref);
504
+ for (const action of ["publish", "subscribe"]) {
505
+ const operation = resolveLocalReference(definition, channel?.[action], entry.contract_ref);
506
+ if (operation?.message) collect(operation.message);
507
+ }
508
+ }
509
+ }
510
+ if (candidates.length !== 1 || candidates[0] === undefined) {
511
+ throw new Error(
512
+ `${mockKindLabel(entry.mock_kind)} scenario ${entry.scenario_id} has no unique deterministic message example for UI Acceptance`,
513
+ );
514
+ }
515
+ return {
516
+ request: {
517
+ operation_or_channel: entry.operation_or_channel,
518
+ scenario_id: entry.scenario_id,
519
+ },
520
+ response: { payload: candidates[0] },
521
+ };
522
+ }
523
+
524
+ const mockProtocolHandlers = Object.freeze([
525
+ Object.freeze({
526
+ format: "OpenAPI",
527
+ matches: (definition) => typeof definition?.openapi === "string",
528
+ protocol: "http",
529
+ validate: validateOpenApiOperation,
530
+ expectation: openApiProtocolExpectation,
531
+ }),
532
+ Object.freeze({
533
+ format: "AsyncAPI",
534
+ matches: (definition) => typeof definition?.asyncapi === "string",
535
+ protocol: "asyncapi",
536
+ validate: validateAsyncApiIdentity,
537
+ expectation: asyncApiProtocolExpectation,
538
+ }),
539
+ ]);
540
+
541
+ function mockProtocolHandler(definition, entry) {
542
+ const handler = mockProtocolHandlers.find((candidate) => candidate.matches(definition));
543
+ if (!handler) {
544
+ throw new Error(
545
+ `${mockKindLabel(entry.mock_kind)} contract must be an OpenAPI or AsyncAPI definition: ${entry.contract_ref}`,
546
+ );
547
+ }
548
+ if (entry.protocol !== handler.protocol) {
549
+ throw new Error(
550
+ `${mockKindLabel(entry.mock_kind)} protocol ${entry.protocol} does not match ${handler.format}`,
551
+ );
552
+ }
553
+ return handler;
554
+ }
555
+
556
+ export function mockProtocolExpectation(definition, entry) {
557
+ const handler = mockProtocolHandler(definition, entry);
558
+ return { protocol: handler.protocol, ...handler.expectation(definition, entry) };
559
+ }
560
+
561
+ function readMockCatalog(projectRoot, definition) {
562
+ const catalogFile = path.join(projectRoot, ...definition.catalogRef.split("/"));
563
+ assertPathInside(projectRoot, catalogFile);
564
+ if (!fs.existsSync(catalogFile)) {
565
+ throw new Error("Mock System is not initialized; run ai-delivery mock setup first");
566
+ }
567
+ let catalog;
568
+ try {
569
+ catalog = parseYaml(fs.readFileSync(catalogFile, "utf8"));
570
+ } catch (error) {
571
+ throw new Error(`${definition.label} catalog is invalid YAML: ${error.message}`);
572
+ }
573
+ if (catalog?.schema_version !== 1
574
+ || catalog?.mock_system?.provider !== "microcks"
575
+ || catalog?.mock_system?.image !== MICROCKS_IMAGE
576
+ || !Array.isArray(catalog?.[definition.collection])) {
577
+ throw new Error(`${definition.label} catalog has an invalid schema, provider, or pinned image`);
578
+ }
579
+ const requiredFields = [
580
+ "mock_kind", "mock_id", "owner", "contract_ref", "contract_approval_ref",
581
+ "replacement_condition", "protocol", "operation_or_channel", "scenario_id",
582
+ ];
583
+ const identityFields = [
584
+ "owner", "contract_ref", "contract_approval_ref", "replacement_condition", "protocol",
585
+ ];
586
+ const identities = new Map();
587
+ const scenarioKeys = new Set();
588
+ const entries = catalog[definition.collection].map((entry, index) => {
589
+ if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
590
+ throw new Error(`${definition.label} entry ${index + 1} must be an object`);
591
+ }
592
+ for (const field of requiredFields) {
593
+ if (typeof entry[field] !== "string" || !entry[field].trim()) {
594
+ throw new Error(`${definition.label} entry ${index + 1} requires ${field}`);
595
+ }
596
+ }
597
+ const catalogEntry = Object.fromEntries(
598
+ requiredFields.map((field) => [field, entry[field].trim()]),
599
+ );
600
+ if (catalogEntry.mock_kind !== definition.kind) {
601
+ throw new Error(`${definition.label} mock_kind must be ${definition.kind}`);
602
+ }
603
+ const existingIdentity = identities.get(catalogEntry.mock_id);
604
+ if (existingIdentity) {
605
+ for (const field of identityFields) {
606
+ if (catalogEntry[field] !== existingIdentity[field]) {
607
+ throw new Error(
608
+ `${definition.label} ${catalogEntry.mock_id} must keep ${field} consistent across scenarios`,
609
+ );
610
+ }
611
+ }
612
+ } else {
613
+ identities.set(catalogEntry.mock_id, catalogEntry);
614
+ }
615
+ const scenarioKey = JSON.stringify([catalogEntry.mock_id, catalogEntry.scenario_id]);
616
+ if (scenarioKeys.has(scenarioKey)) {
617
+ throw new Error(
618
+ `Duplicate ${definition.label} scenario: ${catalogEntry.mock_id} / ${catalogEntry.scenario_id}`,
619
+ );
620
+ }
621
+ scenarioKeys.add(scenarioKey);
622
+ const contractRef = catalogEntry.contract_ref;
623
+ const prefix = definition.definitionPrefix;
624
+ if (contractRef.includes("\\")
625
+ || contractRef.includes("\0")
626
+ || path.posix.isAbsolute(contractRef)
627
+ || path.posix.normalize(contractRef) !== contractRef
628
+ || !contractRef.startsWith(prefix)) {
629
+ throw new Error(`${definition.label} contract_ref is outside ${prefix}: ${contractRef}`);
630
+ }
631
+ const contractFile = path.resolve(projectRoot, ...contractRef.split("/"));
632
+ assertPathInside(projectRoot, contractFile);
633
+ if (!fs.existsSync(contractFile) || !fs.statSync(contractFile).isFile()) {
634
+ throw new Error(`${definition.label} contract is missing: ${contractRef}`);
635
+ }
636
+ assertPathInside(projectRoot, contractFile);
637
+ const contractDefinition = readContractDefinition(contractFile, contractRef);
638
+ validateMockDefinition(contractDefinition, catalogEntry);
639
+ return {
640
+ catalogEntry,
641
+ contractFile,
642
+ };
643
+ });
644
+ return {
645
+ baseUrl: requireLoopbackUrl(catalog.mock_system.management_url),
646
+ definition,
647
+ entries,
648
+ };
649
+ }
650
+
651
+ function readMockCatalogs(projectRoot) {
652
+ const catalogs = MOCK_CATALOG_DEFINITIONS.map((definition) =>
653
+ readMockCatalog(projectRoot, definition));
654
+ const baseUrls = new Set(catalogs.map((catalog) => catalog.baseUrl));
655
+ if (baseUrls.size !== 1) {
656
+ throw new Error("External Dependency and Product Backend Mock catalogs must use the same loopback management URL");
657
+ }
658
+ const kindsById = new Map();
659
+ for (const { entries } of catalogs) {
660
+ for (const entry of entries) {
661
+ const { mock_id: mockId, mock_kind: mockKind } = entry.catalogEntry;
662
+ const existingKind = kindsById.get(mockId);
663
+ if (existingKind && existingKind !== mockKind) {
664
+ throw new Error(`Mock ID is duplicated across catalog kinds: ${entry.catalogEntry.mock_id}`);
665
+ }
666
+ kindsById.set(mockId, mockKind);
667
+ }
668
+ }
669
+ return {
670
+ baseUrl: catalogs[0].baseUrl,
671
+ catalogs,
672
+ entries: catalogs.flatMap((catalog) => catalog.entries),
673
+ };
674
+ }
675
+
676
+ function multipartArtifact(file) {
677
+ const boundary = `----ai-delivery-${crypto.randomUUID()}`;
678
+ const filename = path.basename(file).replace(/["\r\n]/g, "_");
679
+ const prefix = Buffer.from(
680
+ `--${boundary}\r\n`
681
+ + `Content-Disposition: form-data; name="file"; filename="${filename}"\r\n`
682
+ + "Content-Type: application/octet-stream\r\n\r\n",
683
+ );
684
+ const suffix = Buffer.from(`\r\n--${boundary}--\r\n`);
685
+ return {
686
+ body: Buffer.concat([prefix, fs.readFileSync(file), suffix]),
687
+ contentType: `multipart/form-data; boundary=${boundary}`,
688
+ };
689
+ }
690
+
691
+ function reportCatalogEntries(catalogs) {
692
+ return Object.fromEntries(catalogs.map(({ definition, entries }) => [
693
+ definition.collection,
694
+ entries.map((entry) => entry.catalogEntry),
695
+ ]));
696
+ }
697
+
698
+ async function syncMockCatalogs(projectRoot, options = {}) {
699
+ const catalog = readMockCatalogs(projectRoot);
700
+ const baseUrl = requireLoopbackUrl(options.baseUrl || catalog.baseUrl);
701
+ const contracts = new Map();
702
+ for (const entry of catalog.entries) {
703
+ if (!contracts.has(entry.catalogEntry.contract_ref)) {
704
+ contracts.set(entry.catalogEntry.contract_ref, entry.contractFile);
705
+ }
706
+ }
707
+ if (options.dryRun) {
708
+ return {
709
+ provider: "microcks",
710
+ action: "sync",
711
+ dry_run: true,
712
+ base_url: baseUrl,
713
+ planned_contracts: [...contracts.keys()],
714
+ ...reportCatalogEntries(catalog.catalogs),
715
+ };
716
+ }
717
+ const request = options.request || globalThis.fetch;
718
+ const healthUrl = `${baseUrl}/api/health`;
719
+ if (!await inspectHealth(healthUrl, request)) {
720
+ throw new Error(`Microcks is not healthy at ${healthUrl}; start the Mock System before sync`);
721
+ }
722
+ for (const [contractRef, contractFile] of contracts) {
723
+ const multipart = multipartArtifact(contractFile);
724
+ const response = await request(`${baseUrl}/api/artifact/upload?mainArtifact=true`, {
725
+ method: "POST",
726
+ headers: { "content-type": multipart.contentType },
727
+ body: multipart.body,
728
+ });
729
+ if (response?.status !== 201) {
730
+ throw new Error(`Microcks rejected ${contractRef}: HTTP ${response?.status ?? "unknown"}`);
731
+ }
732
+ }
733
+ return {
734
+ provider: "microcks",
735
+ action: "sync",
736
+ base_url: baseUrl,
737
+ health_url: healthUrl,
738
+ uploaded_contracts: contracts.size,
739
+ ...reportCatalogEntries(catalog.catalogs),
740
+ };
741
+ }
742
+
743
+ export async function runMockSystemAction(projectRoot, action, options = {}) {
744
+ if (!new Set(["setup", "start", "stop", "status", "sync", "freeze"]).has(action)) {
745
+ throw new Error(`Unknown Mock System action: ${action}`);
746
+ }
747
+ if (action === "sync") return syncMockCatalogs(projectRoot, options);
748
+ if (action === "freeze") {
749
+ return freezeMockScenarioPack(projectRoot, options, {
750
+ readMockCatalogs,
751
+ validateMockDefinition,
752
+ });
753
+ }
754
+ const runner = options.runner || defaultRunner;
755
+ const engine = selectContainerEngine(runner, projectRoot);
756
+ if (action === "stop") {
757
+ const runtime = mockRuntime(projectRoot);
758
+ if (options.dryRun) {
759
+ return {
760
+ provider: "microcks",
761
+ action,
762
+ dry_run: true,
763
+ engine: engine.command,
764
+ image: MICROCKS_IMAGE,
765
+ container_name: runtime.containerName,
766
+ planned_command: [engine.command, "stop", runtime.containerName],
767
+ };
768
+ }
769
+ const stopped = runner(engine.command, [
770
+ "stop", runtime.containerName,
771
+ ], { cwd: projectRoot });
772
+ requireCommand(stopped, "Stopping the Microcks container");
773
+ return {
774
+ provider: "microcks",
775
+ action,
776
+ engine: engine.command,
777
+ image: MICROCKS_IMAGE,
778
+ container_name: runtime.containerName,
779
+ stopped: true,
780
+ running: false,
781
+ };
782
+ }
783
+ if (action === "status") {
784
+ const runtime = mockRuntime(projectRoot);
785
+ const inspected = runner(engine.command, [
786
+ "inspect", "--format", "{{json .State}}", runtime.containerName,
787
+ ], { cwd: projectRoot });
788
+ if (inspected?.status !== 0) {
789
+ return {
790
+ provider: "microcks",
791
+ action,
792
+ engine: engine.command,
793
+ image: MICROCKS_IMAGE,
794
+ container_name: runtime.containerName,
795
+ management_url: runtime.managementUrl,
796
+ container_state: "absent",
797
+ running: false,
798
+ healthy: false,
799
+ };
800
+ }
801
+ let state;
802
+ try {
803
+ state = JSON.parse(inspected.stdout);
804
+ } catch {
805
+ throw new Error(`Microcks container state is invalid: ${commandFailure(inspected)}`);
806
+ }
807
+ const running = state.Running === true;
808
+ const healthUrl = `${runtime.managementUrl}/api/health`;
809
+ return {
810
+ provider: "microcks",
811
+ action,
812
+ engine: engine.command,
813
+ image: MICROCKS_IMAGE,
814
+ container_name: runtime.containerName,
815
+ management_url: runtime.managementUrl,
816
+ health_url: healthUrl,
817
+ container_state: String(state.Status || (running ? "running" : "stopped")),
818
+ running,
819
+ healthy: running && await inspectHealth(healthUrl, options.request),
820
+ };
821
+ }
822
+ if (action === "start") {
823
+ const runtime = mockRuntime(projectRoot);
824
+ if (options.dryRun) {
825
+ return {
826
+ provider: "microcks",
827
+ action,
828
+ dry_run: true,
829
+ engine: engine.command,
830
+ engine_version: engine.version,
831
+ image: MICROCKS_IMAGE,
832
+ container_name: runtime.containerName,
833
+ management_url: runtime.managementUrl,
834
+ planned_command: [engine.command, ...runtime.runArgs],
835
+ };
836
+ }
837
+ const started = runner(engine.command, runtime.runArgs, {
838
+ cwd: projectRoot,
839
+ });
840
+ requireCommand(started, "Starting the Microcks container");
841
+ const healthUrl = `${runtime.managementUrl}/api/health`;
842
+ try {
843
+ await waitForHealth(healthUrl, options);
844
+ } catch (healthError) {
845
+ const stopped = runner(engine.command, ["stop", runtime.containerName], { cwd: projectRoot });
846
+ if (stopped?.status !== 0) {
847
+ throw new Error(
848
+ `${healthError.message}; cleaning the unhealthy Microcks container failed: ${commandFailure(stopped)}`,
849
+ { cause: healthError },
850
+ );
851
+ }
852
+ throw healthError;
853
+ }
854
+ return {
855
+ provider: "microcks",
856
+ action,
857
+ engine: engine.command,
858
+ engine_version: engine.version,
859
+ image: MICROCKS_IMAGE,
860
+ container_name: runtime.containerName,
861
+ container_id: started.stdout.trim() || null,
862
+ management_url: runtime.managementUrl,
863
+ health_url: healthUrl,
864
+ running: true,
865
+ healthy: true,
866
+ };
867
+ }
868
+ if (options.dryRun) {
869
+ return {
870
+ provider: "microcks",
871
+ action,
872
+ dry_run: true,
873
+ engine: engine.command,
874
+ engine_version: engine.version,
875
+ image: MICROCKS_IMAGE,
876
+ planned_actions: [
877
+ "create the isolated tracked External Dependency and Product Backend Mock catalogs",
878
+ `pull ${MICROCKS_IMAGE}`,
879
+ ],
880
+ };
881
+ }
882
+ const pulled = runner(engine.command, ["pull", MICROCKS_IMAGE], {
883
+ cwd: projectRoot,
884
+ });
885
+ requireCommand(pulled, "Pulling the pinned Microcks image");
886
+ const catalogPaths = initializeMockCatalogs(projectRoot);
887
+ return {
888
+ provider: "microcks",
889
+ action,
890
+ engine: engine.command,
891
+ engine_version: engine.version,
892
+ image: MICROCKS_IMAGE,
893
+ initialized: true,
894
+ catalog_path: catalogPaths["external-dependency"],
895
+ catalog_paths: catalogPaths,
896
+ };
897
+ }