ai-delivery-workflow 0.2.2 → 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 (361) hide show
  1. package/README.md +45 -14
  2. package/bin/ai-delivery.mjs +181 -6
  3. package/bin/benchmark-autonomy.mjs +217 -0
  4. package/bin/release-check.mjs +382 -0
  5. package/docs/CLI-PARAMETER-REFERENCE.zh-CN.md +346 -0
  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 +120 -39
  11. package/docs/MAINTENANCE-VERIFICATION.zh-CN.md +51 -0
  12. package/docs/MOCK-SYSTEM.zh-CN.md +141 -0
  13. package/docs/NPM-RELEASE-MANAGEMENT.zh-CN.md +106 -0
  14. package/docs/PROJECT-MANUAL.zh-CN.md +154 -95
  15. package/docs/PROTOTYPE-MIGRATION.zh-CN.md +164 -0
  16. package/docs/STATE-CLI-MAINTENANCE.zh-CN.md +35 -17
  17. package/docs/STATE-CLI-USER-GUIDE.zh-CN.md +115 -39
  18. package/docs/VIEWER-MAINTENANCE.zh-CN.md +101 -324
  19. package/docs/VIEWER-USER-GUIDE.zh-CN.md +68 -190
  20. package/docs/adr/0001-prototype-first-ui-governance.md +3 -0
  21. package/docs/adr/0002-microcks-as-default-mock-system.md +3 -0
  22. package/docs/adr/0003-workflow-manager-governed-control-surface.md +46 -0
  23. package/docs/adr/0004-operational-carbon-visual-standard.md +9 -0
  24. package/docs/adr/0005-prototype-management-as-routed-pages.md +7 -0
  25. package/docs/agents/domain.md +12 -0
  26. package/docs/agents/issue-tracker.md +27 -0
  27. package/docs/agents/triage-labels.md +11 -0
  28. package/docs/agents/workflow-manager-acceptance-matrix.md +93 -0
  29. package/docs/agents/workflow-manager-agent-interface.md +145 -0
  30. package/docs/agents/workflow-manager-current-state.md +205 -0
  31. package/lib/artifact-files.mjs +47 -0
  32. package/lib/codegraph.mjs +405 -0
  33. package/lib/delivery-state.mjs +3079 -198
  34. package/lib/frontend-guard.mjs +288 -0
  35. package/lib/fs-utils.mjs +53 -0
  36. package/lib/history-anchor.mjs +98 -0
  37. package/lib/mock-scenario-pack.mjs +687 -0
  38. package/lib/mock-system.mjs +897 -0
  39. package/lib/npm-package-result.mjs +11 -0
  40. package/lib/png-evidence.mjs +149 -0
  41. package/lib/project-bootstrap.mjs +96 -55
  42. package/lib/project-installer.mjs +1484 -164
  43. package/lib/project-migration.mjs +1193 -0
  44. package/lib/prototype-migration.mjs +713 -0
  45. package/lib/prototype-page-review.mjs +384 -0
  46. package/lib/prototype-review-target.mjs +334 -0
  47. package/lib/prototype-revision.mjs +812 -0
  48. package/lib/stable-value.mjs +15 -0
  49. package/lib/toml-hooks.mjs +69 -0
  50. package/lib/ui-acceptance.mjs +565 -0
  51. package/lib/visual-standard.mjs +232 -0
  52. package/lib/workflow-manager-contracts.mjs +367 -0
  53. package/lib/workflow-manager-facts.mjs +778 -0
  54. package/lib/workflow-manager-governance.mjs +514 -0
  55. package/lib/workflow-manager-mock.mjs +183 -0
  56. package/lib/workflow-manager-prototypes.mjs +1847 -0
  57. package/lib/workflow-manager-public/assets/ibm-plex-mono-latin-400-normal-CvHOgSBP.woff +0 -0
  58. package/lib/workflow-manager-public/assets/ibm-plex-mono-latin-400-normal-DMJ8VG8y.woff2 +0 -0
  59. package/lib/workflow-manager-public/assets/ibm-plex-sans-latin-400-normal-CDDApCn2.woff2 +0 -0
  60. package/lib/workflow-manager-public/assets/ibm-plex-sans-latin-400-normal-CYLoc0-x.woff +0 -0
  61. package/lib/workflow-manager-public/assets/ibm-plex-sans-latin-500-normal-6ng42L7E.woff2 +0 -0
  62. package/lib/workflow-manager-public/assets/ibm-plex-sans-latin-500-normal-BgVn5rGT.woff +0 -0
  63. package/lib/workflow-manager-public/assets/ibm-plex-sans-latin-600-normal-Cu4Hd6ag.woff +0 -0
  64. package/lib/workflow-manager-public/assets/ibm-plex-sans-latin-600-normal-CuJfVYMP.woff2 +0 -0
  65. package/lib/workflow-manager-public/assets/index-Chlg6r8f.css +1 -0
  66. package/lib/workflow-manager-public/assets/index-E-hGB5ZD.js +13 -0
  67. package/lib/workflow-manager-public/fonts/OFL-1.1.txt +90 -0
  68. package/lib/workflow-manager-public/index.html +14 -0
  69. package/lib/workflow-manager-systems.mjs +519 -0
  70. package/lib/workflow-manager-transaction.mjs +397 -0
  71. package/lib/workflow-manager.mjs +745 -0
  72. package/package.json +8 -2
  73. package/skills/ai-delivery-assemble-release/agents/openai.yaml +3 -3
  74. package/skills/ai-delivery-assemble-release/assets/release-material-index.csv +1 -1
  75. package/skills/ai-delivery-assemble-release/assets/version-inclusion.csv +1 -1
  76. package/skills/ai-delivery-bootstrap/SKILL.md +4 -4
  77. package/skills/ai-delivery-bootstrap/agents/openai.yaml +3 -3
  78. package/skills/ai-delivery-bootstrap/references/bootstrap-contract.md +4 -2
  79. package/skills/ai-delivery-checkpoint-task/SKILL.md +17 -3
  80. package/skills/ai-delivery-checkpoint-task/agents/openai.yaml +3 -3
  81. package/skills/ai-delivery-checkpoint-task/assets/runtime-template/task.json +7 -1
  82. package/skills/ai-delivery-checkpoint-task/references/checkpoint-contract.md +22 -8
  83. package/skills/ai-delivery-checkpoint-task/scripts/hook-event.mjs +91 -0
  84. package/skills/ai-delivery-checkpoint-task/scripts/task-state.mjs +1086 -51
  85. package/skills/ai-delivery-close-version/SKILL.md +9 -8
  86. package/skills/ai-delivery-close-version/agents/openai.yaml +3 -3
  87. package/skills/ai-delivery-close-version/assets/version-lineage.yaml +1 -1
  88. package/skills/ai-delivery-close-version/references/version-closeout-contract.md +2 -2
  89. package/skills/ai-delivery-define-product/SKILL.md +8 -4
  90. package/skills/ai-delivery-define-product/agents/openai.yaml +4 -4
  91. package/skills/ai-delivery-define-product/references/product-contract.md +2 -2
  92. package/skills/ai-delivery-deploy-production/agents/openai.yaml +3 -3
  93. package/skills/ai-delivery-design-architecture/SKILL.md +9 -5
  94. package/skills/ai-delivery-design-architecture/assets/architecture-template/prototype-architecture-validation.yaml +16 -16
  95. package/skills/ai-delivery-design-architecture/references/architecture-contract.md +1 -1
  96. package/skills/ai-delivery-design-experience/SKILL.md +36 -30
  97. package/skills/ai-delivery-design-experience/agents/openai.yaml +4 -4
  98. package/skills/ai-delivery-design-experience/assets/experience-template/LEGACY-COMPATIBILITY.md +16 -0
  99. package/skills/ai-delivery-design-experience/assets/experience-template/design-reference-selection.yaml +32 -0
  100. package/skills/ai-delivery-design-experience/assets/experience-template/experience-baseline.yaml +2 -2
  101. package/skills/ai-delivery-design-experience/assets/experience-template/formal-ui-confirmation.yaml +16 -3
  102. package/skills/ai-delivery-design-experience/assets/experience-template/frontend-change-scope.yaml +30 -0
  103. package/skills/ai-delivery-design-experience/assets/experience-template/interaction-contract.csv +1 -1
  104. package/skills/ai-delivery-design-experience/assets/experience-template/mock-admin-export.yaml +8 -0
  105. package/skills/ai-delivery-design-experience/assets/experience-template/mock-scenario-mappings.csv +1 -0
  106. package/skills/ai-delivery-design-experience/assets/experience-template/mock-scenario-pack-request.yaml +24 -0
  107. package/skills/ai-delivery-design-experience/assets/experience-template/product-prototype-reconciliation.yaml +2 -1
  108. package/skills/ai-delivery-design-experience/assets/experience-template/prototype-adjustment-log.csv +1 -1
  109. package/skills/ai-delivery-design-experience/assets/experience-template/prototype-component-bindings.csv +1 -0
  110. package/skills/ai-delivery-design-experience/assets/experience-template/prototype-component-candidates.csv +1 -0
  111. package/skills/ai-delivery-design-experience/assets/experience-template/prototype-components.csv +1 -0
  112. package/skills/ai-delivery-design-experience/assets/experience-template/prototype-confirmation.yaml +18 -18
  113. package/skills/ai-delivery-design-experience/assets/experience-template/prototype-data-contracts.csv +1 -0
  114. package/skills/ai-delivery-design-experience/assets/experience-template/prototype-impact-assessment.yaml +5 -5
  115. package/skills/ai-delivery-design-experience/assets/experience-template/prototype-implementation-bindings.csv +1 -0
  116. package/skills/ai-delivery-design-experience/assets/experience-template/prototype-manifest.yaml +2 -0
  117. package/skills/ai-delivery-design-experience/assets/experience-template/prototype-pages.csv +1 -0
  118. package/skills/ai-delivery-design-experience/assets/experience-template/prototype-product-coverage.csv +1 -1
  119. package/skills/ai-delivery-design-experience/assets/experience-template/prototype-review-comments.csv +1 -1
  120. package/skills/ai-delivery-design-experience/assets/experience-template/prototype-review-decision.yaml +13 -12
  121. package/skills/ai-delivery-design-experience/assets/experience-template/prototype-review-scenes.csv +1 -0
  122. package/skills/ai-delivery-design-experience/assets/experience-template/prototype-review-sessions.csv +1 -1
  123. package/skills/ai-delivery-design-experience/assets/experience-template/prototype-review-unit-pages.csv +1 -0
  124. package/skills/ai-delivery-design-experience/assets/experience-template/prototype-review-units.csv +1 -0
  125. package/skills/ai-delivery-design-experience/assets/experience-template/prototype-revision.yaml +88 -0
  126. package/skills/ai-delivery-design-experience/assets/experience-template/prototype-routes.csv +1 -0
  127. package/skills/ai-delivery-design-experience/assets/experience-template/prototype-set.yaml +2 -0
  128. package/skills/ai-delivery-design-experience/assets/experience-template/prototype-source-inspection-snapshots.csv +1 -0
  129. package/skills/ai-delivery-design-experience/assets/experience-template/prototype-terminals.csv +1 -0
  130. package/skills/ai-delivery-design-experience/assets/experience-template/prototype-tool-candidates.csv +1 -1
  131. package/skills/ai-delivery-design-experience/assets/experience-template/prototype-tool-selection.yaml +2 -3
  132. package/skills/ai-delivery-design-experience/assets/experience-template/prototype-traceability.csv +1 -1
  133. package/skills/ai-delivery-design-experience/assets/experience-template/prototype-trigger-conditions.csv +1 -0
  134. package/skills/ai-delivery-design-experience/assets/experience-template/prototype.yaml +6 -0
  135. package/skills/ai-delivery-design-experience/assets/experience-template/ui-framework-selection.yaml +17 -1
  136. package/skills/ai-delivery-design-experience/assets/experience-template/ui-handoff.yaml +6 -5
  137. package/skills/ai-delivery-design-experience/assets/experience-template/ui-mapping.csv +1 -0
  138. package/skills/ai-delivery-design-experience/assets/experience-template/visual-direction.yaml +4 -0
  139. package/skills/ai-delivery-design-experience/assets/experience-template/visual-reference-manifest.yaml +23 -0
  140. package/skills/ai-delivery-design-experience/assets/experience-template/visual-reference.html +163 -0
  141. package/skills/ai-delivery-design-experience/assets/experience-template/visual-system-confirmation.yaml +11 -0
  142. package/skills/ai-delivery-design-experience/references/experience-contract.md +26 -27
  143. package/skills/ai-delivery-design-experience/references/prototype-management-contract.md +42 -21
  144. package/skills/ai-delivery-design-tests/SKILL.md +13 -7
  145. package/skills/ai-delivery-design-tests/assets/test-design-template/prototype-test-scope.csv +1 -1
  146. package/skills/ai-delivery-design-tests/assets/test-design-template/prototype-test-validation.yaml +17 -16
  147. package/skills/ai-delivery-design-tests/references/test-design-contract.md +7 -5
  148. package/skills/ai-delivery-develop-iteration/SKILL.md +18 -11
  149. package/skills/ai-delivery-develop-iteration/agents/openai.yaml +3 -3
  150. package/skills/ai-delivery-develop-iteration/assets/development-template/candidate-manifest.yaml +36 -0
  151. package/skills/ai-delivery-develop-iteration/assets/development-template/task-prototype-traceability.csv +1 -1
  152. package/skills/ai-delivery-develop-iteration/references/development-contract.md +5 -3
  153. package/skills/ai-delivery-evolve-workflow/agents/openai.yaml +3 -3
  154. package/skills/ai-delivery-execute-test/SKILL.md +6 -2
  155. package/skills/ai-delivery-execute-test/agents/openai.yaml +4 -4
  156. package/skills/ai-delivery-execute-work-package/SKILL.md +10 -3
  157. package/skills/ai-delivery-execute-work-package/agents/openai.yaml +4 -4
  158. package/skills/ai-delivery-execute-work-package/references/work-package-contract.md +1 -1
  159. package/skills/ai-delivery-manage-git/agents/openai.yaml +3 -3
  160. package/skills/ai-delivery-manage-standards/agents/openai.yaml +4 -4
  161. package/skills/ai-delivery-orchestrate/SKILL.md +47 -29
  162. package/skills/ai-delivery-orchestrate/agents/openai.yaml +3 -3
  163. package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/control/migrations/.gitkeep +0 -0
  164. package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/control/repairs/.gitkeep +0 -0
  165. package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/delivery/project.yaml +1 -0
  166. package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/delivery/workflow-state.yaml +2 -0
  167. package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/tools/frontend-guard/frontend-guard.mjs +50 -0
  168. package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/tools/hooks/hook-event.mjs +91 -0
  169. package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/tools/manager/manager.mjs +64 -0
  170. package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/tools/manager/start.cmd +4 -0
  171. package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/tools/manager/start.ps1 +2 -0
  172. package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/tools/{viewer → manager}/start.sh +1 -1
  173. package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/tools/mock/mock.mjs +50 -0
  174. package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/tools/ui-acceptance/ui-acceptance.mjs +37 -0
  175. package/skills/ai-delivery-orchestrate/assets/project-template/AGENTS.md +32 -6
  176. package/skills/ai-delivery-orchestrate/assets/project-template/gitignore.template +1 -0
  177. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/CONTRIBUTING.md +25 -0
  178. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/LICENSE +21 -0
  179. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/README.md +250 -0
  180. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/UPSTREAM.yaml +19 -0
  181. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/airbnb/DESIGN.md +545 -0
  182. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/airbnb/README.md +5 -0
  183. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/airtable/DESIGN.md +554 -0
  184. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/airtable/README.md +5 -0
  185. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/apple/DESIGN.md +562 -0
  186. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/apple/README.md +5 -0
  187. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/binance/DESIGN.md +634 -0
  188. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/binance/README.md +5 -0
  189. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/bmw/DESIGN.md +544 -0
  190. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/bmw/README.md +5 -0
  191. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/bmw-m/DESIGN.md +503 -0
  192. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/bmw-m/README.md +5 -0
  193. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/bugatti/DESIGN.md +454 -0
  194. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/bugatti/README.md +5 -0
  195. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/cal/DESIGN.md +542 -0
  196. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/cal/README.md +5 -0
  197. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/claude/DESIGN.md +589 -0
  198. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/claude/README.md +5 -0
  199. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/clay/DESIGN.md +541 -0
  200. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/clay/README.md +5 -0
  201. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/clickhouse/DESIGN.md +544 -0
  202. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/clickhouse/README.md +5 -0
  203. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/cohere/DESIGN.md +451 -0
  204. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/cohere/README.md +5 -0
  205. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/coinbase/DESIGN.md +570 -0
  206. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/coinbase/README.md +5 -0
  207. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/composio/DESIGN.md +506 -0
  208. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/composio/README.md +5 -0
  209. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/cursor/DESIGN.md +537 -0
  210. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/cursor/README.md +5 -0
  211. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/dell-1996/DESIGN.md +632 -0
  212. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/dell-1996/README.md +5 -0
  213. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/elevenlabs/DESIGN.md +504 -0
  214. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/elevenlabs/README.md +5 -0
  215. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/expo/DESIGN.md +526 -0
  216. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/expo/README.md +5 -0
  217. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/ferrari/DESIGN.md +531 -0
  218. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/ferrari/README.md +5 -0
  219. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/figma/DESIGN.md +578 -0
  220. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/figma/README.md +5 -0
  221. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/framer/DESIGN.md +544 -0
  222. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/framer/README.md +5 -0
  223. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/hashicorp/DESIGN.md +575 -0
  224. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/hashicorp/README.md +5 -0
  225. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/hp/DESIGN.md +670 -0
  226. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/hp/README.md +5 -0
  227. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/ibm/DESIGN.md +550 -0
  228. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/ibm/README.md +5 -0
  229. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/intercom/DESIGN.md +546 -0
  230. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/intercom/README.md +5 -0
  231. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/kraken/DESIGN.md +125 -0
  232. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/kraken/README.md +5 -0
  233. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/lamborghini/DESIGN.md +288 -0
  234. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/lamborghini/README.md +5 -0
  235. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/linear.app/DESIGN.md +548 -0
  236. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/linear.app/README.md +5 -0
  237. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/lovable/DESIGN.md +298 -0
  238. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/lovable/README.md +5 -0
  239. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/mastercard/DESIGN.md +365 -0
  240. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/mastercard/README.md +5 -0
  241. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/meta/DESIGN.md +683 -0
  242. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/meta/README.md +5 -0
  243. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/minimax/DESIGN.md +746 -0
  244. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/minimax/README.md +5 -0
  245. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/mintlify/DESIGN.md +852 -0
  246. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/mintlify/README.md +5 -0
  247. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/miro/DESIGN.md +825 -0
  248. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/miro/README.md +5 -0
  249. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/mistral.ai/DESIGN.md +773 -0
  250. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/mistral.ai/README.md +5 -0
  251. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/mongodb/DESIGN.md +767 -0
  252. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/mongodb/README.md +5 -0
  253. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/nike/DESIGN.md +575 -0
  254. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/nike/README.md +5 -0
  255. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/nintendo-2001/DESIGN.md +649 -0
  256. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/nintendo-2001/README.md +5 -0
  257. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/notion/DESIGN.md +821 -0
  258. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/notion/README.md +5 -0
  259. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/nvidia/DESIGN.md +640 -0
  260. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/nvidia/README.md +5 -0
  261. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/ollama/DESIGN.md +539 -0
  262. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/ollama/README.md +5 -0
  263. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/opencode.ai/DESIGN.md +521 -0
  264. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/opencode.ai/README.md +5 -0
  265. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/pinterest/DESIGN.md +597 -0
  266. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/pinterest/README.md +5 -0
  267. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/playstation/DESIGN.md +661 -0
  268. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/playstation/README.md +5 -0
  269. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/posthog/DESIGN.md +690 -0
  270. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/posthog/README.md +5 -0
  271. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/raycast/DESIGN.md +669 -0
  272. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/raycast/README.md +5 -0
  273. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/renault/DESIGN.md +589 -0
  274. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/renault/README.md +5 -0
  275. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/replicate/DESIGN.md +616 -0
  276. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/replicate/README.md +5 -0
  277. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/resend/DESIGN.md +585 -0
  278. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/resend/README.md +5 -0
  279. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/revolut/DESIGN.md +636 -0
  280. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/revolut/README.md +5 -0
  281. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/runwayml/DESIGN.md +244 -0
  282. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/runwayml/README.md +5 -0
  283. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/sanity/DESIGN.md +357 -0
  284. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/sanity/README.md +5 -0
  285. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/sentry/DESIGN.md +551 -0
  286. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/sentry/README.md +5 -0
  287. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/shopify/DESIGN.md +516 -0
  288. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/shopify/README.md +5 -0
  289. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/slack/DESIGN.md +482 -0
  290. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/spacex/DESIGN.md +363 -0
  291. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/spacex/README.md +5 -0
  292. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/spotify/DESIGN.md +246 -0
  293. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/spotify/README.md +5 -0
  294. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/starbucks/DESIGN.md +580 -0
  295. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/starbucks/README.md +5 -0
  296. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/stripe/DESIGN.md +487 -0
  297. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/stripe/README.md +5 -0
  298. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/supabase/DESIGN.md +462 -0
  299. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/supabase/README.md +5 -0
  300. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/superhuman/DESIGN.md +448 -0
  301. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/superhuman/README.md +5 -0
  302. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/tesla/DESIGN.md +286 -0
  303. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/tesla/README.md +5 -0
  304. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/theverge/DESIGN.md +339 -0
  305. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/theverge/README.md +5 -0
  306. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/together.ai/DESIGN.md +633 -0
  307. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/together.ai/README.md +5 -0
  308. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/uber/DESIGN.md +636 -0
  309. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/uber/README.md +5 -0
  310. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/vercel/DESIGN.md +736 -0
  311. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/vercel/README.md +5 -0
  312. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/vodafone/DESIGN.md +538 -0
  313. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/vodafone/README.md +5 -0
  314. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/voltagent/DESIGN.md +521 -0
  315. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/voltagent/README.md +5 -0
  316. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/warp/DESIGN.md +526 -0
  317. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/warp/README.md +5 -0
  318. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/webflow/DESIGN.md +588 -0
  319. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/webflow/README.md +5 -0
  320. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/wired/DESIGN.md +497 -0
  321. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/wired/README.md +5 -0
  322. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/wise/DESIGN.md +544 -0
  323. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/wise/README.md +5 -0
  324. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/x.ai/DESIGN.md +465 -0
  325. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/x.ai/README.md +5 -0
  326. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/zapier/DESIGN.md +537 -0
  327. package/skills/ai-delivery-orchestrate/assets/project-template/ref/ui/design-md/zapier/README.md +5 -0
  328. package/skills/ai-delivery-orchestrate/references/formal-state-contract.md +65 -20
  329. package/skills/ai-delivery-orchestrate/references/workflow-model.md +7 -5
  330. package/skills/ai-delivery-orchestrate-release/SKILL.md +2 -2
  331. package/skills/ai-delivery-orchestrate-release/agents/openai.yaml +4 -4
  332. package/skills/ai-delivery-orchestrate-release/references/release-workflow-contract.md +1 -1
  333. package/skills/ai-delivery-plan-iteration/SKILL.md +11 -4
  334. package/skills/ai-delivery-plan-iteration/agents/openai.yaml +4 -4
  335. package/skills/ai-delivery-plan-iteration/assets/planning-template/scope-manifest.yaml +17 -0
  336. package/skills/ai-delivery-plan-iteration/assets/planning-template/slice-prototype-traceability.csv +1 -1
  337. package/skills/ai-delivery-plan-iteration/references/planning-contract.md +8 -2
  338. package/skills/ai-delivery-prepare-platform/SKILL.md +5 -1
  339. package/skills/ai-delivery-prepare-platform/agents/openai.yaml +4 -4
  340. package/skills/ai-delivery-prepare-release/agents/openai.yaml +4 -4
  341. package/skills/ai-delivery-review-change/SKILL.md +14 -4
  342. package/skills/ai-delivery-review-change/agents/openai.yaml +4 -4
  343. package/skills/ai-delivery-review-change/references/review-contract.md +6 -0
  344. package/skills/ai-delivery-triage-failure/SKILL.md +5 -1
  345. package/skills/ai-delivery-triage-failure/agents/openai.yaml +4 -4
  346. package/skills/ai-delivery-validate-artifacts/SKILL.md +6 -3
  347. package/skills/ai-delivery-validate-artifacts/agents/openai.yaml +4 -4
  348. package/skills/ai-delivery-validate-artifacts/references/artifact-contract.md +13 -13
  349. package/skills/ai-delivery-verify-candidate/SKILL.md +13 -6
  350. package/skills/ai-delivery-verify-candidate/agents/openai.yaml +3 -3
  351. package/skills/ai-delivery-verify-candidate/assets/verification-template/ui-acceptance-request.yaml +19 -0
  352. package/skills/ai-delivery-verify-candidate/assets/verification-template/ui-acceptance-results.yaml +53 -0
  353. package/skills/ai-delivery-verify-candidate/references/candidate-verification-contract.md +10 -2
  354. package/skills/ai-delivery-verify-production/agents/openai.yaml +3 -3
  355. package/skills/ai-delivery-design-experience/assets/experience-template/low-fidelity-confirmation.yaml +0 -32
  356. package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/tools/viewer/public/app.js +0 -546
  357. package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/tools/viewer/public/index.html +0 -199
  358. package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/tools/viewer/public/styles.css +0 -529
  359. package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/tools/viewer/server.mjs +0 -780
  360. package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/tools/viewer/start.cmd +0 -4
  361. package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/tools/viewer/start.ps1 +0 -2
@@ -1,780 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- import crypto from "node:crypto";
4
- import fs from "node:fs";
5
- import http from "node:http";
6
- import path from "node:path";
7
- import { spawn, spawnSync } from "node:child_process";
8
- import { createRequire } from "node:module";
9
- import { fileURLToPath } from "node:url";
10
-
11
- const viewerRoot = path.dirname(fileURLToPath(import.meta.url));
12
- const require = createRequire(import.meta.url);
13
- const vendoredYaml = path.join(viewerRoot, "..", "state", "vendor", "yaml", "dist", "index.js");
14
- const yaml = require(fs.existsSync(vendoredYaml) ? vendoredYaml : "yaml");
15
- const publicRoot = path.join(viewerRoot, "public");
16
- const defaultProjectRoot = path.resolve(viewerRoot, "..", "..", "..");
17
- const MAX_PREVIEW_BYTES = 2 * 1024 * 1024;
18
- const MAX_SCAN_FILES = 10_000;
19
- const TEXT_EXTENSIONS = new Set([
20
- ".csv", ".html", ".ini", ".json", ".jsonl", ".md", ".mdx", ".properties",
21
- ".rst", ".toml", ".txt", ".xml", ".yaml", ".yml",
22
- ]);
23
- const IMAGE_EXTENSIONS = new Set([".gif", ".jpeg", ".jpg", ".png", ".webp"]);
24
-
25
- const DEVELOPMENT_NODE_DEFINITIONS = [
26
- ["00-bootstrap", "引导"],
27
- ["01-product-discovery", "产品发现"],
28
- ["02-product-definition", "产品定义"],
29
- ["03-architecture-initial", "初始架构"],
30
- ["04-experience-design", "体验设计"],
31
- ["05-architecture-reconcile", "架构校准"],
32
- ["06-platform-preparation", "平台准备"],
33
- ["07-iteration-planning", "迭代规划"],
34
- ["08-test-design", "测试设计"],
35
- ["09-development", "开发实现"],
36
- ["10-change-review", "变更审查"],
37
- ["11-candidate-verification", "候选验证"],
38
- ["12-version-closeout", "版本收尾"],
39
- ].map(([id, label], sequence) => ({ id, label, sequence, group: "development" }));
40
-
41
- const RELEASE_NODE_DEFINITIONS = [
42
- ["R00-release-request", "发布请求"],
43
- ["R01-version-selection", "版本选择"],
44
- ["R02-release-eligibility", "发布资格"],
45
- ["R03-material-aggregation", "物料整合"],
46
- ["R04-release-candidate", "发布候选"],
47
- ["R05-release-verification", "发布验证"],
48
- ["R06-release-preparation", "发布准备"],
49
- ["R07-production-approval", "生产审批"],
50
- ["R08-production-deployment", "生产部署"],
51
- ["R09-production-verification", "生产验证"],
52
- ["R10-release-archive", "发布归档"],
53
- ].map(([id, label], sequence) => ({ id, label, sequence, group: "release" }));
54
-
55
- const LEGACY_NODE_DEFINITIONS = [
56
- ["12-release-preparation", "历史发布准备"],
57
- ["13-production-approval", "历史生产审批"],
58
- ["14-production-deployment", "历史生产部署"],
59
- ["15-production-verification", "历史生产验证"],
60
- ["16-version-archive", "历史版本归档"],
61
- ].map(([id, label], sequence) => ({ id, label, sequence, group: "legacy" }));
62
-
63
- const NODE_DEFINITIONS = [
64
- ...DEVELOPMENT_NODE_DEFINITIONS,
65
- ...RELEASE_NODE_DEFINITIONS,
66
- ...LEGACY_NODE_DEFINITIONS,
67
- ];
68
-
69
- const NODE_ALIASES = new Map([
70
- ["bootstrap", "00-bootstrap"],
71
- ["product-discovery", "01-product-discovery"],
72
- ["product", "02-product-definition"],
73
- ["product-definition", "02-product-definition"],
74
- ["architecture-initial", "03-architecture-initial"],
75
- ["experience", "04-experience-design"],
76
- ["experience-design", "04-experience-design"],
77
- ["architecture", "05-architecture-reconcile"],
78
- ["architecture-reconcile", "05-architecture-reconcile"],
79
- ["platform-preparation", "06-platform-preparation"],
80
- ["iteration-planning", "07-iteration-planning"],
81
- ["planning", "07-iteration-planning"],
82
- ["test-design", "08-test-design"],
83
- ["development", "09-development"],
84
- ["change-review", "10-change-review"],
85
- ["review", "10-change-review"],
86
- ["candidate-verification", "11-candidate-verification"],
87
- ["version-closeout", "12-version-closeout"],
88
- ["release-request", "R00-release-request"],
89
- ["version-selection", "R01-version-selection"],
90
- ["release-eligibility", "R02-release-eligibility"],
91
- ["material-aggregation", "R03-material-aggregation"],
92
- ["release-candidate", "R04-release-candidate"],
93
- ["release-verification", "R05-release-verification"],
94
- ["R06-release-preparation", "R06-release-preparation"],
95
- ["R07-production-approval", "R07-production-approval"],
96
- ["R08-production-deployment", "R08-production-deployment"],
97
- ["R09-production-verification", "R09-production-verification"],
98
- ["release-archive", "R10-release-archive"],
99
- ["release-preparation", "12-release-preparation"],
100
- ["production-approval", "13-production-approval"],
101
- ["production-deployment", "14-production-deployment"],
102
- ["production-verification", "15-production-verification"],
103
- ["version-archive", "16-version-archive"],
104
- ["standards", "standards"],
105
- ["delivery", "governance"],
106
- ]);
107
-
108
- const STATUS_META = {
109
- approved: { label: "已批准", tone: "success" },
110
- valid: { label: "有效", tone: "success" },
111
- frozen: { label: "已冻结", tone: "success" },
112
- immutable: { label: "不可变", tone: "success" },
113
- deployed: { label: "已部署", tone: "success" },
114
- released: { label: "已发布", tone: "success" },
115
- "release-ready": { label: "待发布", tone: "success" },
116
- "included-in-release": { label: "已纳入发布", tone: "success" },
117
- completed: { label: "已完成", tone: "success" },
118
- passed: { label: "已通过", tone: "success" },
119
- ready: { label: "已就绪", tone: "success" },
120
- draft: { label: "草稿", tone: "neutral" },
121
- "review-draft": { label: "审阅草稿", tone: "neutral" },
122
- planned: { label: "已规划", tone: "neutral" },
123
- queued: { label: "待执行", tone: "neutral" },
124
- pending: { label: "待确认", tone: "warning" },
125
- "pending-approval": { label: "待批准", tone: "warning" },
126
- "pending-review": { label: "待审阅", tone: "warning" },
127
- running: { label: "进行中", tone: "warning" },
128
- observed: { label: "已观察", tone: "neutral" },
129
- proposed: { label: "已提案", tone: "warning" },
130
- trial: { label: "试运行", tone: "warning" },
131
- active: { label: "已启用", tone: "success" },
132
- disabled: { label: "已禁用", tone: "warning" },
133
- rejected: { label: "已拒绝", tone: "danger" },
134
- expired: { label: "已失效", tone: "neutral" },
135
- checkpointed: { label: "已检查点", tone: "warning" },
136
- stale: { label: "已过期", tone: "warning" },
137
- "rolled-back": { label: "已回滚", tone: "warning" },
138
- superseded: { label: "已替代", tone: "neutral" },
139
- archived: { label: "已归档", tone: "success" },
140
- changed: { label: "已变更", tone: "warning" },
141
- blocked: { label: "已阻塞", tone: "danger" },
142
- invalid: { label: "无效", tone: "danger" },
143
- failed: { label: "失败", tone: "danger" },
144
- missing: { label: "缺失", tone: "danger" },
145
- abandoned: { label: "已放弃", tone: "danger" },
146
- unknown: { label: "未标记", tone: "muted" },
147
- };
148
-
149
- function toPosix(value) {
150
- return value.replaceAll("\\", "/");
151
- }
152
-
153
- function parseArguments(argv) {
154
- const readValue = (flag, fallback) => {
155
- const index = argv.indexOf(flag);
156
- return index >= 0 && argv[index + 1] ? argv[index + 1] : fallback;
157
- };
158
- const port = Number(readValue("--port", process.env.AI_DELIVERY_VIEWER_PORT || "4173"));
159
- if (!Number.isInteger(port) || port < 1 || port > 65535) {
160
- throw new Error(`Invalid port: ${port}`);
161
- }
162
- return {
163
- host: readValue("--host", process.env.AI_DELIVERY_VIEWER_HOST || "127.0.0.1"),
164
- port,
165
- projectRoot: path.resolve(readValue("--project", defaultProjectRoot)),
166
- open: !argv.includes("--no-open"),
167
- };
168
- }
169
-
170
- function isInside(candidate, root) {
171
- const relative = path.relative(path.resolve(root), path.resolve(candidate));
172
- return relative === "" || (!relative.startsWith("..") && !path.isAbsolute(relative));
173
- }
174
-
175
- function readText(file, limit = MAX_PREVIEW_BYTES) {
176
- const stat = fs.statSync(file);
177
- if (stat.size > limit) return null;
178
- return fs.readFileSync(file, "utf8");
179
- }
180
-
181
- function scalar(text, keys) {
182
- if (!text) return null;
183
- for (const key of keys) {
184
- const expression = new RegExp(`^\\s*${key}\\s*:\\s*[\"']?([^\\r\\n#\"']+)`, "im");
185
- const match = text.match(expression);
186
- if (match?.[1]?.trim()) return match[1].trim();
187
- }
188
- return null;
189
- }
190
-
191
- function structuredData(text, extension) {
192
- if (!text) return null;
193
- try {
194
- if (extension === ".yaml" || extension === ".yml") return yaml.parse(text);
195
- if (extension === ".json") return JSON.parse(text);
196
- } catch {
197
- return null;
198
- }
199
- return null;
200
- }
201
-
202
- function normalizeStatus(value, changed) {
203
- if (changed) return { key: "changed", ...STATUS_META.changed };
204
- const raw = String(value || "").trim().toLowerCase().replaceAll("_", "-");
205
- const aliases = {
206
- accepted: "valid",
207
- "changes-required": "invalid",
208
- pass: "passed",
209
- success: "completed",
210
- };
211
- const key = STATUS_META[raw] ? raw : aliases[raw] || "unknown";
212
- return { key, ...STATUS_META[key] };
213
- }
214
-
215
- function fileType(extension) {
216
- const types = {
217
- ".md": "Markdown", ".mdx": "Markdown", ".csv": "CSV", ".yaml": "YAML",
218
- ".yml": "YAML", ".json": "JSON", ".jsonl": "JSONL", ".html": "原型",
219
- ".png": "图片", ".jpg": "图片", ".jpeg": "图片", ".webp": "图片",
220
- ".pdf": "PDF", ".txt": "文本", ".toml": "TOML",
221
- };
222
- return types[extension] || (extension ? extension.slice(1).toUpperCase() : "文件");
223
- }
224
-
225
- function titleFor(relativePath, text) {
226
- const extension = path.extname(relativePath).toLowerCase();
227
- if (extension === ".md" || extension === ".mdx") {
228
- const heading = text?.match(/^#\s+(.+)$/m)?.[1]?.trim();
229
- if (heading) return heading;
230
- }
231
- return scalar(text, ["title", "name", "artifact_id", "baseline_id", "release_id"])
232
- || path.basename(relativePath);
233
- }
234
-
235
- function normalizeNode(value) {
236
- if (!value) return null;
237
- if (NODE_DEFINITIONS.some((node) => node.id === value)) return value;
238
- if (value === "00-governance") return "governance";
239
- const withoutSequence = value.replace(/^\d{2}-/, "");
240
- return NODE_ALIASES.get(value) || NODE_ALIASES.get(withoutSequence) || value;
241
- }
242
-
243
- function nodeFor(relativePath, text) {
244
- const parts = relativePath.split("/");
245
- if (parts[1] === "iterations" && parts[3]) {
246
- return normalizeNode(parts[3]);
247
- }
248
- if (parts[1] === "releases" && parts[3]) {
249
- return normalizeNode(parts[3]);
250
- }
251
- if (parts[1] === "product") return "02-product-definition";
252
- if (parts[1] === "architecture") return "05-architecture-reconcile";
253
- if (parts[1] === "experience") return "04-experience-design";
254
- if (parts[1] === "standards") return "standards";
255
- if (parts[1] === "evolution" || parts[1] === "extensions") return "evolution";
256
- if (parts[1] === "delivery") {
257
- if (parts[2] === "bootstrap") return "00-bootstrap";
258
- if (parts[2] === "runtime" && parts.includes("archive")) return "16-version-archive";
259
- return "governance";
260
- }
261
- const declared = scalar(text, ["node", "node_id", "stage"]);
262
- return normalizeNode(declared) || "unassigned";
263
- }
264
-
265
- function releaseFor(relativePath, text) {
266
- const parts = relativePath.split("/");
267
- if (parts[1] === "releases" && parts[2]) return parts[2];
268
- return scalar(text, ["release_id"]) || null;
269
- }
270
-
271
- function iterationFor(relativePath, text) {
272
- const parts = relativePath.split("/");
273
- if (parts[1] === "iterations" && parts[2]) return parts[2];
274
- return scalar(text, ["iteration_id", "current_iteration_id"]) || null;
275
- }
276
-
277
- function gitChanges(projectRoot) {
278
- const result = spawnSync("git", ["status", "--porcelain=v1", "--untracked-files=all", "--", ".workflow"], {
279
- cwd: projectRoot,
280
- encoding: "utf8",
281
- windowsHide: true,
282
- });
283
- if (result.status !== 0) return new Map();
284
- const changes = new Map();
285
- for (const line of result.stdout.split(/\r?\n/).filter(Boolean)) {
286
- const code = line.slice(0, 2).trim() || "M";
287
- let file = line.slice(3).trim();
288
- if (file.includes(" -> ")) file = file.split(" -> ").at(-1);
289
- file = file.replace(/^"|"$/g, "").replaceAll("\\", "/");
290
- changes.set(file, code);
291
- }
292
- return changes;
293
- }
294
-
295
- function repositoryStatus(repositoryRoot, tagPattern) {
296
- const run = (args) => spawnSync("git", args, {
297
- cwd: repositoryRoot,
298
- encoding: "utf8",
299
- windowsHide: true,
300
- });
301
- const top = run(["rev-parse", "--show-toplevel"]);
302
- if (top.status !== 0 || path.resolve(top.stdout.trim()).toLowerCase() !== path.resolve(repositoryRoot).toLowerCase()) {
303
- return { repository: false, root: toPosix(repositoryRoot), tags: [] };
304
- }
305
- const branch = run(["branch", "--show-current"]);
306
- const head = run(["rev-parse", "HEAD"]);
307
- const status = run(["status", "--porcelain=v1", "--untracked-files=all"]);
308
- const upstream = run(["rev-parse", "--abbrev-ref", "--symbolic-full-name", "@{upstream}"]);
309
- let ahead = null;
310
- let behind = null;
311
- if (upstream.status === 0) {
312
- const divergence = run(["rev-list", "--left-right", "--count", "HEAD...@{upstream}"]);
313
- if (divergence.status === 0) [ahead, behind] = divergence.stdout.trim().split(/\s+/).map(Number);
314
- }
315
- const dirtyPaths = status.stdout.split(/\r?\n/).filter(Boolean).map((line) => toPosix(line.slice(3)));
316
- const tags = run(["tag", "--list", tagPattern, "--sort=version:refname"]);
317
- return {
318
- repository: true,
319
- root: toPosix(repositoryRoot),
320
- branch: branch.stdout.trim() || "main",
321
- head: head.status === 0 ? head.stdout.trim() : null,
322
- dirty_paths: dirtyPaths,
323
- upstream: upstream.status === 0 ? upstream.stdout.trim() : null,
324
- ahead,
325
- behind,
326
- sync_status: dirtyPaths.length ? "uncommitted"
327
- : ahead > 0 ? "unpushed"
328
- : behind > 0 ? "behind"
329
- : upstream.status === 0 ? "synchronized" : "no-upstream",
330
- tags: tags.status === 0 ? tags.stdout.split(/\r?\n/).filter(Boolean) : [],
331
- };
332
- }
333
-
334
- function workspaceStatus(projectRoot) {
335
- const configFile = path.join(projectRoot, ".workflow", "config", "workspace.yaml");
336
- let configuration = null;
337
- try {
338
- configuration = yaml.parse(fs.readFileSync(configFile, "utf8"));
339
- } catch {
340
- configuration = { code_repository: { repo_id: "app", path: "code" } };
341
- }
342
- const codePath = configuration?.code_repository?.path || "code";
343
- const codeRoot = path.resolve(projectRoot, codePath);
344
- const relative = path.relative(projectRoot, codeRoot);
345
- if (!relative || relative.startsWith("..") || path.isAbsolute(relative)) {
346
- throw new Error(`Invalid code repository path in workspace configuration: ${codePath}`);
347
- }
348
- const tasksRoot = path.join(projectRoot, ".workflow", "control", "tasks");
349
- const checkpointsRoot = path.join(projectRoot, ".workflow", "control", "checkpoints");
350
- const taskFiles = fs.existsSync(tasksRoot)
351
- ? fs.readdirSync(tasksRoot).filter((name) => /\.(json|ya?ml)$/i.test(name)) : [];
352
- const checkpointFiles = [];
353
- const visit = (directory) => {
354
- if (!fs.existsSync(directory)) return;
355
- for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {
356
- const absolute = path.join(directory, entry.name);
357
- if (entry.isDirectory()) visit(absolute);
358
- else if (entry.isFile() && /\.(json|ya?ml)$/i.test(entry.name)) checkpointFiles.push(absolute);
359
- }
360
- };
361
- visit(checkpointsRoot);
362
- return {
363
- configuration,
364
- workflow_git: repositoryStatus(projectRoot, "workflow-ready/*"),
365
- code_git: repositoryStatus(codeRoot, "version-ready/*"),
366
- shared_state: {
367
- task_count: taskFiles.length,
368
- checkpoint_count: checkpointFiles.length,
369
- latest_checkpoint: checkpointFiles
370
- .map((file) => ({ path: toPosix(path.relative(projectRoot, file)), mtime: fs.statSync(file).mtimeMs }))
371
- .sort((left, right) => right.mtime - left.mtime)[0]?.path || null,
372
- },
373
- };
374
- }
375
-
376
- function walkWorkflow(workflowRoot) {
377
- const files = [];
378
- let truncated = false;
379
- const visit = (directory) => {
380
- if (truncated) return;
381
- for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {
382
- if (files.length >= MAX_SCAN_FILES) {
383
- truncated = true;
384
- break;
385
- }
386
- const absolute = path.join(directory, entry.name);
387
- const relativeParts = path.relative(workflowRoot, absolute).split(path.sep);
388
- if (entry.isSymbolicLink()) continue;
389
- if (entry.isDirectory() && (
390
- relativeParts[0] === "tools"
391
- || (relativeParts[0] === "delivery" && relativeParts[1] === "runtime")
392
- )) continue;
393
- if (entry.isDirectory()) visit(absolute);
394
- else if (entry.isFile() && entry.name !== ".gitkeep") files.push(absolute);
395
- }
396
- };
397
- if (fs.existsSync(workflowRoot)) visit(workflowRoot);
398
- return { files, truncated };
399
- }
400
-
401
- function referencesFor(relativePath, text, knownPaths) {
402
- if (!text) return [];
403
- const references = new Set();
404
- const tokens = text.match(/(?:\.workflow\/|(?:\.\.\/|\.\/)+)[A-Za-z0-9._/@-]+/g) || [];
405
- for (const token of tokens) {
406
- const cleaned = token.replace(/[),.;:'"]+$/g, "");
407
- const resolved = cleaned.startsWith(".workflow/")
408
- ? cleaned
409
- : toPosix(path.normalize(path.join(path.dirname(relativePath), cleaned)));
410
- if (knownPaths.has(resolved)) references.add(resolved);
411
- }
412
- return [...references].sort();
413
- }
414
-
415
- function artifactRegistry(workflowRoot) {
416
- const registryFile = path.join(workflowRoot, "delivery", "artifact-registry.yaml");
417
- if (!fs.existsSync(registryFile)) return new Map();
418
- try {
419
- const parsed = yaml.parse(fs.readFileSync(registryFile, "utf8"));
420
- const entries = Array.isArray(parsed?.artifacts) ? parsed.artifacts : [];
421
- return new Map(entries
422
- .filter((artifact) => artifact && typeof artifact.path === "string")
423
- .map((artifact) => [artifact.path.replaceAll("\\", "/"), artifact]));
424
- } catch {
425
- return new Map();
426
- }
427
- }
428
-
429
- function evolutionSummary(workflowRoot) {
430
- const indexFile = path.join(workflowRoot, "evolution", "index.yaml");
431
- const empty = {
432
- schema_version: 1, revision: 0, feedback_count: 0, proposal_count: 0,
433
- trial_count: 0, active_count: 0, high_risk_count: 0, rollback_count: 0,
434
- hook_result_count: 0, updated_at: null,
435
- };
436
- if (!fs.existsSync(indexFile)) return empty;
437
- try {
438
- const index = yaml.parse(fs.readFileSync(indexFile, "utf8")) || {};
439
- const extensions = Array.isArray(index.extensions) ? index.extensions : [];
440
- const hookRoot = path.join(workflowRoot, "evolution", "experiments", "hook-results");
441
- return {
442
- schema_version: index.schema_version || 1,
443
- revision: index.revision || 0,
444
- feedback_count: Array.isArray(index.feedback) ? index.feedback.length : 0,
445
- proposal_count: Array.isArray(index.proposals) ? index.proposals.filter((item) => item.status === "proposed").length : 0,
446
- trial_count: extensions.filter((item) => item.state === "trial").length,
447
- active_count: extensions.filter((item) => item.state === "active").length,
448
- high_risk_count: extensions.filter((item) => item.effective_risk === "high" && ["trial", "active"].includes(item.state)).length,
449
- rollback_count: extensions.filter((item) => item.state === "rolled-back").length,
450
- hook_result_count: fs.existsSync(hookRoot)
451
- ? fs.readdirSync(hookRoot, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name !== ".gitkeep").length
452
- : 0,
453
- updated_at: index.updated_at || null,
454
- };
455
- } catch {
456
- return { ...empty, invalid: true };
457
- }
458
- }
459
-
460
- export function buildCatalog(projectRoot) {
461
- const workflowRoot = path.join(projectRoot, ".workflow");
462
- const { files, truncated } = walkWorkflow(workflowRoot);
463
- const changes = gitChanges(projectRoot);
464
- const registeredArtifacts = artifactRegistry(workflowRoot);
465
- const prepared = files.map((absolute) => {
466
- const relativePath = toPosix(path.relative(projectRoot, absolute));
467
- const extension = path.extname(absolute).toLowerCase();
468
- const stat = fs.statSync(absolute);
469
- const text = TEXT_EXTENSIONS.has(extension) ? readText(absolute) : null;
470
- const data = structuredData(text, extension);
471
- const changedCode = changes.get(relativePath) || null;
472
- const registered = registeredArtifacts.get(relativePath);
473
- const declaredStatus = registered?.status
474
- || scalar(text, ["status", "decision", "version_status", "state"]);
475
- const status = normalizeStatus(declaredStatus, Boolean(changedCode));
476
- return {
477
- path: relativePath,
478
- title: titleFor(relativePath, text),
479
- file_name: path.basename(relativePath),
480
- extension,
481
- type: fileType(extension),
482
- node_id: normalizeNode(registered?.node) || nodeFor(relativePath, text),
483
- iteration_id: iterationFor(relativePath, text),
484
- release_id: releaseFor(relativePath, text),
485
- release_mode: data?.mode || scalar(text, ["mode"]) || null,
486
- target_version_id: data?.target_version || data?.target_version_id
487
- || scalar(text, ["target_version", "target_version_id"]) || null,
488
- current_production_version: data?.current_production_version
489
- || scalar(text, ["current_production_version"]) || null,
490
- newly_included_versions: Array.isArray(data?.newly_included_versions)
491
- ? data.newly_included_versions.map(String) : [],
492
- status,
493
- declared_status: declaredStatus,
494
- version: registered?.version
495
- || scalar(text, ["version", "artifact_version", "schema_version"]) || null,
496
- artifact_id: registered?.artifact_id || registered?.id
497
- || scalar(text, ["artifact_id", "baseline_id", "release_id", "deployment_id"]) || null,
498
- standards: [...new Set(text?.match(/STD-[A-Z0-9-]+/g) || [])].sort(),
499
- modified_at: stat.mtime.toISOString(),
500
- size_bytes: stat.size,
501
- checksum: crypto.createHash("sha256").update(fs.readFileSync(absolute)).digest("hex"),
502
- git_status: changedCode,
503
- preview_kind: TEXT_EXTENSIONS.has(extension) && stat.size <= MAX_PREVIEW_BYTES
504
- ? "text"
505
- : IMAGE_EXTENSIONS.has(extension) ? "image" : "none",
506
- previewable: (TEXT_EXTENSIONS.has(extension) && stat.size <= MAX_PREVIEW_BYTES)
507
- || IMAGE_EXTENSIONS.has(extension),
508
- _text: text,
509
- };
510
- });
511
- const knownPaths = new Set(prepared.map((item) => item.path));
512
- const inbound = new Map(prepared.map((item) => [item.path, []]));
513
- for (const item of prepared) {
514
- item.outbound = referencesFor(item.path, item._text, knownPaths);
515
- for (const target of item.outbound) inbound.get(target)?.push(item.path);
516
- }
517
- for (const item of prepared) {
518
- item.inbound = (inbound.get(item.path) || []).sort();
519
- delete item._text;
520
- }
521
- prepared.sort((left, right) =>
522
- left.node_id.localeCompare(right.node_id)
523
- || right.modified_at.localeCompare(left.modified_at)
524
- || left.path.localeCompare(right.path));
525
-
526
- const projectText = fs.existsSync(path.join(workflowRoot, "delivery", "project.yaml"))
527
- ? readText(path.join(workflowRoot, "delivery", "project.yaml"))
528
- : "";
529
- const workflowText = fs.existsSync(path.join(workflowRoot, "delivery", "workflow-state.yaml"))
530
- ? readText(path.join(workflowRoot, "delivery", "workflow-state.yaml"))
531
- : "";
532
- const formalState = structuredData(workflowText, ".yaml") || {};
533
- const currentIteration = formalState.development_state?.scope_id
534
- || scalar(workflowText, ["iteration_id"])
535
- || scalar(projectText, ["current_iteration_id"])
536
- || prepared.map((item) => item.iteration_id).filter(Boolean).sort().at(-1)
537
- || null;
538
- const iterations = [...new Set([
539
- ...(currentIteration ? [currentIteration] : []),
540
- ...prepared.map((item) => item.iteration_id).filter(Boolean),
541
- ])].sort().reverse();
542
- const releaseNodeIds = new Set(RELEASE_NODE_DEFINITIONS.map((node) => node.id));
543
- const releaseDocuments = prepared.filter((item) => item.release_id && releaseNodeIds.has(item.node_id))
544
- .sort((left, right) => right.modified_at.localeCompare(left.modified_at));
545
- const activeReleaseId = formalState.release_state?.scope_id
546
- || releaseDocuments[0]?.release_id
547
- || null;
548
- const activeReleaseDocuments = releaseDocuments.filter((item) => item.release_id === activeReleaseId);
549
- const releaseSelection = activeReleaseDocuments.find((item) => item.node_id === "R01-version-selection")
550
- || activeReleaseDocuments.find((item) => item.target_version_id)
551
- || null;
552
- const releases = [...new Set(releaseDocuments.map((item) => item.release_id))];
553
- const nodes = [
554
- { id: "governance", label: "流程治理", sequence: -2, group: "governance" },
555
- { id: "standards", label: "项目规范", sequence: -1, group: "governance" },
556
- { id: "evolution", label: "自进化", sequence: 0, group: "governance" },
557
- ...NODE_DEFINITIONS,
558
- ].map((node) => {
559
- const documents = prepared.filter((item) => {
560
- if (item.node_id !== node.id) return false;
561
- if (node.group === "development") {
562
- return !currentIteration || !item.iteration_id || item.iteration_id === currentIteration;
563
- }
564
- if (node.group === "release") return !activeReleaseId || item.release_id === activeReleaseId;
565
- return true;
566
- });
567
- const tones = documents.map((item) => item.status.tone);
568
- const tone = tones.includes("danger") ? "danger"
569
- : tones.includes("warning") ? "warning"
570
- : tones.includes("success") ? "success" : "muted";
571
- return { ...node, document_count: documents.length, tone };
572
- });
573
- const counts = Object.fromEntries(["success", "warning", "danger", "neutral", "muted"]
574
- .map((tone) => [tone, prepared.filter((item) => item.status.tone === tone).length]));
575
- const workspace = workspaceStatus(projectRoot);
576
- const traceability = prepared.filter((item) => item.node_id === "12-version-closeout")
577
- .map((item) => ({
578
- version_id: item.iteration_id || item.artifact_id,
579
- manifest_path: item.path,
580
- manifest_sha256: item.checksum,
581
- code_tag: scalar(fs.readFileSync(path.join(projectRoot, item.path), "utf8"), ["code_tag", "version_ready_tag"]),
582
- workflow_tag: scalar(fs.readFileSync(path.join(projectRoot, item.path), "utf8"), ["workflow_tag", "workflow_ready_tag"]),
583
- }))
584
- .filter((item) => item.code_tag || item.workflow_tag);
585
- return {
586
- schema_version: 1,
587
- scanned_at: new Date().toISOString(),
588
- project: {
589
- id: scalar(projectText, ["project_id"]) || path.basename(projectRoot),
590
- name: scalar(projectText, ["name", "project_name"]) || path.basename(projectRoot),
591
- root: toPosix(projectRoot),
592
- workflow_root: ".workflow",
593
- current_iteration_id: currentIteration,
594
- production_version_id: scalar(workflowText, ["production_version_id"])
595
- || scalar(projectText, ["production_version_id"]) || null,
596
- production_release_id: scalar(workflowText, ["production_release_id"])
597
- || scalar(projectText, ["production_release_id"]) || null,
598
- latest_line_version_id: scalar(workflowText, ["latest_line_version_id"])
599
- || scalar(projectText, ["latest_line_version_id"]) || null,
600
- release_ready_count: new Set(prepared
601
- .filter((item) => item.node_id === "12-version-closeout" && item.status.key === "release-ready")
602
- .map((item) => item.iteration_id || item.artifact_id || item.path)).size,
603
- active_release_id: activeReleaseId,
604
- selected_target_version: releaseSelection?.target_version_id || null,
605
- release_mode: releaseSelection?.release_mode || null,
606
- newly_included_versions: releaseSelection?.newly_included_versions || [],
607
- },
608
- iterations,
609
- releases,
610
- nodes,
611
- documents: prepared,
612
- counts,
613
- repositories: {
614
- workflow: workspace.workflow_git,
615
- code: workspace.code_git,
616
- code_repo_id: workspace.configuration?.code_repository?.repo_id || "app",
617
- },
618
- shared_state: workspace.shared_state,
619
- traceability,
620
- evolution: evolutionSummary(workflowRoot),
621
- truncated,
622
- };
623
- }
624
-
625
- function sendJson(response, status, value) {
626
- const body = `${JSON.stringify(value)}\n`;
627
- response.writeHead(status, {
628
- "Content-Type": "application/json; charset=utf-8",
629
- "Cache-Control": "no-store",
630
- "Content-Length": Buffer.byteLength(body),
631
- });
632
- response.end(body);
633
- }
634
-
635
- function serveStatic(response, pathname) {
636
- const relative = pathname === "/" ? "index.html" : pathname.slice(1);
637
- const file = path.resolve(publicRoot, relative);
638
- if (!isInside(file, publicRoot) || !fs.existsSync(file) || !fs.statSync(file).isFile()) {
639
- sendJson(response, 404, { error: "Not found" });
640
- return;
641
- }
642
- const types = {
643
- ".html": "text/html; charset=utf-8",
644
- ".css": "text/css; charset=utf-8",
645
- ".js": "text/javascript; charset=utf-8",
646
- ".png": "image/png",
647
- ".svg": "image/svg+xml",
648
- };
649
- const body = fs.readFileSync(file);
650
- response.writeHead(200, {
651
- "Content-Type": types[path.extname(file)] || "application/octet-stream",
652
- "Content-Length": body.length,
653
- "Cache-Control": "no-cache",
654
- "Content-Security-Policy": "default-src 'self'; img-src 'self' data:; style-src 'self'; script-src 'self'; connect-src 'self'; object-src 'none'; base-uri 'none'; frame-ancestors 'none'",
655
- "X-Content-Type-Options": "nosniff",
656
- "Referrer-Policy": "no-referrer",
657
- });
658
- response.end(body);
659
- }
660
-
661
- export function createViewerServer(projectRoot) {
662
- const root = path.resolve(projectRoot);
663
- const workflowRoot = path.join(root, ".workflow");
664
- return http.createServer((request, response) => {
665
- try {
666
- const url = new URL(request.url || "/", "http://localhost");
667
- if (request.method !== "GET") {
668
- sendJson(response, 405, { error: "Method not allowed" });
669
- return;
670
- }
671
- if (url.pathname === "/api/health") {
672
- sendJson(response, 200, { ok: true, project_root: toPosix(root) });
673
- return;
674
- }
675
- if (url.pathname === "/api/catalog") {
676
- sendJson(response, 200, buildCatalog(root));
677
- return;
678
- }
679
- if (url.pathname === "/api/document") {
680
- const requested = url.searchParams.get("path") || "";
681
- const absolute = path.resolve(root, requested);
682
- if (!requested.startsWith(".workflow/") || !isInside(absolute, workflowRoot)) {
683
- sendJson(response, 403, { error: "Only .workflow documents may be read" });
684
- return;
685
- }
686
- if (!fs.existsSync(absolute) || !fs.statSync(absolute).isFile()) {
687
- sendJson(response, 404, { error: "Document not found" });
688
- return;
689
- }
690
- const stat = fs.statSync(absolute);
691
- if (stat.size > MAX_PREVIEW_BYTES) {
692
- sendJson(response, 413, { error: "Document is larger than the 2 MiB preview limit" });
693
- return;
694
- }
695
- const extension = path.extname(absolute).toLowerCase();
696
- if (!TEXT_EXTENSIONS.has(extension)) {
697
- sendJson(response, 415, { error: "This file type has no text preview" });
698
- return;
699
- }
700
- sendJson(response, 200, {
701
- path: requested,
702
- extension,
703
- content: fs.readFileSync(absolute, "utf8"),
704
- });
705
- return;
706
- }
707
- if (url.pathname === "/api/file") {
708
- const requested = url.searchParams.get("path") || "";
709
- const absolute = path.resolve(root, requested);
710
- if (!requested.startsWith(".workflow/") || !isInside(absolute, workflowRoot)) {
711
- sendJson(response, 403, { error: "Only .workflow files may be read" });
712
- return;
713
- }
714
- if (!fs.existsSync(absolute) || !fs.statSync(absolute).isFile()) {
715
- sendJson(response, 404, { error: "File not found" });
716
- return;
717
- }
718
- const extension = path.extname(absolute).toLowerCase();
719
- if (!IMAGE_EXTENSIONS.has(extension)) {
720
- sendJson(response, 415, { error: "Only image previews are served by this endpoint" });
721
- return;
722
- }
723
- const contentTypes = {
724
- ".gif": "image/gif",
725
- ".jpeg": "image/jpeg",
726
- ".jpg": "image/jpeg",
727
- ".png": "image/png",
728
- ".webp": "image/webp",
729
- };
730
- const body = fs.readFileSync(absolute);
731
- response.writeHead(200, {
732
- "Content-Type": contentTypes[extension],
733
- "Content-Length": body.length,
734
- "Cache-Control": "no-store",
735
- "X-Content-Type-Options": "nosniff",
736
- });
737
- response.end(body);
738
- return;
739
- }
740
- serveStatic(response, url.pathname);
741
- } catch (error) {
742
- sendJson(response, 500, { error: error.message });
743
- }
744
- });
745
- }
746
-
747
- function openBrowser(url) {
748
- const command = process.platform === "win32"
749
- ? ["cmd", ["/c", "start", "", url]]
750
- : process.platform === "darwin"
751
- ? ["open", [url]]
752
- : ["xdg-open", [url]];
753
- try {
754
- spawn(command[0], command[1], {
755
- detached: true,
756
- stdio: "ignore",
757
- windowsHide: true,
758
- }).unref();
759
- } catch {
760
- // The printed URL remains usable when no desktop browser opener is available.
761
- }
762
- }
763
-
764
- if (path.resolve(process.argv[1] || "") === path.resolve(fileURLToPath(import.meta.url))) {
765
- try {
766
- const options = parseArguments(process.argv.slice(2));
767
- if (!fs.existsSync(options.projectRoot) || !fs.statSync(options.projectRoot).isDirectory()) {
768
- throw new Error(`Project directory does not exist: ${options.projectRoot}`);
769
- }
770
- const server = createViewerServer(options.projectRoot);
771
- server.listen(options.port, options.host, () => {
772
- const url = `http://${options.host}:${options.port}`;
773
- process.stdout.write(`AI Delivery Viewer\nProject: ${options.projectRoot}\nURL: ${url}\nPress Ctrl+C to stop.\n`);
774
- if (options.open) openBrowser(url);
775
- });
776
- } catch (error) {
777
- process.stderr.write(`ai-delivery-viewer: ${error.message}\n`);
778
- process.exitCode = 1;
779
- }
780
- }