create-yss-spec 1.1.1 → 1.1.3

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 (257) hide show
  1. package/package.json +1 -1
  2. package/template/.agents/skills/high-fidelity-html-prototype/SKILL.md +102 -0
  3. package/template/.codex/skills/data-analytics/.app.json +84 -0
  4. package/template/.codex/skills/data-analytics/.codex-plugin/plugin.json +66 -0
  5. package/template/.codex/skills/data-analytics/.mcp.json +30 -0
  6. package/template/.codex/skills/data-analytics/AGENTS.md +20 -0
  7. package/template/.codex/skills/data-analytics/DEPENDENCIES.MD +27 -0
  8. package/template/.codex/skills/data-analytics/README.md +60 -0
  9. package/template/.codex/skills/data-analytics/assets/datascience-artifact-widget.html +16 -0
  10. package/template/.codex/skills/data-analytics/assets/datascience-artifact-widget.html.gz.b64.part001 +1 -0
  11. package/template/.codex/skills/data-analytics/assets/datascience-artifact-widget.html.gz.b64.part002 +1 -0
  12. package/template/.codex/skills/data-analytics/assets/datascience-artifact-widget.html.gz.b64.part003 +1 -0
  13. package/template/.codex/skills/data-analytics/assets/datascience-artifact-widget.html.gz.b64.part004 +1 -0
  14. package/template/.codex/skills/data-analytics/assets/datascience-artifact-widget.html.gz.b64.part005 +1 -0
  15. package/template/.codex/skills/data-analytics/assets/datascience-artifact-widget.html.gz.b64.part006 +1 -0
  16. package/template/.codex/skills/data-analytics/assets/datascience-chart-widget.html +16 -0
  17. package/template/.codex/skills/data-analytics/assets/datascience-chart-widget.html.gz.b64.part001 +1 -0
  18. package/template/.codex/skills/data-analytics/assets/datascience-chart-widget.html.gz.b64.part002 +1 -0
  19. package/template/.codex/skills/data-analytics/assets/datascience-chart-widget.html.gz.b64.part003 +1 -0
  20. package/template/.codex/skills/data-analytics/assets/datascience-chart-widget.html.gz.b64.part004 +1 -0
  21. package/template/.codex/skills/data-analytics/assets/datascience-chart-widget.html.gz.b64.part005 +1 -0
  22. package/template/.codex/skills/data-analytics/assets/datascience-chart-widget.html.gz.b64.part006 +1 -0
  23. package/template/.codex/skills/data-analytics/assets/datascience-chart-widget.html.gz.b64.part007 +1 -0
  24. package/template/.codex/skills/data-analytics/assets/datascience-small.svg +5 -0
  25. package/template/.codex/skills/data-analytics/assets/datascience-table-widget.html +16 -0
  26. package/template/.codex/skills/data-analytics/assets/datascience-table-widget.html.gz.b64.part001 +1 -0
  27. package/template/.codex/skills/data-analytics/assets/datascience-table-widget.html.gz.b64.part002 +1 -0
  28. package/template/.codex/skills/data-analytics/assets/datascience-table-widget.html.gz.b64.part003 +1 -0
  29. package/template/.codex/skills/data-analytics/assets/datascience-table-widget.html.gz.b64.part004 +1 -0
  30. package/template/.codex/skills/data-analytics/assets/datascience.png +0 -0
  31. package/template/.codex/skills/data-analytics/assets/datascience.svg +10 -0
  32. package/template/.codex/skills/data-analytics/mcp/server.cjs +2963 -0
  33. package/template/.codex/skills/data-analytics/package-lock.json +3048 -0
  34. package/template/.codex/skills/data-analytics/package.json +43 -0
  35. package/template/.codex/skills/data-analytics/scripts/normalize-widget-assets.mjs +75 -0
  36. package/template/.codex/skills/data-analytics/skills/analyze-data-quality/SKILL.md +160 -0
  37. package/template/.codex/skills/data-analytics/skills/analyze-data-quality/agents/openai.yaml +6 -0
  38. package/template/.codex/skills/data-analytics/skills/build-dashboard/SKILL.md +148 -0
  39. package/template/.codex/skills/data-analytics/skills/build-dashboard/agents/openai.yaml +6 -0
  40. package/template/.codex/skills/data-analytics/skills/build-dashboard/specifications/bi-platform-dashboard.md +18 -0
  41. package/template/.codex/skills/data-analytics/skills/build-dashboard/specifications/html-dashboard.md +24 -0
  42. package/template/.codex/skills/data-analytics/skills/build-dashboard/specifications/mcp-artifact-dashboard.md +71 -0
  43. package/template/.codex/skills/data-analytics/skills/build-dashboard/specifications/streamlit-dashboard.md +85 -0
  44. package/template/.codex/skills/data-analytics/skills/build-report/SKILL.md +207 -0
  45. package/template/.codex/skills/data-analytics/skills/build-report/agents/openai.yaml +6 -0
  46. package/template/.codex/skills/data-analytics/skills/build-report/assets/executive-report-shell.html +70 -0
  47. package/template/.codex/skills/data-analytics/skills/build-report/assets/technical-report-shell.html +66 -0
  48. package/template/.codex/skills/data-analytics/skills/build-report/report-to-google-doc/SKILL.md +118 -0
  49. package/template/.codex/skills/data-analytics/skills/build-report/report-to-google-doc/agents/openai.yaml +6 -0
  50. package/template/.codex/skills/data-analytics/skills/build-report/report-to-google-doc/scripts/report_to_google_doc/__init__.py +1 -0
  51. package/template/.codex/skills/data-analytics/skills/build-report/report-to-google-doc/scripts/report_to_google_doc/cli.py +57 -0
  52. package/template/.codex/skills/data-analytics/skills/build-report/report-to-google-doc/scripts/report_to_google_doc/constants.py +61 -0
  53. package/template/.codex/skills/data-analytics/skills/build-report/report-to-google-doc/scripts/report_to_google_doc/docx_writer.py +362 -0
  54. package/template/.codex/skills/data-analytics/skills/build-report/report-to-google-doc/scripts/report_to_google_doc/html_parser.py +829 -0
  55. package/template/.codex/skills/data-analytics/skills/build-report/report-to-google-doc/scripts/report_to_google_doc/model.py +30 -0
  56. package/template/.codex/skills/data-analytics/skills/build-report/report-to-google-doc/scripts/report_to_google_doc/plan.py +129 -0
  57. package/template/.codex/skills/data-analytics/skills/build-report/report-to-google-doc/scripts/report_to_google_doc/quality.py +374 -0
  58. package/template/.codex/skills/data-analytics/skills/build-report/report-to-google-doc/scripts/report_to_google_doc/rendering.py +613 -0
  59. package/template/.codex/skills/data-analytics/skills/build-report/report-to-google-doc/scripts/report_to_google_doc/table_utils.py +54 -0
  60. package/template/.codex/skills/data-analytics/skills/build-report/report-to-google-doc/scripts/report_to_google_doc/utils.py +16 -0
  61. package/template/.codex/skills/data-analytics/skills/build-report/report-to-google-doc/scripts/report_to_google_doc_plan.py +9 -0
  62. package/template/.codex/skills/data-analytics/skills/build-report/report-to-google-slides/SKILL.md +78 -0
  63. package/template/.codex/skills/data-analytics/skills/build-report/report-to-google-slides/agents/openai.yaml +6 -0
  64. package/template/.codex/skills/data-analytics/skills/build-report/report-to-google-slides/scripts/report_to_google_slides.py +2379 -0
  65. package/template/.codex/skills/data-analytics/skills/build-report/report-to-pdf/SKILL.md +88 -0
  66. package/template/.codex/skills/data-analytics/skills/build-report/report-to-pdf/agents/openai.yaml +6 -0
  67. package/template/.codex/skills/data-analytics/skills/build-report/specifications/executive-report.md +97 -0
  68. package/template/.codex/skills/data-analytics/skills/build-report/specifications/mcp-app-report.md +59 -0
  69. package/template/.codex/skills/data-analytics/skills/build-report/specifications/technical-report.md +75 -0
  70. package/template/.codex/skills/data-analytics/skills/design-kpis/SKILL.md +103 -0
  71. package/template/.codex/skills/data-analytics/skills/design-kpis/agents/openai.yaml +6 -0
  72. package/template/.codex/skills/data-analytics/skills/gather-business-context/SKILL.md +68 -0
  73. package/template/.codex/skills/data-analytics/skills/gather-business-context/agents/openai.yaml +6 -0
  74. package/template/.codex/skills/data-analytics/skills/index/SKILL.md +251 -0
  75. package/template/.codex/skills/data-analytics/skills/index/agents/openai.yaml +6 -0
  76. package/template/.codex/skills/data-analytics/skills/jupyter-notebooks/SKILL.md +131 -0
  77. package/template/.codex/skills/data-analytics/skills/jupyter-notebooks/agents/openai.yaml +6 -0
  78. package/template/.codex/skills/data-analytics/skills/kpi-reporting/SKILL.md +141 -0
  79. package/template/.codex/skills/data-analytics/skills/kpi-reporting/agents/openai.yaml +6 -0
  80. package/template/.codex/skills/data-analytics/skills/kpi-reporting/references/report-templates.md +32 -0
  81. package/template/.codex/skills/data-analytics/skills/market-sizing/SKILL.md +106 -0
  82. package/template/.codex/skills/data-analytics/skills/market-sizing/agents/openai.yaml +6 -0
  83. package/template/.codex/skills/data-analytics/skills/metric-diagnostics/SKILL.md +130 -0
  84. package/template/.codex/skills/data-analytics/skills/metric-diagnostics/agents/openai.yaml +6 -0
  85. package/template/.codex/skills/data-analytics/skills/product-business-analysis/SKILL.md +141 -0
  86. package/template/.codex/skills/data-analytics/skills/product-business-analysis/agents/openai.yaml +6 -0
  87. package/template/.codex/skills/data-analytics/skills/spreadsheets/SKILL.md +178 -0
  88. package/template/.codex/skills/data-analytics/skills/spreadsheets/agents/openai.yaml +9 -0
  89. package/template/.codex/skills/data-analytics/skills/spreadsheets/assets/file-spreadsheet.png +0 -0
  90. package/template/.codex/skills/data-analytics/skills/spreadsheets/charts.md +31 -0
  91. package/template/.codex/skills/data-analytics/skills/spreadsheets/references/artifact_tool_api.md +466 -0
  92. package/template/.codex/skills/data-analytics/skills/spreadsheets/style_guidelines.md +99 -0
  93. package/template/.codex/skills/data-analytics/skills/user-context/SKILL.md +195 -0
  94. package/template/.codex/skills/data-analytics/skills/user-context/agents/openai.yaml +6 -0
  95. package/template/.codex/skills/data-analytics/skills/user-context/plugin-author-config/automation-config.md +26 -0
  96. package/template/.codex/skills/data-analytics/skills/user-context/plugin-author-config/source-category-config.json +51 -0
  97. package/template/.codex/skills/data-analytics/skills/user-context/plugin-author-config/user-context-config.md +66 -0
  98. package/template/.codex/skills/data-analytics/skills/user-context/references/automation.md +69 -0
  99. package/template/.codex/skills/data-analytics/skills/user-context/references/onboarding-examples.md +204 -0
  100. package/template/.codex/skills/data-analytics/skills/user-context/references/onboarding-state-template.json +87 -0
  101. package/template/.codex/skills/data-analytics/skills/user-context/references/onboarding.md +497 -0
  102. package/template/.codex/skills/data-analytics/skills/user-context/references/semantic-layer/connector-playbook.md +74 -0
  103. package/template/.codex/skills/data-analytics/skills/user-context/references/semantic-layer/setup.md +65 -0
  104. package/template/.codex/skills/data-analytics/skills/user-context/references/semantic-layer/skill-template.md +160 -0
  105. package/template/.codex/skills/data-analytics/skills/user-context/references/semantic-layer/source-intake.md +75 -0
  106. package/template/.codex/skills/data-analytics/skills/user-context/references/semantic-layer/weekly-polling-automation.md +96 -0
  107. package/template/.codex/skills/data-analytics/skills/user-context/references/source-category-runtime.md +263 -0
  108. package/template/.codex/skills/data-analytics/skills/user-context/scripts/data_analytics_preflight.py +1460 -0
  109. package/template/.codex/skills/data-analytics/skills/user-context/scripts/init_user_context_state.py +128 -0
  110. package/template/.codex/skills/data-analytics/skills/user-context/scripts/reset_user_context_state.py +101 -0
  111. package/template/.codex/skills/data-analytics/skills/user-context/scripts/validate_user_context_preflight.py +499 -0
  112. package/template/.codex/skills/data-analytics/skills/user-context/tests/test_state_helpers.py +978 -0
  113. package/template/.codex/skills/data-analytics/skills/validate-data/SKILL.md +190 -0
  114. package/template/.codex/skills/data-analytics/skills/validate-data/agents/openai.yaml +6 -0
  115. package/template/.codex/skills/data-analytics/skills/visualize-data/SKILL.md +157 -0
  116. package/template/.codex/skills/data-analytics/skills/visualize-data/agents/openai.yaml +6 -0
  117. package/template/.codex/skills/data-analytics/skills/visualize-data/references/seaborn-templates.md +774 -0
  118. package/template/.codex/skills/data-analytics/src/DESIGN.md +222 -0
  119. package/template/.codex/skills/data-analytics/src/analytics-app/App.tsx +3666 -0
  120. package/template/.codex/skills/data-analytics/src/analytics-app/analytics-layout.test.mjs +136 -0
  121. package/template/.codex/skills/data-analytics/src/analytics-app/charting/ChartFrame.tsx +54 -0
  122. package/template/.codex/skills/data-analytics/src/analytics-app/charting/ChartLegend.tsx +96 -0
  123. package/template/.codex/skills/data-analytics/src/analytics-app/charting/ChartRenderer.tsx +1647 -0
  124. package/template/.codex/skills/data-analytics/src/analytics-app/charting/ChartTooltip.tsx +245 -0
  125. package/template/.codex/skills/data-analytics/src/analytics-app/charting/chart-app-helpers.tsx +462 -0
  126. package/template/.codex/skills/data-analytics/src/analytics-app/charting/chart-capabilities.ts +107 -0
  127. package/template/.codex/skills/data-analytics/src/analytics-app/charting/chart-compatibility.ts +164 -0
  128. package/template/.codex/skills/data-analytics/src/analytics-app/charting/chart-contract.ts +192 -0
  129. package/template/.codex/skills/data-analytics/src/analytics-app/charting/chart-theme.ts +203 -0
  130. package/template/.codex/skills/data-analytics/src/analytics-app/charting/chart-tokens.css +619 -0
  131. package/template/.codex/skills/data-analytics/src/analytics-app/charting/chart-transforms.ts +402 -0
  132. package/template/.codex/skills/data-analytics/src/analytics-app/fonts/SystemSansVariableVF.woff2 +0 -0
  133. package/template/.codex/skills/data-analytics/src/analytics-app/imageExport.ts +370 -0
  134. package/template/.codex/skills/data-analytics/src/analytics-app/layout/AnalyticsLayoutCanvas.tsx +536 -0
  135. package/template/.codex/skills/data-analytics/src/analytics-app/layout/RichMarkdown.tsx +681 -0
  136. package/template/.codex/skills/data-analytics/src/analytics-app/layout/analyticsLayoutCore.ts +164 -0
  137. package/template/.codex/skills/data-analytics/src/analytics-app/main.tsx +21 -0
  138. package/template/.codex/skills/data-analytics/src/analytics-app/scripts/chart_contract.py +472 -0
  139. package/template/.codex/skills/data-analytics/src/analytics-app/scripts/check_analytics_app_runtime_links.py +75 -0
  140. package/template/.codex/skills/data-analytics/src/analytics-app/scripts/design_contract.py +142 -0
  141. package/template/.codex/skills/data-analytics/src/analytics-app/scripts/package_utils.py +142 -0
  142. package/template/.codex/skills/data-analytics/src/analytics-app/scripts/tests/test_package_utils.py +377 -0
  143. package/template/.codex/skills/data-analytics/src/analytics-app/styles.css +3468 -0
  144. package/template/.codex/skills/data-analytics/src/analytics-app/tables/DataTable.d.ts +44 -0
  145. package/template/.codex/skills/data-analytics/src/analytics-app/tables/DataTable.jsx +639 -0
  146. package/template/.codex/skills/data-analytics/src/analytics-app/tables/data-table.css +327 -0
  147. package/template/.codex/skills/data-analytics/src/analytics-app/tokens.css +225 -0
  148. package/template/.codex/skills/data-analytics/src/analytics-app/types.ts +204 -0
  149. package/template/.codex/skills/data-analytics/src/analytics-app-core.md +85 -0
  150. package/template/.codex/skills/data-analytics/src/codex-style-contract.md +30 -0
  151. package/template/.codex/skills/data-analytics/src/datascience-artifact-widget.html +12 -0
  152. package/template/.codex/skills/data-analytics/src/datascience-artifact-widget.jsx +1008 -0
  153. package/template/.codex/skills/data-analytics/src/datascience-chart-widget.css +2117 -0
  154. package/template/.codex/skills/data-analytics/src/datascience-chart-widget.html +122 -0
  155. package/template/.codex/skills/data-analytics/src/datascience-chart-widget.js +3588 -0
  156. package/template/.codex/skills/data-analytics/src/datascience-table-widget.css +483 -0
  157. package/template/.codex/skills/data-analytics/src/datascience-table-widget.html +32 -0
  158. package/template/.codex/skills/data-analytics/src/datascience-table-widget.js +333 -0
  159. package/template/.codex/skills/data-analytics/src/mcp-host.js +153 -0
  160. package/template/.codex/skills/data-analytics/src/recharts-config.js +315 -0
  161. package/template/.codex/skills/data-analytics/src/recharts-renderer.jsx +294 -0
  162. package/template/.codex/skills/data-analytics/src/sql-source-view.css +33 -0
  163. package/template/.codex/skills/data-analytics/src/sql-source-view.js +157 -0
  164. package/template/.codex/skills/data-analytics/src/styles/codex-theme.css +121 -0
  165. package/template/.codex/skills/data-analytics/src/table-renderer.jsx +28 -0
  166. package/template/.codex/skills/data-analytics/tests/chart-transforms.test.mjs +87 -0
  167. package/template/.codex/skills/data-analytics/tests/funnel-smoke.html +105 -0
  168. package/template/.codex/skills/data-analytics/tests/inline-widget-compare.html +233 -0
  169. package/template/.codex/skills/data-analytics/tests/mcp-server.test.mjs +1500 -0
  170. package/template/.codex/skills/data-analytics/tests/native-style-contract.test.mjs +219 -0
  171. package/template/.codex/skills/data-analytics/tests/recharts-config.test.mjs +144 -0
  172. package/template/.codex/skills/data-analytics/tests/recharts-renderer.test.mjs +11 -0
  173. package/template/.codex/skills/data-analytics/tests/rich-markdown.test.mjs +54 -0
  174. package/template/.codex/skills/data-analytics/tests/widget-render-harness.html +321 -0
  175. package/template/.codex/skills/data-analytics/tsconfig.json +19 -0
  176. package/template/.codex/skills/data-analytics/vite.config.ts +46 -0
  177. package/template/.codex/skills/high-fidelity-html-prototype/SKILL.md +102 -0
  178. package/template/.codex/skills/high-fidelity-html-prototype/agents/openai.yaml +5 -0
  179. package/template/.codex/skills/product-design/.app.json +7 -0
  180. package/template/.codex/skills/product-design/.codex-plugin/plugin.json +50 -0
  181. package/template/.codex/skills/product-design/README.md +50 -0
  182. package/template/.codex/skills/product-design/agents/openai.yaml +4 -0
  183. package/template/.codex/skills/product-design/assets/composerIcon.svg +9 -0
  184. package/template/.codex/skills/product-design/assets/logo.png +0 -0
  185. package/template/.codex/skills/product-design/package.json +11 -0
  186. package/template/.codex/skills/product-design/references/browser-order.md +9 -0
  187. package/template/.codex/skills/product-design/references/communication-protocol.md +45 -0
  188. package/template/.codex/skills/product-design/references/critical-overrides.md +58 -0
  189. package/template/.codex/skills/product-design/references/local-prototype-preflight.md +16 -0
  190. package/template/.codex/skills/product-design/scripts/bootstrap-prototype.mjs +147 -0
  191. package/template/.codex/skills/product-design/skills/audit/SKILL.md +159 -0
  192. package/template/.codex/skills/product-design/skills/audit/agents/openai.yaml +6 -0
  193. package/template/.codex/skills/product-design/skills/audit/references/design-audit-framework.md +73 -0
  194. package/template/.codex/skills/product-design/skills/design-qa/SKILL.md +133 -0
  195. package/template/.codex/skills/product-design/skills/design-qa/agents/openai.yaml +6 -0
  196. package/template/.codex/skills/product-design/skills/design-qa/references/qa-rubric.md +61 -0
  197. package/template/.codex/skills/product-design/skills/get-context/SKILL.md +81 -0
  198. package/template/.codex/skills/product-design/skills/get-context/agents/openai.yaml +6 -0
  199. package/template/.codex/skills/product-design/skills/ideate/SKILL.md +179 -0
  200. package/template/.codex/skills/product-design/skills/ideate/agents/openai.yaml +6 -0
  201. package/template/.codex/skills/product-design/skills/image-to-code/SKILL.md +105 -0
  202. package/template/.codex/skills/product-design/skills/image-to-code/agents/openai.yaml +6 -0
  203. package/template/.codex/skills/product-design/skills/index/SKILL.md +126 -0
  204. package/template/.codex/skills/product-design/skills/index/agents/openai.yaml +6 -0
  205. package/template/.codex/skills/product-design/skills/prototype/SKILL.md +128 -0
  206. package/template/.codex/skills/product-design/skills/prototype/agents/openai.yaml +6 -0
  207. package/template/.codex/skills/product-design/skills/prototype/references/existing-codebase-edits.md +18 -0
  208. package/template/.codex/skills/product-design/skills/research/SKILL.md +92 -0
  209. package/template/.codex/skills/product-design/skills/research/agents/openai.yaml +6 -0
  210. package/template/.codex/skills/product-design/skills/share/SKILL.md +41 -0
  211. package/template/.codex/skills/product-design/skills/share/agents/openai.yaml +6 -0
  212. package/template/.codex/skills/product-design/skills/url-to-code/SKILL.md +124 -0
  213. package/template/.codex/skills/product-design/skills/url-to-code/agents/openai.yaml +6 -0
  214. package/template/.codex/skills/product-design/skills/user-context/SKILL.md +147 -0
  215. package/template/.codex/skills/product-design/skills/user-context/agents/openai.yaml +6 -0
  216. package/template/.codex/skills/product-design/skills/user-context/plugin-author-config/user-context-template.md +63 -0
  217. package/template/.codex/skills/product-design/skills/user-context/references/onboarding.md +66 -0
  218. package/template/.codex/skills/product-design/skills/user-context/scripts/init_user_context.py +86 -0
  219. package/template/.codex/skills/product-design/skills/user-context/scripts/user_context_preflight.py +204 -0
  220. package/template/.codex/skills/product-design/templates/prototype/AGENTS.md +7 -0
  221. package/template/.codex/skills/product-design/templates/prototype/index.html +12 -0
  222. package/template/.codex/skills/product-design/templates/prototype/package.json +18 -0
  223. package/template/.codex/skills/product-design/templates/prototype/src/App.jsx +5 -0
  224. package/template/.codex/skills/product-design/templates/prototype/src/main.jsx +10 -0
  225. package/template/.codex/skills/product-design/templates/prototype/src/styles.css +13 -0
  226. package/template/.codex/skills/product-design/templates/prototype/vite.config.mjs +14 -0
  227. package/template/.codex/skills/product-design-prototype/SKILL.md +2 -4
  228. package/template/.codex/skills/prototype-review/SKILL.md +7 -7
  229. package/template/.codex/skills/yss-design-system/SKILL.md +4 -2
  230. package/template/.codex/skills/yss-product-lifecycle/SKILL.md +10 -7
  231. package/template/.codex/skills/yss-product-lifecycle/references/artifact-checklist.md +1 -0
  232. package/template/.codex/skills/yss-product-lifecycle/references/stage-routing.md +1 -1
  233. package/template/.codex/skills/yss-ui/SKILL.md +4 -10
  234. package/template/.codex/skills/yss-ui/references/quick-recipes.md +1 -1
  235. package/template/AGENTS.md +9 -3
  236. package/template/CONTEXT.md +1 -0
  237. package/template/docs/adr/adr-product-design-prototype-entrypoint.md +54 -0
  238. package/template/docs/api/templates/openapi-draft-review-checklist.md +5 -1
  239. package/template/docs/design/README.md +13 -6
  240. package/template/docs/design/prototypes/.gitkeep +1 -0
  241. package/template/docs/design/templates/interaction-spec-template.md +8 -3
  242. package/template/docs/design/templates/product-overview-design-template.md +34 -5
  243. package/template/docs/design/templates/prototype-confirmation-template.md +57 -0
  244. package/template/docs/design/templates/prototype-review-checklist.md +7 -3
  245. package/template/docs/design/templates/state-matrix-template.md +1 -1
  246. package/template/docs/process/harness-executive-blueprint.md +6 -1
  247. package/template/docs/process/harness-process-tailoring.md +3 -3
  248. package/template/docs/process/harness-work-unit-map.md +1 -1
  249. package/template/docs/process/lifecycle-artifact-map.md +7 -5
  250. package/template/docs/process/product-prototype-workflow.md +82 -0
  251. package/template/docs/templates/requirement-freeze-template.md +4 -3
  252. package/template/docs/user-guide/product-lifecycle-workflow.md +2 -2
  253. package/template/docs/user-guide/product-rd-lifecycle-best-practices.md +54 -24
  254. package/template/.codex/skills/component-story-prototype/SKILL.md +0 -55
  255. package/template/.codex/skills/component-story-prototype/agents/openai.yaml +0 -4
  256. package/template/.codex/skills/mock-api-prototype/SKILL.md +0 -48
  257. package/template/.codex/skills/mock-api-prototype/agents/openai.yaml +0 -4
@@ -0,0 +1,536 @@
1
+ import {
2
+ type CSSProperties,
3
+ type PointerEvent as ReactPointerEvent,
4
+ type ReactNode,
5
+ useEffect,
6
+ useLayoutEffect,
7
+ useMemo,
8
+ useRef,
9
+ useState
10
+ } from "react";
11
+
12
+ import {
13
+ type AnalyticsLayoutItemState,
14
+ type AnalyticsLayoutPlacement,
15
+ type AnalyticsLayoutPlacementIntent,
16
+ type AnalyticsLayoutWidth,
17
+ normalize,
18
+ packRows,
19
+ predictPlacement
20
+ } from "./analyticsLayoutCore";
21
+
22
+ export type { AnalyticsLayoutWidth } from "./analyticsLayoutCore";
23
+
24
+ export type AnalyticsLayoutRenderActions = {
25
+ setLayout: (layout: AnalyticsLayoutWidth) => void;
26
+ };
27
+
28
+ export type AnalyticsLayoutBlock = {
29
+ className?: string;
30
+ defaultLayout?: AnalyticsLayoutWidth;
31
+ id: string;
32
+ render: (layout: AnalyticsLayoutWidth, actions: AnalyticsLayoutRenderActions) => ReactNode;
33
+ };
34
+
35
+ type BlockRect = {
36
+ bottom: number;
37
+ height: number;
38
+ left: number;
39
+ right: number;
40
+ top: number;
41
+ width: number;
42
+ };
43
+
44
+ type DragSession = {
45
+ currentPoint: { x: number; y: number };
46
+ draggedId: string;
47
+ intent: AnalyticsLayoutPlacementIntent;
48
+ isStacked: boolean;
49
+ pointerOffset: { x: number; y: number };
50
+ previewItems: AnalyticsLayoutItemState[];
51
+ rects: Map<string, BlockRect>;
52
+ sourceRect: BlockRect;
53
+ startItems: AnalyticsLayoutItemState[];
54
+ targetId: string | null;
55
+ };
56
+
57
+ const STACK_BREAKPOINT_PX = 760;
58
+ const AUTO_SCROLL_EDGE_PX = 72;
59
+ const AUTO_SCROLL_STEP_PX = 18;
60
+ const REORDER_INSERT_BAND_RATIO = 0.3;
61
+ const SPLIT_SIDE_ZONE_RATIO = 0.4;
62
+ const SPLIT_INDICATOR_OUTSET_PX = 8;
63
+
64
+ function parseStoredLayout(storageKey: string | null): unknown {
65
+ if (!storageKey) return undefined;
66
+ const stored = window.localStorage.getItem(storageKey);
67
+ if (!stored) return undefined;
68
+ try {
69
+ return JSON.parse(stored);
70
+ } catch {
71
+ return undefined;
72
+ }
73
+ }
74
+
75
+ function sameItems(first: AnalyticsLayoutItemState[], second: AnalyticsLayoutItemState[]) {
76
+ return (
77
+ first.length === second.length
78
+ && first.every((item, index) => item.id === second[index]?.id && item.layout === second[index]?.layout)
79
+ );
80
+ }
81
+
82
+ function rectFromElement(element: HTMLElement): BlockRect {
83
+ const rect = element.getBoundingClientRect();
84
+ return {
85
+ bottom: rect.bottom,
86
+ height: rect.height,
87
+ left: rect.left,
88
+ right: rect.right,
89
+ top: rect.top,
90
+ width: rect.width
91
+ };
92
+ }
93
+
94
+ function distanceToRect(x: number, y: number, rect: BlockRect) {
95
+ const dx = x < rect.left ? rect.left - x : x > rect.right ? x - rect.right : 0;
96
+ const dy = y < rect.top ? rect.top - y : y > rect.bottom ? y - rect.bottom : 0;
97
+ return Math.hypot(dx, dy);
98
+ }
99
+
100
+ function shouldCancelDrag(target: EventTarget | null, cancelSelector: string) {
101
+ return target instanceof Element && Boolean(target.closest(cancelSelector));
102
+ }
103
+
104
+ function DragHandleIcon() {
105
+ return (
106
+ <svg
107
+ aria-hidden="true"
108
+ className="analytics-layout-grab-handle-icon"
109
+ fill="none"
110
+ focusable="false"
111
+ height="24"
112
+ viewBox="0 0 24 24"
113
+ width="24"
114
+ >
115
+ <g transform="rotate(-90 12 12)">
116
+ <circle cx="5" cy="8.5" fill="currentColor" r="2" />
117
+ <circle cx="12" cy="8.5" fill="currentColor" r="2" />
118
+ <circle cx="19" cy="8.5" fill="currentColor" r="2" />
119
+ <circle cx="5" cy="15.5" fill="currentColor" r="2" />
120
+ <circle cx="12" cy="15.5" fill="currentColor" r="2" />
121
+ <circle cx="19" cy="15.5" fill="currentColor" r="2" />
122
+ </g>
123
+ </svg>
124
+ );
125
+ }
126
+
127
+ export function AnalyticsLayoutCanvas({
128
+ ariaLabel,
129
+ blocks,
130
+ cancelSelector,
131
+ className,
132
+ isEditMode = false,
133
+ itemClassName,
134
+ layoutResetKey = 0,
135
+ onLayoutChange,
136
+ storageKey
137
+ }: {
138
+ ariaLabel: string;
139
+ blocks: AnalyticsLayoutBlock[];
140
+ cancelSelector: string;
141
+ className?: string;
142
+ isEditMode?: boolean;
143
+ itemClassName?: (block: AnalyticsLayoutBlock, layout: AnalyticsLayoutWidth) => string;
144
+ layoutResetKey?: number;
145
+ onLayoutChange?: (items: AnalyticsLayoutItemState[]) => void;
146
+ storageKey: string | null;
147
+ }) {
148
+ const [items, setItems] = useState<AnalyticsLayoutItemState[]>(() => normalize(blocks));
149
+ const [dragSession, setDragSession] = useState<DragSession | null>(null);
150
+ const blockById = useMemo(() => new Map(blocks.map((block) => [block.id, block])), [blocks]);
151
+ const canvasRef = useRef<HTMLDivElement | null>(null);
152
+ const itemRefs = useRef(new Map<string, HTMLElement>());
153
+ const dragSessionRef = useRef<DragSession | null>(null);
154
+ const dragFrameRef = useRef<number | null>(null);
155
+ const dragPointRef = useRef<{ x: number; y: number } | null>(null);
156
+ const layoutLoadRef = useRef<{ layoutResetKey: number; storageKey: string | null } | null>(null);
157
+ const onLayoutChangeRef = useRef(onLayoutChange);
158
+
159
+ useEffect(() => {
160
+ onLayoutChangeRef.current = onLayoutChange;
161
+ }, [onLayoutChange]);
162
+
163
+ useLayoutEffect(() => {
164
+ const previousLoad = layoutLoadRef.current;
165
+ const shouldReloadStoredLayout =
166
+ !previousLoad
167
+ || previousLoad.layoutResetKey !== layoutResetKey
168
+ || previousLoad.storageKey !== storageKey;
169
+ layoutLoadRef.current = { layoutResetKey, storageKey };
170
+ setItems((currentItems) => {
171
+ const nextItems = normalize(
172
+ blocks,
173
+ shouldReloadStoredLayout ? parseStoredLayout(storageKey) : currentItems
174
+ );
175
+ onLayoutChangeRef.current?.(nextItems);
176
+ return nextItems;
177
+ });
178
+ }, [blocks, layoutResetKey, storageKey]);
179
+
180
+ useEffect(() => {
181
+ dragSessionRef.current = dragSession;
182
+ }, [dragSession]);
183
+
184
+ useEffect(() => {
185
+ if (!dragSession) return;
186
+ function refreshMeasuredRects() {
187
+ const session = dragSessionRef.current;
188
+ const canvas = canvasRef.current;
189
+ if (!session || !canvas) return;
190
+ const nextSession: DragSession = {
191
+ ...session,
192
+ isStacked: canvas.getBoundingClientRect().width < STACK_BREAKPOINT_PX,
193
+ rects: measureBlockRects()
194
+ };
195
+ dragSessionRef.current = nextSession;
196
+ setDragSession(nextSession);
197
+ }
198
+ window.addEventListener("resize", refreshMeasuredRects);
199
+ window.addEventListener("scroll", refreshMeasuredRects, true);
200
+ return () => {
201
+ window.removeEventListener("resize", refreshMeasuredRects);
202
+ window.removeEventListener("scroll", refreshMeasuredRects, true);
203
+ };
204
+ }, [dragSession?.draggedId]);
205
+
206
+ useEffect(() => {
207
+ return () => {
208
+ if (dragFrameRef.current != null) window.cancelAnimationFrame(dragFrameRef.current);
209
+ };
210
+ }, []);
211
+
212
+ const rows = packRows(items);
213
+
214
+ function measureBlockRects() {
215
+ const rects = new Map<string, BlockRect>();
216
+ itemRefs.current.forEach((element, id) => {
217
+ rects.set(id, rectFromElement(element));
218
+ });
219
+ return rects;
220
+ }
221
+
222
+ function commitItems(nextItems: AnalyticsLayoutItemState[]) {
223
+ const normalizedItems = normalize(blocks, nextItems);
224
+ setItems(normalizedItems);
225
+ onLayoutChangeRef.current?.(normalizedItems);
226
+ if (!isEditMode && storageKey) {
227
+ window.localStorage.setItem(storageKey, JSON.stringify(normalizedItems));
228
+ }
229
+ }
230
+
231
+ function setBlockLayout(blockId: string, layout: AnalyticsLayoutWidth) {
232
+ commitItems(items.map((item) => (item.id === blockId ? { ...item, layout } : item)));
233
+ }
234
+
235
+ function findPlacement(
236
+ clientX: number,
237
+ clientY: number,
238
+ session: DragSession,
239
+ rects: Map<string, BlockRect>
240
+ ): AnalyticsLayoutPlacement {
241
+ const candidates = [...rects.entries()]
242
+ .filter(([id]) => id !== session.draggedId)
243
+ .sort((first, second) => first[1].top - second[1].top || first[1].left - second[1].left);
244
+ if (!candidates.length) {
245
+ return { draggedId: session.draggedId, intent: "end" };
246
+ }
247
+
248
+ const firstRect = candidates[0][1];
249
+ const lastRect = candidates[candidates.length - 1][1];
250
+
251
+ let targetId = candidates[0][0];
252
+ let targetRect = candidates[0][1];
253
+ let bestDistance = Number.POSITIVE_INFINITY;
254
+ for (const [id, rect] of candidates) {
255
+ const distance = distanceToRect(clientX, clientY, rect);
256
+ if (distance < bestDistance) {
257
+ bestDistance = distance;
258
+ targetId = id;
259
+ targetRect = rect;
260
+ }
261
+ }
262
+
263
+ const sideBand = targetRect.width * SPLIT_SIDE_ZONE_RATIO;
264
+ const isInsideTargetHeight = clientY >= targetRect.top && clientY <= targetRect.bottom;
265
+ const insertBand = Math.min(targetRect.height * REORDER_INSERT_BAND_RATIO, targetRect.height / 2);
266
+ const isBeforeBand = isInsideTargetHeight && clientY < targetRect.top + insertBand;
267
+ const isAfterBand = isInsideTargetHeight && clientY > targetRect.bottom - insertBand;
268
+ if (isBeforeBand) {
269
+ return { draggedId: session.draggedId, intent: "before", targetId };
270
+ }
271
+ if (isAfterBand) {
272
+ return { draggedId: session.draggedId, intent: "after", targetId };
273
+ }
274
+ if (!session.isStacked && isInsideTargetHeight && clientX < targetRect.left + sideBand) {
275
+ return { draggedId: session.draggedId, intent: "pair-before", targetId };
276
+ }
277
+ if (!session.isStacked && isInsideTargetHeight && clientX > targetRect.right - sideBand) {
278
+ return { draggedId: session.draggedId, intent: "pair-after", targetId };
279
+ }
280
+
281
+ if (clientY < firstRect.top + firstRect.height / 2) {
282
+ return { draggedId: session.draggedId, intent: "before", targetId: candidates[0][0] };
283
+ }
284
+ if (clientY > lastRect.top + lastRect.height / 2) {
285
+ return { draggedId: session.draggedId, intent: "end" };
286
+ }
287
+
288
+ const targetItem = session.startItems.find((item) => item.id === targetId);
289
+ if (targetItem?.layout === "half") {
290
+ const targetCenterX = targetRect.left + targetRect.width / 2;
291
+ return {
292
+ draggedId: session.draggedId,
293
+ intent: clientX < targetCenterX ? "before" : "after",
294
+ targetId
295
+ };
296
+ }
297
+
298
+ const targetCenterY = targetRect.top + targetRect.height / 2;
299
+ return {
300
+ draggedId: session.draggedId,
301
+ intent: clientY < targetCenterY ? "before" : "after",
302
+ targetId
303
+ };
304
+ }
305
+
306
+ function autoScroll(clientY: number) {
307
+ if (clientY < AUTO_SCROLL_EDGE_PX) {
308
+ window.scrollBy({ top: -AUTO_SCROLL_STEP_PX });
309
+ } else if (clientY > window.innerHeight - AUTO_SCROLL_EDGE_PX) {
310
+ window.scrollBy({ top: AUTO_SCROLL_STEP_PX });
311
+ }
312
+ }
313
+
314
+ function applyDragPoint(clientX: number, clientY: number) {
315
+ const session = dragSessionRef.current;
316
+ if (!session) return;
317
+ autoScroll(clientY);
318
+ const rects = measureBlockRects();
319
+ const placement = findPlacement(clientX, clientY, session, rects);
320
+ const predictedItems = predictPlacement(session.startItems, placement);
321
+ const previewChanged = !sameItems(predictedItems, session.previewItems);
322
+ const previewItems = previewChanged ? predictedItems : session.previewItems;
323
+ const nextSession: DragSession = {
324
+ ...session,
325
+ currentPoint: { x: clientX, y: clientY },
326
+ intent: placement.intent,
327
+ previewItems,
328
+ rects,
329
+ targetId: placement.targetId ?? null
330
+ };
331
+ dragSessionRef.current = nextSession;
332
+ setDragSession(nextSession);
333
+ }
334
+
335
+ function scheduleDragPoint(clientX: number, clientY: number) {
336
+ dragPointRef.current = { x: clientX, y: clientY };
337
+ if (dragFrameRef.current != null) return;
338
+ dragFrameRef.current = window.requestAnimationFrame(() => {
339
+ dragFrameRef.current = null;
340
+ const point = dragPointRef.current;
341
+ if (!point) return;
342
+ applyDragPoint(point.x, point.y);
343
+ });
344
+ }
345
+
346
+ function startDragSession(event: ReactPointerEvent<HTMLElement>, blockId: string) {
347
+ if (!isEditMode) return;
348
+ if (event.pointerType === "mouse" && event.button !== 0) return;
349
+ if (shouldCancelDrag(event.target, cancelSelector)) return;
350
+ const element = itemRefs.current.get(blockId);
351
+ const canvas = canvasRef.current;
352
+ if (!element || !canvas) return;
353
+ event.preventDefault();
354
+ element.setPointerCapture?.(event.pointerId);
355
+ const sourceRect = rectFromElement(element);
356
+ const rects = measureBlockRects();
357
+ const canvasRect = canvas.getBoundingClientRect();
358
+ const startItems = normalize(blocks, items);
359
+ const session: DragSession = {
360
+ currentPoint: { x: event.clientX, y: event.clientY },
361
+ draggedId: blockId,
362
+ intent: "end",
363
+ isStacked: canvasRect.width < STACK_BREAKPOINT_PX,
364
+ pointerOffset: {
365
+ x: event.clientX - sourceRect.left,
366
+ y: event.clientY - sourceRect.top
367
+ },
368
+ previewItems: startItems,
369
+ rects,
370
+ sourceRect,
371
+ startItems,
372
+ targetId: null
373
+ };
374
+ dragSessionRef.current = session;
375
+ setDragSession(session);
376
+ }
377
+
378
+ function handlePointerDown(event: ReactPointerEvent<HTMLDivElement>, blockId: string) {
379
+ startDragSession(event, blockId);
380
+ }
381
+
382
+ function finishDrag(commit: boolean) {
383
+ const session = dragSessionRef.current;
384
+ if (dragFrameRef.current != null) {
385
+ window.cancelAnimationFrame(dragFrameRef.current);
386
+ dragFrameRef.current = null;
387
+ }
388
+ dragPointRef.current = null;
389
+ dragSessionRef.current = null;
390
+ setDragSession(null);
391
+ if (commit && session) {
392
+ commitItems(session.previewItems);
393
+ }
394
+ }
395
+
396
+ function handlePointerMove(event: ReactPointerEvent<HTMLDivElement>) {
397
+ if (!dragSessionRef.current) return;
398
+ event.preventDefault();
399
+ scheduleDragPoint(event.clientX, event.clientY);
400
+ }
401
+
402
+ function ghostStyle(session: DragSession): CSSProperties {
403
+ return {
404
+ height: session.sourceRect.height,
405
+ left: session.currentPoint.x - session.pointerOffset.x,
406
+ top: session.currentPoint.y - session.pointerOffset.y,
407
+ width: session.sourceRect.width
408
+ };
409
+ }
410
+
411
+ function dropIndicatorStyle(session: DragSession): { className: string; style: CSSProperties } | null {
412
+ if (session.intent === "hold") return null;
413
+ const canvas = canvasRef.current;
414
+ if (!canvas) return null;
415
+ const canvasRect = canvas.getBoundingClientRect();
416
+ const candidates = [...session.rects.entries()]
417
+ .filter(([id]) => id !== session.draggedId)
418
+ .sort((first, second) => first[1].top - second[1].top || first[1].left - second[1].left);
419
+ if (!candidates.length) return null;
420
+
421
+ if (session.intent === "pair-before" || session.intent === "pair-after") {
422
+ if (!session.targetId) return null;
423
+ const targetRect = session.rects.get(session.targetId);
424
+ if (!targetRect) return null;
425
+ const lineX = session.intent === "pair-before"
426
+ ? targetRect.left - SPLIT_INDICATOR_OUTSET_PX
427
+ : targetRect.right + SPLIT_INDICATOR_OUTSET_PX;
428
+ return {
429
+ className: "analytics-layout-drop-indicator is-split",
430
+ style: {
431
+ height: targetRect.height,
432
+ left: lineX - canvasRect.left,
433
+ top: targetRect.top - canvasRect.top
434
+ }
435
+ };
436
+ }
437
+
438
+ const targetRect = session.targetId
439
+ ? session.rects.get(session.targetId)
440
+ : candidates[candidates.length - 1]?.[1];
441
+ if (!targetRect) return null;
442
+ const lineY = session.intent === "before"
443
+ ? targetRect.top
444
+ : targetRect.bottom;
445
+ return {
446
+ className: "analytics-layout-drop-indicator is-reorder",
447
+ style: {
448
+ left: 0,
449
+ top: lineY - canvasRect.top,
450
+ width: canvasRect.width
451
+ }
452
+ };
453
+ }
454
+
455
+ const dropIndicator = dragSession ? dropIndicatorStyle(dragSession) : null;
456
+
457
+ return (
458
+ <section
459
+ aria-label={ariaLabel}
460
+ className={`analytics-layout-canvas ${isEditMode ? "is-edit-mode" : ""} ${dragSession ? "is-layout-dragging" : ""} ${className ?? ""}`.trim()}
461
+ data-analytics-layout-canvas
462
+ data-edit-mode={isEditMode ? "true" : "false"}
463
+ onPointerCancel={() => finishDrag(false)}
464
+ onPointerMove={handlePointerMove}
465
+ onPointerUp={() => finishDrag(true)}
466
+ ref={canvasRef}
467
+ >
468
+ {dropIndicator ? (
469
+ <div
470
+ aria-hidden="true"
471
+ className={dropIndicator.className}
472
+ data-image-export-exclude="true"
473
+ style={dropIndicator.style}
474
+ />
475
+ ) : null}
476
+ {rows.map((row, rowIndex) => (
477
+ <div
478
+ className={`analytics-layout-row ${row.length === 2 ? "is-half-row" : "is-full-row"}`}
479
+ key={row.map((item) => item.id).join(":")}
480
+ >
481
+ {row.map((item) => {
482
+ const block = blockById.get(item.id);
483
+ if (!block) return null;
484
+ const isDragged = dragSession?.draggedId === item.id;
485
+ const isTarget = dragSession?.targetId === item.id;
486
+ const rendered = block.render(item.layout, {
487
+ setLayout: (nextLayout) => setBlockLayout(item.id, nextLayout)
488
+ });
489
+ return (
490
+ <div
491
+ className={`analytics-layout-item layout-${item.layout} ${block.className ?? ""} ${itemClassName?.(block, item.layout) ?? ""} ${isDragged ? "is-dragging" : ""} ${isTarget ? `is-drop-target intent-zone-${dragSession?.intent}` : ""}`.trim()}
492
+ data-analytics-layout-item
493
+ data-layout-block-id={item.id}
494
+ data-layout-row-index={rowIndex}
495
+ data-layout-width={item.layout}
496
+ key={item.id}
497
+ ref={(node) => {
498
+ if (node) itemRefs.current.set(item.id, node);
499
+ else itemRefs.current.delete(item.id);
500
+ }}
501
+ >
502
+ {isEditMode ? (
503
+ <div
504
+ aria-hidden="true"
505
+ className="analytics-layout-grab-handle"
506
+ data-image-export-exclude="true"
507
+ onPointerDown={(event) => handlePointerDown(event, item.id)}
508
+ title="Drag to reorder"
509
+ >
510
+ <DragHandleIcon />
511
+ </div>
512
+ ) : null}
513
+ <div className="analytics-layout-item-shell">
514
+ {rendered}
515
+ </div>
516
+ </div>
517
+ );
518
+ })}
519
+ </div>
520
+ ))}
521
+ {dragSession ? (
522
+ <div
523
+ aria-hidden="true"
524
+ className="analytics-layout-ghost"
525
+ data-image-export-exclude="true"
526
+ style={ghostStyle(dragSession)}
527
+ >
528
+ {blockById.get(dragSession.draggedId)?.render(
529
+ dragSession.startItems.find((item) => item.id === dragSession.draggedId)?.layout ?? "full",
530
+ { setLayout: () => undefined }
531
+ )}
532
+ </div>
533
+ ) : null}
534
+ </section>
535
+ );
536
+ }