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,402 @@
1
+ import type { ChartSeriesSpec, ChartSpec, ValueFormat } from "./chart-contract";
2
+
3
+ export type ChartDataRow = Record<string, string | number | boolean | [number, number] | null | undefined>;
4
+
5
+ export const PERCENT_AXIS_TICKS = [0, 0.25, 0.5, 0.75, 1];
6
+ const Y_AXIS_TICK_COUNT = 5;
7
+ const COMPACT_VALUE_THRESHOLD = 100_000;
8
+ const DATE_AXIS_MIN_TICKS = 5;
9
+ const DATE_AXIS_MAX_TICKS = 10;
10
+ const DATE_AXIS_ESTIMATED_TICK_WIDTH = 90;
11
+
12
+ export function asNumber(value: unknown): number | null {
13
+ if (typeof value === "number" && Number.isFinite(value)) return value;
14
+ if (typeof value === "string" && value.trim() !== "") {
15
+ const numeric = Number(value);
16
+ if (Number.isFinite(numeric)) return numeric;
17
+ }
18
+ return null;
19
+ }
20
+
21
+ export function asFiniteNumber(value: unknown, fallback = 0): number {
22
+ return asNumber(value) ?? fallback;
23
+ }
24
+
25
+ export function clamp(value: number, min: number, max: number): number {
26
+ return Math.max(min, Math.min(max, value));
27
+ }
28
+
29
+ function isUsdUnit(unit: string): boolean {
30
+ return unit === "$" || unit.toUpperCase() === "USD";
31
+ }
32
+
33
+ function unitScaleSuffix(unit: string): string | null {
34
+ const normalized = unit.toLowerCase();
35
+ if (normalized === "usd millions" || normalized === "usd million") return "M";
36
+ if (normalized === "usd billions" || normalized === "usd billion") return "B";
37
+ if (normalized === "usd thousands" || normalized === "usd thousand") return "K";
38
+ if (/^\$[kmbt]$/i.test(unit)) return unit.slice(1).toUpperCase();
39
+ return null;
40
+ }
41
+
42
+ function compactDigits(value: number): number {
43
+ const absolute = Math.abs(value);
44
+ if (absolute >= COMPACT_VALUE_THRESHOLD) return 1;
45
+ return 2;
46
+ }
47
+
48
+ function formatPlainNumber(value: number, compact = false): string {
49
+ const absolute = Math.abs(value);
50
+ return new Intl.NumberFormat(undefined, {
51
+ maximumFractionDigits: compactDigits(value),
52
+ notation: compact && absolute >= COMPACT_VALUE_THRESHOLD ? "compact" : "standard",
53
+ }).format(value);
54
+ }
55
+
56
+ function formatCurrency(value: number): string {
57
+ const absolute = Math.abs(value);
58
+ return new Intl.NumberFormat(undefined, {
59
+ currency: "USD",
60
+ maximumFractionDigits: compactDigits(value),
61
+ notation: absolute >= COMPACT_VALUE_THRESHOLD ? "compact" : "standard",
62
+ style: "currency",
63
+ }).format(value);
64
+ }
65
+
66
+ function isPercentWordUnit(unit: string): boolean {
67
+ const normalized = unit.toLowerCase();
68
+ return normalized === "percent" || normalized === "percentage";
69
+ }
70
+
71
+ export function formatValue(value: unknown, format: ValueFormat = "compact", unit?: string): string {
72
+ const numeric = asNumber(value);
73
+ if (numeric == null) return value == null ? "n/a" : String(value);
74
+ const cleanUnit = unit?.trim();
75
+ if (cleanUnit) {
76
+ if (isPercentWordUnit(cleanUnit)) {
77
+ return new Intl.NumberFormat(undefined, {
78
+ maximumFractionDigits: 1,
79
+ style: "percent",
80
+ }).format(numeric);
81
+ }
82
+ if (cleanUnit === "%" || cleanUnit.startsWith("%")) return `${formatPlainNumber(numeric)}%`;
83
+ if (isUsdUnit(cleanUnit)) return formatCurrency(numeric);
84
+ const scaleSuffix = unitScaleSuffix(cleanUnit);
85
+ if (scaleSuffix) return `$${formatPlainNumber(numeric)}${scaleSuffix}`;
86
+ if (cleanUnit.startsWith("$")) return `$${formatPlainNumber(numeric)}${cleanUnit.slice(1)}`;
87
+ return `${formatPlainNumber(numeric, format === "compact")} ${cleanUnit}`;
88
+ }
89
+ if (format === "percent") {
90
+ return new Intl.NumberFormat(undefined, {
91
+ maximumFractionDigits: 1,
92
+ style: "percent",
93
+ }).format(numeric);
94
+ }
95
+ if (format === "currency") {
96
+ return formatCurrency(numeric);
97
+ }
98
+ if (format === "number") {
99
+ return formatPlainNumber(numeric);
100
+ }
101
+ return formatPlainNumber(numeric, true);
102
+ }
103
+
104
+ export function isDateAxisValue(value: unknown): value is string {
105
+ return dateAxisParts(value) != null;
106
+ }
107
+
108
+ function dateAxisParts(value: unknown): { day: number; granularity: "day"; month: number; year: number } | { granularity: "month"; month: number; year: number } | null {
109
+ if (typeof value !== "string") return null;
110
+ const trimmed = value.trim();
111
+ const match = trimmed.match(/^(\d{4})-(\d{2})-(\d{2})(?:$|[T\s])/);
112
+ if (!match) {
113
+ const monthMatch = trimmed.match(/^(\d{4})-(\d{2})$/);
114
+ if (!monthMatch) return null;
115
+ const [, monthYear, monthValue] = monthMatch;
116
+ const monthParts = {
117
+ granularity: "month" as const,
118
+ month: Number(monthValue),
119
+ year: Number(monthYear),
120
+ };
121
+ const date = new Date(Date.UTC(monthParts.year, monthParts.month - 1, 1));
122
+ if (date.getUTCFullYear() !== monthParts.year || date.getUTCMonth() !== monthParts.month - 1) {
123
+ return null;
124
+ }
125
+ return monthParts;
126
+ }
127
+ const [, year, month, day] = match;
128
+ const parts = {
129
+ day: Number(day),
130
+ granularity: "day" as const,
131
+ month: Number(month),
132
+ year: Number(year),
133
+ };
134
+ const date = new Date(Date.UTC(parts.year, parts.month - 1, parts.day));
135
+ if (
136
+ date.getUTCFullYear() !== parts.year ||
137
+ date.getUTCMonth() !== parts.month - 1 ||
138
+ date.getUTCDate() !== parts.day
139
+ ) {
140
+ return null;
141
+ }
142
+ return parts;
143
+ }
144
+
145
+ export function formatDateAxisLabel(value: unknown, options: { includeYear?: boolean } = {}): string {
146
+ const parts = dateAxisParts(value);
147
+ if (!parts) return value == null ? "" : String(value);
148
+ if (parts.granularity === "month") {
149
+ return new Intl.DateTimeFormat(undefined, {
150
+ month: "short",
151
+ timeZone: "UTC",
152
+ year: "numeric",
153
+ }).format(new Date(Date.UTC(parts.year, parts.month - 1, 1)));
154
+ }
155
+ return new Intl.DateTimeFormat(undefined, {
156
+ day: "numeric",
157
+ month: "short",
158
+ timeZone: "UTC",
159
+ year: options.includeYear ? "numeric" : undefined,
160
+ }).format(new Date(Date.UTC(parts.year, parts.month - 1, parts.day)));
161
+ }
162
+
163
+ function uniqueOrderedValues(values: string[]): string[] {
164
+ const seen = new Set<string>();
165
+ const unique: string[] = [];
166
+ for (const value of values) {
167
+ if (seen.has(value)) continue;
168
+ seen.add(value);
169
+ unique.push(value);
170
+ }
171
+ return unique;
172
+ }
173
+
174
+ function targetDateAxisTickCount(valueCount: number, availableWidth: number): number {
175
+ if (valueCount <= 7) return valueCount;
176
+ const widthTarget = Math.floor(availableWidth / DATE_AXIS_ESTIMATED_TICK_WIDTH);
177
+ return clamp(widthTarget, DATE_AXIS_MIN_TICKS, Math.min(valueCount, DATE_AXIS_MAX_TICKS));
178
+ }
179
+
180
+ export function getDateAxisTicks(rows: ChartDataRow[], xField: string, availableWidth = 760): string[] | undefined {
181
+ const values = uniqueOrderedValues(
182
+ rows
183
+ .map((row) => row[xField])
184
+ .filter((value): value is string => typeof value === "string"),
185
+ );
186
+ if (values.length === 0 || !values.every(isDateAxisValue)) return undefined;
187
+ if (values.length === 1) return values;
188
+ const targetCount = targetDateAxisTickCount(values.length, availableWidth);
189
+ if (targetCount >= values.length) return values;
190
+
191
+ const lastIndex = values.length - 1;
192
+ const step = Math.max(1, Math.ceil(lastIndex / Math.max(1, targetCount - 1)));
193
+ const ticks = values.filter((_, index) => index % step === 0);
194
+ const last = values[lastIndex];
195
+ if (ticks[ticks.length - 1] !== last) ticks.push(last);
196
+ return ticks;
197
+ }
198
+
199
+ function niceAxisStep(value: number): number {
200
+ if (!Number.isFinite(value) || value <= 0) return 1;
201
+ const magnitude = 10 ** Math.floor(Math.log10(value));
202
+ const normalized = value / magnitude;
203
+ const niceStep = [1, 1.5, 2, 2.5, 3, 4, 5, 7.5, 9, 10].find(
204
+ (candidate) => normalized <= candidate,
205
+ );
206
+ return (niceStep ?? 10) * magnitude;
207
+ }
208
+
209
+ export function getYAxisScaleForSeries(
210
+ chart: ChartSpec,
211
+ rows: ChartDataRow[],
212
+ seriesList: ChartSeriesSpec[],
213
+ ): { labels: string[]; ticks: number[] } {
214
+ const barGroupMode = chart.settings?.groupMode;
215
+ const normalizedStackedBars =
216
+ chart.type === "stackedBar100" ||
217
+ chart.type === "horizontalStackedBar100" ||
218
+ (chart.type === "bar" && barGroupMode === "stacked100");
219
+ const stackedBars =
220
+ chart.type === "stackedBar" ||
221
+ chart.type === "horizontalStackedBar" ||
222
+ (chart.type === "bar" && (barGroupMode === "stacked" || barGroupMode === "stacked100"));
223
+
224
+ if (normalizedStackedBars) {
225
+ return {
226
+ labels: PERCENT_AXIS_TICKS.map((value) => formatValue(value, "percent")),
227
+ ticks: PERCENT_AXIS_TICKS,
228
+ };
229
+ }
230
+
231
+ const values: number[] = [0];
232
+ for (const row of rows) {
233
+ if (chart.type === "stackedArea" || stackedBars) {
234
+ let positiveTotal = 0;
235
+ let negativeTotal = 0;
236
+ for (const series of seriesList) {
237
+ const value = asNumber(row[series.field]);
238
+ if (value == null) continue;
239
+ if (value >= 0) positiveTotal += value;
240
+ else negativeTotal += value;
241
+ }
242
+ values.push(positiveTotal, negativeTotal);
243
+ } else {
244
+ for (const series of seriesList) {
245
+ const value = asNumber(row[series.field]);
246
+ if (value != null) values.push(value);
247
+ }
248
+ }
249
+ }
250
+
251
+ const min = Math.min(...values);
252
+ const max = Math.max(...values);
253
+ const roughTickStep = niceAxisStep((max - min) / Math.max(1, Y_AXIS_TICK_COUNT - 1));
254
+ const axisMin = min < 0 ? Math.floor(min / roughTickStep) * roughTickStep : 0;
255
+ const tickStep = niceAxisStep((max - axisMin) / Math.max(1, Y_AXIS_TICK_COUNT - 1));
256
+ const axisMax = max > 0 ? Math.ceil(max / tickStep) * tickStep : 0;
257
+ const tickSlots = Math.max(1, Math.round((axisMax - axisMin) / tickStep));
258
+ const ticks =
259
+ axisMin === axisMax
260
+ ? [axisMin]
261
+ : Array.from({ length: tickSlots + 1 }, (_, index) => axisMin + tickStep * index);
262
+ return {
263
+ labels: ticks.map((value) => formatValue(value, chart.valueFormat)),
264
+ ticks,
265
+ };
266
+ }
267
+
268
+ export type BoxPlotDataRow = ChartDataRow & {
269
+ __boxMax: number;
270
+ __boxMedian: number;
271
+ __boxMin: number;
272
+ __boxQ1: number;
273
+ __boxQ3: number;
274
+ __boxRange: [number, number];
275
+ };
276
+
277
+ export function buildBoxPlotRows(chart: ChartSpec, rows: ChartDataRow[]): BoxPlotDataRow[] {
278
+ const [minSeries, q1Series, medianSeries, q3Series, maxSeries] = chart.series;
279
+ return rows.map((row) => {
280
+ const min = asFiniteNumber(row[minSeries?.field ?? ""]);
281
+ const q1 = asFiniteNumber(row[q1Series?.field ?? ""], min);
282
+ const median = asFiniteNumber(row[medianSeries?.field ?? ""], q1);
283
+ const q3 = asFiniteNumber(row[q3Series?.field ?? ""], median);
284
+ const max = asFiniteNumber(row[maxSeries?.field ?? ""], q3);
285
+ return {
286
+ ...row,
287
+ __boxMax: max,
288
+ __boxMedian: median,
289
+ __boxMin: min,
290
+ __boxQ1: q1,
291
+ __boxQ3: q3,
292
+ __boxRange: [q1, q3],
293
+ };
294
+ });
295
+ }
296
+
297
+ export function getBoxPlotXAxisScale(rows: BoxPlotDataRow[]): { domain: [number, number]; ticks: number[] } {
298
+ const values = rows.flatMap((row) => [row.__boxMin, row.__boxMax]);
299
+ const min = Math.min(0, ...values);
300
+ const max = Math.max(0, ...values);
301
+ const roughTickStep = niceAxisStep((max - min) / Math.max(1, Y_AXIS_TICK_COUNT - 1));
302
+ const axisMin = min < 0 ? Math.floor(min / roughTickStep) * roughTickStep : 0;
303
+ const tickStep = niceAxisStep((max - axisMin) / Math.max(1, Y_AXIS_TICK_COUNT - 1));
304
+ const axisMax = max > 0 ? Math.ceil(max / tickStep) * tickStep : 0;
305
+ if (axisMin === axisMax) {
306
+ const fallbackMax = axisMin + tickStep;
307
+ return { domain: [axisMin, fallbackMax], ticks: [axisMin, fallbackMax] };
308
+ }
309
+ const tickSlots = Math.max(1, Math.round((axisMax - axisMin) / tickStep));
310
+ const ticks = Array.from({ length: tickSlots + 1 }, (_, index) => axisMin + tickStep * index);
311
+ return { domain: [axisMin, axisMax], ticks };
312
+ }
313
+
314
+ export type WaterfallDataRow = ChartDataRow & {
315
+ __waterfallEnd: number;
316
+ __waterfallIsLast: boolean;
317
+ __waterfallIsPositive: boolean;
318
+ __waterfallRange: [number, number];
319
+ __waterfallRowCount: number;
320
+ __waterfallStart: number;
321
+ __waterfallValue: number;
322
+ };
323
+
324
+ export function buildWaterfallRows(chart: ChartSpec, rows: ChartDataRow[]): WaterfallDataRow[] {
325
+ const series = chart.series[0];
326
+ let running = 0;
327
+ return rows.map((row, index) => {
328
+ const value = asFiniteNumber(row[series?.field ?? ""]);
329
+ const start = running;
330
+ const end = start + value;
331
+ running = end;
332
+ return {
333
+ ...row,
334
+ __waterfallEnd: end,
335
+ __waterfallIsLast: index === rows.length - 1,
336
+ __waterfallIsPositive: value >= 0,
337
+ __waterfallRange: [Math.min(start, end), Math.max(start, end)],
338
+ __waterfallRowCount: rows.length,
339
+ __waterfallStart: start,
340
+ __waterfallValue: value,
341
+ };
342
+ });
343
+ }
344
+
345
+ export function buildPieRows(chart: ChartSpec, rows: ChartDataRow[]): ChartDataRow[] {
346
+ if (chart.series.length > 1) {
347
+ return chart.series
348
+ .map((series, index) => ({
349
+ __pieIndex: index,
350
+ __pieField: series.field,
351
+ __pieName: String(series.label ?? series.field),
352
+ __pieValue: rows.reduce((sum, row) => sum + Math.max(0, asNumber(row[series.field]) ?? 0), 0),
353
+ }))
354
+ .filter((row) => Number(row.__pieValue) > 0);
355
+ }
356
+ const series = chart.series[0];
357
+ return rows
358
+ .map((row, index) => ({
359
+ ...row,
360
+ __pieIndex: index,
361
+ __pieName: formatDateAxisLabel(row[chart.xField]),
362
+ __pieValue: Math.max(0, asNumber(row[series?.field ?? ""]) ?? 0),
363
+ }))
364
+ .filter((row) => asNumber(row.__pieValue) != null && Number(row.__pieValue) > 0);
365
+ }
366
+
367
+ export function buildFunnelRows(chart: ChartSpec, rows: ChartDataRow[], getStageColor: (index: number, rowCount: number) => string): ChartDataRow[] {
368
+ const series = chart.series[0];
369
+ return rows.map((row, index) => {
370
+ const value = asNumber(row[series?.field ?? ""]) ?? 0;
371
+ const baseline = (asNumber(rows[0]?.[series?.field ?? ""]) ?? value) || 1;
372
+ return {
373
+ ...row,
374
+ __funnelIndex: index,
375
+ __funnelLabel: formatDateAxisLabel(row[chart.xField]),
376
+ __funnelPairLabel: `${formatDateAxisLabel(row[chart.xField])}\u0000${formatValue(value, chart.valueFormat, chart.unit)}`,
377
+ __funnelRowCount: rows.length,
378
+ __funnelShareLabel: index === 0 ? "100%" : formatValue(value / baseline, "percent"),
379
+ __funnelStageColor: getStageColor(index, rows.length),
380
+ __funnelValueLabel: formatValue(value, chart.valueFormat, chart.unit),
381
+ };
382
+ });
383
+ }
384
+
385
+ export function chartEmptyMessage(chart: ChartSpec, rows: ChartDataRow[], visibleFields?: Set<string>): string {
386
+ if (!rows.length) return chart.emptyState || "No rows match the selected filters.";
387
+ const visibleSeries = chart.series.filter(
388
+ (series) => !visibleFields || !visibleFields.size || visibleFields.has(series.field),
389
+ );
390
+ if (chart.series.length && !visibleSeries.length) return "No visible series selected.";
391
+ if (chart.type === "scatter" && !rows.some((row) => asNumber(row[chart.xField]) != null && visibleSeries.some((series) => asNumber(row[series.field]) != null))) {
392
+ return "Scatter plots need numeric x and y values.";
393
+ }
394
+ if (chart.type === "histogram" && !rows.some((row) => asNumber(row[chart.series[0]?.field ?? chart.xField]) != null)) {
395
+ return "Histogram needs numeric values.";
396
+ }
397
+ if (chart.type === "pie" && !buildPieRows(chart, rows).length) return "Pie charts need positive values.";
398
+ if ((chart.type === "line" || chart.type === "area" || chart.type === "stackedArea" || chart.type === "sparkline") && new Set(rows.map((row) => String(row[chart.xField] ?? ""))).size < 2) {
399
+ return `${chart.type === "stackedArea" ? "Stacked area" : "Trend"} charts need at least two x values.`;
400
+ }
401
+ return "";
402
+ }