create-yss-spec 3.5.2 → 3.5.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 (438) hide show
  1. package/package.json +1 -1
  2. package/src/template/asset-runtime.js +3 -1
  3. package/template/.agents/skills/.strategic-design-skills-manifest.json +1 -1
  4. package/template/.agents/skills/codebase-design/SKILL.md +4 -0
  5. package/template/{.codex/skills/improve-codebase-architecture/SKILL.md → .agents/skills/codebase-design/references/architecture-audit.md} +3 -9
  6. package/template/.agents/skills/frontend-commit/SKILL.md +4 -93
  7. package/template/.agents/skills/git-commit-core/SKILL.md +18 -0
  8. package/template/.agents/skills/java-backend-commit/SKILL.md +4 -96
  9. package/template/.agents/skills/llm-wiki/SKILL.md +12 -13
  10. package/template/.agents/skills/llm-wiki/assets/CLAUDE.md.template +7 -1
  11. package/template/.agents/skills/llm-wiki/references/compile.md +21 -114
  12. package/template/.agents/skills/llm-wiki/references/ingest.md +8 -33
  13. package/template/.agents/skills/llm-wiki/references/lint.md +9 -46
  14. package/template/.agents/skills/llm-wiki/references/query.md +9 -18
  15. package/template/.agents/skills/llm-wiki/references/schema.md +56 -29
  16. package/template/.agents/skills/llm-wiki/references/transactions.md +48 -0
  17. package/template/.agents/skills/llm-wiki/references/writing.md +4 -4
  18. package/template/.agents/skills/llm-wiki/scripts/advise.mjs +46 -58
  19. package/template/.agents/skills/llm-wiki/scripts/advise.test.mjs +11 -16
  20. package/template/.agents/skills/llm-wiki/scripts/core.mjs +262 -0
  21. package/template/.agents/skills/llm-wiki/scripts/extract.mjs +35 -18
  22. package/template/.agents/skills/llm-wiki/scripts/extract.test.mjs +5 -8
  23. package/template/.agents/skills/llm-wiki/scripts/feedback.mjs +51 -0
  24. package/template/.agents/skills/llm-wiki/scripts/inventory.mjs +43 -171
  25. package/template/.agents/skills/llm-wiki/scripts/inventory.test.mjs +25 -18
  26. package/template/.agents/skills/llm-wiki/scripts/lint-wikilinks.mjs +69 -92
  27. package/template/.agents/skills/llm-wiki/scripts/lint-wikilinks.test.mjs +25 -37
  28. package/template/.agents/skills/llm-wiki/scripts/migrate.mjs +51 -0
  29. package/template/.agents/skills/llm-wiki/scripts/query.mjs +149 -0
  30. package/template/.agents/skills/llm-wiki/scripts/regressions.test.mjs +101 -0
  31. package/template/.agents/skills/llm-wiki/scripts/sources.mjs +166 -0
  32. package/template/.agents/skills/llm-wiki/scripts/transaction.mjs +384 -0
  33. package/template/.agents/skills/llm-wiki/scripts/v2.test.mjs +354 -0
  34. package/template/.agents/skills/prototype/LOGIC.md +1 -1
  35. package/template/.agents/skills/prototype/SKILL.md +5 -19
  36. package/template/.agents/skills/setup-matt-pocock-skills/SKILL.md +3 -3
  37. package/template/.agents/skills/yss-implementation-contract-compiler/SKILL.md +2 -0
  38. package/template/.agents/skills/yss-implementation-contract-compiler/references/boundaries.md +2 -3
  39. package/template/.agents/skills/yss-implementation-contract-compiler/references/yss-skill-execution-result.md +14 -0
  40. package/template/.agents/skills/yss-product-lifecycle/SKILL.md +8 -8
  41. package/template/.agents/skills/yss-product-lifecycle/references/external-input-questionnaire.md +19 -0
  42. package/template/.agents/skills/yss-product-lifecycle/references/matt-yss-adapter.md +5 -5
  43. package/template/.agents/skills/yss-product-lifecycle/references/orchestration-contract.yaml +20 -4
  44. package/template/.agents/skills/yss-product-lifecycle/references/orchestration.md +2 -2
  45. package/template/.agents/skills/yss-product-lifecycle/references/plan-requirements.md +10 -0
  46. package/template/.agents/skills/yss-product-lifecycle/references/state-model.md +1 -1
  47. package/template/.agents/skills/yss-research/SKILL.md +4 -0
  48. package/template/.codex/skills/codebase-design/SKILL.md +4 -0
  49. package/template/{.pi/skills/improve-codebase-architecture/SKILL.md → .codex/skills/codebase-design/references/architecture-audit.md} +3 -9
  50. package/template/.codex/skills/frontend-commit/SKILL.md +4 -93
  51. package/template/.codex/skills/git-commit-core/SKILL.md +18 -0
  52. package/template/.codex/skills/java-backend-commit/SKILL.md +4 -96
  53. package/template/.codex/skills/llm-wiki/SKILL.md +12 -13
  54. package/template/.codex/skills/llm-wiki/assets/CLAUDE.md.template +7 -1
  55. package/template/.codex/skills/llm-wiki/references/compile.md +21 -114
  56. package/template/.codex/skills/llm-wiki/references/ingest.md +8 -33
  57. package/template/.codex/skills/llm-wiki/references/lint.md +9 -46
  58. package/template/.codex/skills/llm-wiki/references/query.md +9 -18
  59. package/template/.codex/skills/llm-wiki/references/schema.md +56 -29
  60. package/template/.codex/skills/llm-wiki/references/transactions.md +48 -0
  61. package/template/.codex/skills/llm-wiki/references/writing.md +4 -4
  62. package/template/.codex/skills/llm-wiki/scripts/advise.mjs +46 -58
  63. package/template/.codex/skills/llm-wiki/scripts/advise.test.mjs +11 -16
  64. package/template/.codex/skills/llm-wiki/scripts/core.mjs +262 -0
  65. package/template/.codex/skills/llm-wiki/scripts/extract.mjs +35 -18
  66. package/template/.codex/skills/llm-wiki/scripts/extract.test.mjs +5 -8
  67. package/template/.codex/skills/llm-wiki/scripts/feedback.mjs +51 -0
  68. package/template/.codex/skills/llm-wiki/scripts/inventory.mjs +43 -171
  69. package/template/.codex/skills/llm-wiki/scripts/inventory.test.mjs +25 -18
  70. package/template/.codex/skills/llm-wiki/scripts/lint-wikilinks.mjs +69 -92
  71. package/template/.codex/skills/llm-wiki/scripts/lint-wikilinks.test.mjs +25 -37
  72. package/template/.codex/skills/llm-wiki/scripts/migrate.mjs +51 -0
  73. package/template/.codex/skills/llm-wiki/scripts/query.mjs +149 -0
  74. package/template/.codex/skills/llm-wiki/scripts/regressions.test.mjs +101 -0
  75. package/template/.codex/skills/llm-wiki/scripts/sources.mjs +166 -0
  76. package/template/.codex/skills/llm-wiki/scripts/transaction.mjs +384 -0
  77. package/template/.codex/skills/llm-wiki/scripts/v2.test.mjs +354 -0
  78. package/template/.codex/skills/prototype/LOGIC.md +1 -1
  79. package/template/.codex/skills/prototype/SKILL.md +5 -19
  80. package/template/.codex/skills/setup-matt-pocock-skills/SKILL.md +3 -3
  81. package/template/.codex/skills/yss-implementation-contract-compiler/SKILL.md +2 -0
  82. package/template/.codex/skills/yss-implementation-contract-compiler/references/boundaries.md +2 -3
  83. package/template/.codex/skills/yss-implementation-contract-compiler/references/yss-skill-execution-result.md +14 -0
  84. package/template/.codex/skills/yss-product-lifecycle/SKILL.md +8 -8
  85. package/template/.codex/skills/yss-product-lifecycle/references/external-input-questionnaire.md +19 -0
  86. package/template/.codex/skills/yss-product-lifecycle/references/matt-yss-adapter.md +5 -5
  87. package/template/.codex/skills/yss-product-lifecycle/references/orchestration-contract.yaml +20 -4
  88. package/template/.codex/skills/yss-product-lifecycle/references/orchestration.md +2 -2
  89. package/template/.codex/skills/yss-product-lifecycle/references/plan-requirements.md +10 -0
  90. package/template/.codex/skills/yss-product-lifecycle/references/state-model.md +1 -1
  91. package/template/.codex/skills/yss-research/SKILL.md +4 -0
  92. package/template/.cursor/skills/codebase-design/SKILL.md +4 -0
  93. package/template/.cursor/skills/{improve-codebase-architecture/SKILL.md → codebase-design/references/architecture-audit.md} +3 -9
  94. package/template/.cursor/skills/frontend-commit/SKILL.md +4 -93
  95. package/template/.cursor/skills/git-commit-core/SKILL.md +18 -0
  96. package/template/.cursor/skills/java-backend-commit/SKILL.md +4 -96
  97. package/template/.cursor/skills/llm-wiki/SKILL.md +12 -13
  98. package/template/.cursor/skills/llm-wiki/assets/CLAUDE.md.template +7 -1
  99. package/template/.cursor/skills/llm-wiki/references/compile.md +21 -114
  100. package/template/.cursor/skills/llm-wiki/references/ingest.md +8 -33
  101. package/template/.cursor/skills/llm-wiki/references/lint.md +9 -46
  102. package/template/.cursor/skills/llm-wiki/references/query.md +9 -18
  103. package/template/.cursor/skills/llm-wiki/references/schema.md +56 -29
  104. package/template/.cursor/skills/llm-wiki/references/transactions.md +48 -0
  105. package/template/.cursor/skills/llm-wiki/references/writing.md +4 -4
  106. package/template/.cursor/skills/llm-wiki/scripts/advise.mjs +46 -58
  107. package/template/.cursor/skills/llm-wiki/scripts/advise.test.mjs +11 -16
  108. package/template/.cursor/skills/llm-wiki/scripts/core.mjs +262 -0
  109. package/template/.cursor/skills/llm-wiki/scripts/extract.mjs +35 -18
  110. package/template/.cursor/skills/llm-wiki/scripts/extract.test.mjs +5 -8
  111. package/template/.cursor/skills/llm-wiki/scripts/feedback.mjs +51 -0
  112. package/template/.cursor/skills/llm-wiki/scripts/inventory.mjs +43 -171
  113. package/template/.cursor/skills/llm-wiki/scripts/inventory.test.mjs +25 -18
  114. package/template/.cursor/skills/llm-wiki/scripts/lint-wikilinks.mjs +69 -92
  115. package/template/.cursor/skills/llm-wiki/scripts/lint-wikilinks.test.mjs +25 -37
  116. package/template/.cursor/skills/llm-wiki/scripts/migrate.mjs +51 -0
  117. package/template/.cursor/skills/llm-wiki/scripts/query.mjs +149 -0
  118. package/template/.cursor/skills/llm-wiki/scripts/regressions.test.mjs +101 -0
  119. package/template/.cursor/skills/llm-wiki/scripts/sources.mjs +166 -0
  120. package/template/.cursor/skills/llm-wiki/scripts/transaction.mjs +384 -0
  121. package/template/.cursor/skills/llm-wiki/scripts/v2.test.mjs +354 -0
  122. package/template/.cursor/skills/prototype/LOGIC.md +1 -1
  123. package/template/.cursor/skills/prototype/SKILL.md +5 -19
  124. package/template/.cursor/skills/setup-matt-pocock-skills/SKILL.md +3 -3
  125. package/template/.cursor/skills/yss-implementation-contract-compiler/SKILL.md +2 -0
  126. package/template/.cursor/skills/yss-implementation-contract-compiler/references/boundaries.md +2 -3
  127. package/template/.cursor/skills/yss-implementation-contract-compiler/references/yss-skill-execution-result.md +14 -0
  128. package/template/.cursor/skills/yss-product-lifecycle/SKILL.md +8 -8
  129. package/template/.cursor/skills/yss-product-lifecycle/references/external-input-questionnaire.md +19 -0
  130. package/template/.cursor/skills/yss-product-lifecycle/references/matt-yss-adapter.md +5 -5
  131. package/template/.cursor/skills/yss-product-lifecycle/references/orchestration-contract.yaml +20 -4
  132. package/template/.cursor/skills/yss-product-lifecycle/references/orchestration.md +2 -2
  133. package/template/.cursor/skills/yss-product-lifecycle/references/plan-requirements.md +10 -0
  134. package/template/.cursor/skills/yss-product-lifecycle/references/state-model.md +1 -1
  135. package/template/.cursor/skills/yss-research/SKILL.md +4 -0
  136. package/template/.pi/skills/codebase-design/SKILL.md +4 -0
  137. package/template/{.agents/skills/improve-codebase-architecture/SKILL.md → .pi/skills/codebase-design/references/architecture-audit.md} +3 -9
  138. package/template/.pi/skills/frontend-commit/SKILL.md +4 -93
  139. package/template/.pi/skills/git-commit-core/SKILL.md +18 -0
  140. package/template/.pi/skills/java-backend-commit/SKILL.md +4 -96
  141. package/template/.pi/skills/llm-wiki/SKILL.md +12 -13
  142. package/template/.pi/skills/llm-wiki/assets/CLAUDE.md.template +7 -1
  143. package/template/.pi/skills/llm-wiki/references/compile.md +21 -114
  144. package/template/.pi/skills/llm-wiki/references/ingest.md +8 -33
  145. package/template/.pi/skills/llm-wiki/references/lint.md +9 -46
  146. package/template/.pi/skills/llm-wiki/references/query.md +9 -18
  147. package/template/.pi/skills/llm-wiki/references/schema.md +56 -29
  148. package/template/.pi/skills/llm-wiki/references/transactions.md +48 -0
  149. package/template/.pi/skills/llm-wiki/references/writing.md +4 -4
  150. package/template/.pi/skills/llm-wiki/scripts/advise.mjs +46 -58
  151. package/template/.pi/skills/llm-wiki/scripts/advise.test.mjs +11 -16
  152. package/template/.pi/skills/llm-wiki/scripts/core.mjs +262 -0
  153. package/template/.pi/skills/llm-wiki/scripts/extract.mjs +35 -18
  154. package/template/.pi/skills/llm-wiki/scripts/extract.test.mjs +5 -8
  155. package/template/.pi/skills/llm-wiki/scripts/feedback.mjs +51 -0
  156. package/template/.pi/skills/llm-wiki/scripts/inventory.mjs +43 -171
  157. package/template/.pi/skills/llm-wiki/scripts/inventory.test.mjs +25 -18
  158. package/template/.pi/skills/llm-wiki/scripts/lint-wikilinks.mjs +69 -92
  159. package/template/.pi/skills/llm-wiki/scripts/lint-wikilinks.test.mjs +25 -37
  160. package/template/.pi/skills/llm-wiki/scripts/migrate.mjs +51 -0
  161. package/template/.pi/skills/llm-wiki/scripts/query.mjs +149 -0
  162. package/template/.pi/skills/llm-wiki/scripts/regressions.test.mjs +101 -0
  163. package/template/.pi/skills/llm-wiki/scripts/sources.mjs +166 -0
  164. package/template/.pi/skills/llm-wiki/scripts/transaction.mjs +384 -0
  165. package/template/.pi/skills/llm-wiki/scripts/v2.test.mjs +354 -0
  166. package/template/.pi/skills/prototype/LOGIC.md +1 -1
  167. package/template/.pi/skills/prototype/SKILL.md +5 -19
  168. package/template/.pi/skills/setup-matt-pocock-skills/SKILL.md +3 -3
  169. package/template/.pi/skills/yss-implementation-contract-compiler/SKILL.md +2 -0
  170. package/template/.pi/skills/yss-implementation-contract-compiler/references/boundaries.md +2 -3
  171. package/template/.pi/skills/yss-implementation-contract-compiler/references/yss-skill-execution-result.md +14 -0
  172. package/template/.pi/skills/yss-product-lifecycle/SKILL.md +8 -8
  173. package/template/.pi/skills/yss-product-lifecycle/references/external-input-questionnaire.md +19 -0
  174. package/template/.pi/skills/yss-product-lifecycle/references/matt-yss-adapter.md +5 -5
  175. package/template/.pi/skills/yss-product-lifecycle/references/orchestration-contract.yaml +20 -4
  176. package/template/.pi/skills/yss-product-lifecycle/references/orchestration.md +2 -2
  177. package/template/.pi/skills/yss-product-lifecycle/references/plan-requirements.md +10 -0
  178. package/template/.pi/skills/yss-product-lifecycle/references/state-model.md +1 -1
  179. package/template/.pi/skills/yss-research/SKILL.md +4 -0
  180. package/template/.template-spec/agents/README.md +1 -1
  181. package/template/.template-spec/agents/digital-human-roles.yaml +1 -1
  182. package/template/.template-spec/agents/skill-migrations.md +15 -0
  183. package/template/.template-spec/agents/yss-skill-registry.yaml +10 -29
  184. package/template/.template-spec/architecture/README.md +3 -34
  185. package/template/.template-spec/plan/templates/competitive-analysis-template.md +2 -2
  186. package/template/.template-spec/process/contract-reading.md +24 -0
  187. package/template/.template-spec/process/lifecycle-registry-baseline.json +3 -1
  188. package/template/.template-spec/process/lifecycle-registry.yaml +6 -0
  189. package/template/.template-spec/process/research-completion.md +23 -0
  190. package/template/.template-spec/process/schemas/digital-human-task-package.schema.json +202 -12
  191. package/template/.template-spec/process/schemas/frontend-implementation-evidence.schema.json +7 -15
  192. package/template/.template-spec/process/subagent-collaboration.md +8 -0
  193. package/template/.template-spec/process/templates/frontend-implementation-verification-template.yaml +15 -1
  194. package/template/AGENTS.md +1 -1
  195. package/template/CONTEXT.md +5 -1
  196. package/template/README.md +12 -24
  197. package/template/scripts/contract +5 -5
  198. package/template/scripts/lib/contract-views.mjs +57 -2
  199. package/template/scripts/lib/execution-evidence.mjs +51 -0
  200. package/template/scripts/lib/harness-execution-scope.mjs +1 -1
  201. package/template/scripts/lib/implementation-contract-compiler.mjs +2 -0
  202. package/template/scripts/lib/lifecycle-context-query.mjs +15 -3
  203. package/template/scripts/lib/lifecycle-status.mjs +32 -6
  204. package/template/scripts/lib/lifecycle-transition.mjs +19 -1
  205. package/template/scripts/lib/maintenance-research.mjs +63 -0
  206. package/template/scripts/lib/read-only-intake.mjs +132 -0
  207. package/template/scripts/lib/skill-registry.mjs +2 -1
  208. package/template/scripts/lib/skill-supply-chain.mjs +4 -0
  209. package/template/scripts/lib/slice-task-package.mjs +1 -1
  210. package/template/scripts/lib/task-package.mjs +9 -2
  211. package/template/scripts/lifecycle-status +2 -2
  212. package/template/scripts/prepare-read-only-intake +16 -0
  213. package/template/scripts/run-read-only-intake +14 -0
  214. package/template/scripts/verify-digital-human-task-package +2 -2
  215. package/template/scripts/verify-frontend-implementation-evidence +24 -1
  216. package/template/scripts/verify-maintenance-research +13 -0
  217. package/template/skills-lock.json +19 -76
  218. package/template.manifest.json +118 -29
  219. package/template.snapshot.json +5 -6
  220. package/template/.agents/skills/grill-with-docs/SKILL.md +0 -20
  221. package/template/.agents/skills/grill-with-docs/agents/openai.yaml +0 -5
  222. package/template/.agents/skills/improve-codebase-architecture/agents/openai.yaml +0 -5
  223. package/template/.agents/skills/prototype/UI.md +0 -112
  224. package/template/.agents/skills/setup-matt-pocock-skills/domain.md +0 -37
  225. package/template/.agents/skills/to-questionnaire/SKILL.md +0 -55
  226. package/template/.agents/skills/to-questionnaire/agents/openai.yaml +0 -5
  227. package/template/.agents/skills/wait-what/SKILL.md +0 -7
  228. package/template/.agents/skills/wait-what/agents/openai.yaml +0 -5
  229. package/template/.codex/skills/data-analytics/.app.json +0 -84
  230. package/template/.codex/skills/data-analytics/.codex-plugin/plugin.json +0 -66
  231. package/template/.codex/skills/data-analytics/.mcp.json +0 -30
  232. package/template/.codex/skills/data-analytics/AGENTS.md +0 -20
  233. package/template/.codex/skills/data-analytics/DEPENDENCIES.MD +0 -27
  234. package/template/.codex/skills/data-analytics/README.md +0 -60
  235. package/template/.codex/skills/data-analytics/__yss_dotfile__.gitignore +0 -2
  236. package/template/.codex/skills/data-analytics/assets/datascience-artifact-widget.html +0 -16
  237. package/template/.codex/skills/data-analytics/assets/datascience-artifact-widget.html.gz.b64.part001 +0 -1
  238. package/template/.codex/skills/data-analytics/assets/datascience-artifact-widget.html.gz.b64.part002 +0 -1
  239. package/template/.codex/skills/data-analytics/assets/datascience-artifact-widget.html.gz.b64.part003 +0 -1
  240. package/template/.codex/skills/data-analytics/assets/datascience-artifact-widget.html.gz.b64.part004 +0 -1
  241. package/template/.codex/skills/data-analytics/assets/datascience-artifact-widget.html.gz.b64.part005 +0 -1
  242. package/template/.codex/skills/data-analytics/assets/datascience-artifact-widget.html.gz.b64.part006 +0 -1
  243. package/template/.codex/skills/data-analytics/assets/datascience-chart-widget.html +0 -16
  244. package/template/.codex/skills/data-analytics/assets/datascience-chart-widget.html.gz.b64.part001 +0 -1
  245. package/template/.codex/skills/data-analytics/assets/datascience-chart-widget.html.gz.b64.part002 +0 -1
  246. package/template/.codex/skills/data-analytics/assets/datascience-chart-widget.html.gz.b64.part003 +0 -1
  247. package/template/.codex/skills/data-analytics/assets/datascience-chart-widget.html.gz.b64.part004 +0 -1
  248. package/template/.codex/skills/data-analytics/assets/datascience-chart-widget.html.gz.b64.part005 +0 -1
  249. package/template/.codex/skills/data-analytics/assets/datascience-chart-widget.html.gz.b64.part006 +0 -1
  250. package/template/.codex/skills/data-analytics/assets/datascience-chart-widget.html.gz.b64.part007 +0 -1
  251. package/template/.codex/skills/data-analytics/assets/datascience-small.svg +0 -5
  252. package/template/.codex/skills/data-analytics/assets/datascience-table-widget.html +0 -16
  253. package/template/.codex/skills/data-analytics/assets/datascience-table-widget.html.gz.b64.part001 +0 -1
  254. package/template/.codex/skills/data-analytics/assets/datascience-table-widget.html.gz.b64.part002 +0 -1
  255. package/template/.codex/skills/data-analytics/assets/datascience-table-widget.html.gz.b64.part003 +0 -1
  256. package/template/.codex/skills/data-analytics/assets/datascience-table-widget.html.gz.b64.part004 +0 -1
  257. package/template/.codex/skills/data-analytics/assets/datascience.png +0 -0
  258. package/template/.codex/skills/data-analytics/assets/datascience.svg +0 -10
  259. package/template/.codex/skills/data-analytics/mcp/server.cjs +0 -2964
  260. package/template/.codex/skills/data-analytics/package-lock.json +0 -3048
  261. package/template/.codex/skills/data-analytics/package.json +0 -43
  262. package/template/.codex/skills/data-analytics/scripts/normalize-widget-assets.mjs +0 -75
  263. package/template/.codex/skills/data-analytics/skills/analyze-data-quality/SKILL.md +0 -137
  264. package/template/.codex/skills/data-analytics/skills/analyze-data-quality/agents/openai.yaml +0 -6
  265. package/template/.codex/skills/data-analytics/skills/analyze-data-quality/references/quality-checks.md +0 -29
  266. package/template/.codex/skills/data-analytics/skills/build-dashboard/SKILL.md +0 -148
  267. package/template/.codex/skills/data-analytics/skills/build-dashboard/agents/openai.yaml +0 -6
  268. package/template/.codex/skills/data-analytics/skills/build-dashboard/specifications/bi-platform-dashboard.md +0 -18
  269. package/template/.codex/skills/data-analytics/skills/build-dashboard/specifications/html-dashboard.md +0 -24
  270. package/template/.codex/skills/data-analytics/skills/build-dashboard/specifications/mcp-artifact-dashboard.md +0 -71
  271. package/template/.codex/skills/data-analytics/skills/build-dashboard/specifications/streamlit-dashboard.md +0 -85
  272. package/template/.codex/skills/data-analytics/skills/build-report/SKILL.md +0 -207
  273. package/template/.codex/skills/data-analytics/skills/build-report/agents/openai.yaml +0 -6
  274. package/template/.codex/skills/data-analytics/skills/build-report/assets/executive-report-shell.html +0 -70
  275. package/template/.codex/skills/data-analytics/skills/build-report/assets/technical-report-shell.html +0 -66
  276. package/template/.codex/skills/data-analytics/skills/build-report/report-to-google-doc/SKILL.md +0 -108
  277. package/template/.codex/skills/data-analytics/skills/build-report/report-to-google-doc/agents/openai.yaml +0 -6
  278. package/template/.codex/skills/data-analytics/skills/build-report/report-to-google-doc/scripts/report_to_google_doc/__init__.py +0 -1
  279. package/template/.codex/skills/data-analytics/skills/build-report/report-to-google-doc/scripts/report_to_google_doc/cli.py +0 -52
  280. package/template/.codex/skills/data-analytics/skills/build-report/report-to-google-doc/scripts/report_to_google_doc/constants.py +0 -61
  281. package/template/.codex/skills/data-analytics/skills/build-report/report-to-google-doc/scripts/report_to_google_doc/docx_writer.py +0 -362
  282. package/template/.codex/skills/data-analytics/skills/build-report/report-to-google-doc/scripts/report_to_google_doc/html_parser.py +0 -829
  283. package/template/.codex/skills/data-analytics/skills/build-report/report-to-google-doc/scripts/report_to_google_doc/model.py +0 -30
  284. package/template/.codex/skills/data-analytics/skills/build-report/report-to-google-doc/scripts/report_to_google_doc/plan.py +0 -127
  285. package/template/.codex/skills/data-analytics/skills/build-report/report-to-google-doc/scripts/report_to_google_doc/quality.py +0 -374
  286. package/template/.codex/skills/data-analytics/skills/build-report/report-to-google-doc/scripts/report_to_google_doc/rendering.py +0 -613
  287. package/template/.codex/skills/data-analytics/skills/build-report/report-to-google-doc/scripts/report_to_google_doc/table_utils.py +0 -54
  288. package/template/.codex/skills/data-analytics/skills/build-report/report-to-google-doc/scripts/report_to_google_doc/utils.py +0 -16
  289. package/template/.codex/skills/data-analytics/skills/build-report/report-to-google-doc/scripts/report_to_google_doc_plan.py +0 -9
  290. package/template/.codex/skills/data-analytics/skills/build-report/report-to-google-doc/tests/test_delivery_plan.py +0 -45
  291. package/template/.codex/skills/data-analytics/skills/build-report/report-to-google-slides/SKILL.md +0 -77
  292. package/template/.codex/skills/data-analytics/skills/build-report/report-to-google-slides/agents/openai.yaml +0 -6
  293. package/template/.codex/skills/data-analytics/skills/build-report/report-to-google-slides/scripts/report_to_google_slides.py +0 -2379
  294. package/template/.codex/skills/data-analytics/skills/build-report/report-to-pdf/SKILL.md +0 -88
  295. package/template/.codex/skills/data-analytics/skills/build-report/report-to-pdf/agents/openai.yaml +0 -6
  296. package/template/.codex/skills/data-analytics/skills/build-report/specifications/executive-report.md +0 -97
  297. package/template/.codex/skills/data-analytics/skills/build-report/specifications/mcp-app-report.md +0 -59
  298. package/template/.codex/skills/data-analytics/skills/build-report/specifications/technical-report.md +0 -75
  299. package/template/.codex/skills/data-analytics/skills/design-kpis/SKILL.md +0 -103
  300. package/template/.codex/skills/data-analytics/skills/design-kpis/agents/openai.yaml +0 -6
  301. package/template/.codex/skills/data-analytics/skills/gather-business-context/SKILL.md +0 -68
  302. package/template/.codex/skills/data-analytics/skills/gather-business-context/agents/openai.yaml +0 -6
  303. package/template/.codex/skills/data-analytics/skills/index/SKILL.md +0 -251
  304. package/template/.codex/skills/data-analytics/skills/index/agents/openai.yaml +0 -6
  305. package/template/.codex/skills/data-analytics/skills/jupyter-notebooks/SKILL.md +0 -131
  306. package/template/.codex/skills/data-analytics/skills/jupyter-notebooks/agents/openai.yaml +0 -6
  307. package/template/.codex/skills/data-analytics/skills/kpi-reporting/SKILL.md +0 -141
  308. package/template/.codex/skills/data-analytics/skills/kpi-reporting/agents/openai.yaml +0 -6
  309. package/template/.codex/skills/data-analytics/skills/kpi-reporting/references/report-templates.md +0 -32
  310. package/template/.codex/skills/data-analytics/skills/market-sizing/SKILL.md +0 -106
  311. package/template/.codex/skills/data-analytics/skills/market-sizing/agents/openai.yaml +0 -6
  312. package/template/.codex/skills/data-analytics/skills/metric-diagnostics/SKILL.md +0 -130
  313. package/template/.codex/skills/data-analytics/skills/metric-diagnostics/agents/openai.yaml +0 -6
  314. package/template/.codex/skills/data-analytics/skills/product-business-analysis/SKILL.md +0 -141
  315. package/template/.codex/skills/data-analytics/skills/product-business-analysis/agents/openai.yaml +0 -6
  316. package/template/.codex/skills/data-analytics/skills/spreadsheets/SKILL.md +0 -178
  317. package/template/.codex/skills/data-analytics/skills/spreadsheets/agents/openai.yaml +0 -9
  318. package/template/.codex/skills/data-analytics/skills/spreadsheets/assets/file-spreadsheet.png +0 -0
  319. package/template/.codex/skills/data-analytics/skills/spreadsheets/charts.md +0 -31
  320. package/template/.codex/skills/data-analytics/skills/spreadsheets/references/artifact_tool_api.md +0 -466
  321. package/template/.codex/skills/data-analytics/skills/spreadsheets/style_guidelines.md +0 -99
  322. package/template/.codex/skills/data-analytics/skills/user-context/SKILL.md +0 -197
  323. package/template/.codex/skills/data-analytics/skills/user-context/agents/openai.yaml +0 -6
  324. package/template/.codex/skills/data-analytics/skills/user-context/plugin-author-config/automation-config.md +0 -26
  325. package/template/.codex/skills/data-analytics/skills/user-context/plugin-author-config/source-category-config.json +0 -51
  326. package/template/.codex/skills/data-analytics/skills/user-context/plugin-author-config/user-context-config.md +0 -66
  327. package/template/.codex/skills/data-analytics/skills/user-context/references/automation.md +0 -69
  328. package/template/.codex/skills/data-analytics/skills/user-context/references/onboarding-examples.md +0 -204
  329. package/template/.codex/skills/data-analytics/skills/user-context/references/onboarding-state-template.json +0 -87
  330. package/template/.codex/skills/data-analytics/skills/user-context/references/onboarding.md +0 -497
  331. package/template/.codex/skills/data-analytics/skills/user-context/references/semantic-layer/connector-playbook.md +0 -74
  332. package/template/.codex/skills/data-analytics/skills/user-context/references/semantic-layer/setup.md +0 -65
  333. package/template/.codex/skills/data-analytics/skills/user-context/references/semantic-layer/skill-template.md +0 -160
  334. package/template/.codex/skills/data-analytics/skills/user-context/references/semantic-layer/source-intake.md +0 -75
  335. package/template/.codex/skills/data-analytics/skills/user-context/references/semantic-layer/weekly-polling-automation.md +0 -96
  336. package/template/.codex/skills/data-analytics/skills/user-context/references/source-category-runtime.md +0 -263
  337. package/template/.codex/skills/data-analytics/skills/user-context/scripts/data_analytics_preflight.py +0 -1462
  338. package/template/.codex/skills/data-analytics/skills/user-context/scripts/init_user_context_state.py +0 -128
  339. package/template/.codex/skills/data-analytics/skills/user-context/scripts/reset_user_context_state.py +0 -101
  340. package/template/.codex/skills/data-analytics/skills/user-context/scripts/validate_user_context_preflight.py +0 -499
  341. package/template/.codex/skills/data-analytics/skills/user-context/tests/test_state_helpers.py +0 -978
  342. package/template/.codex/skills/data-analytics/skills/validate-data/SKILL.md +0 -126
  343. package/template/.codex/skills/data-analytics/skills/validate-data/agents/openai.yaml +0 -6
  344. package/template/.codex/skills/data-analytics/skills/validate-data/references/validation-methods.md +0 -70
  345. package/template/.codex/skills/data-analytics/skills/visualize-data/SKILL.md +0 -157
  346. package/template/.codex/skills/data-analytics/skills/visualize-data/agents/openai.yaml +0 -6
  347. package/template/.codex/skills/data-analytics/skills/visualize-data/references/seaborn-templates.md +0 -774
  348. package/template/.codex/skills/data-analytics/src/DESIGN.md +0 -222
  349. package/template/.codex/skills/data-analytics/src/analytics-app/App.tsx +0 -3666
  350. package/template/.codex/skills/data-analytics/src/analytics-app/analytics-layout.test.mjs +0 -136
  351. package/template/.codex/skills/data-analytics/src/analytics-app/charting/ChartFrame.tsx +0 -54
  352. package/template/.codex/skills/data-analytics/src/analytics-app/charting/ChartLegend.tsx +0 -96
  353. package/template/.codex/skills/data-analytics/src/analytics-app/charting/ChartRenderer.tsx +0 -1647
  354. package/template/.codex/skills/data-analytics/src/analytics-app/charting/ChartTooltip.tsx +0 -245
  355. package/template/.codex/skills/data-analytics/src/analytics-app/charting/chart-app-helpers.tsx +0 -462
  356. package/template/.codex/skills/data-analytics/src/analytics-app/charting/chart-capabilities.ts +0 -107
  357. package/template/.codex/skills/data-analytics/src/analytics-app/charting/chart-compatibility.ts +0 -164
  358. package/template/.codex/skills/data-analytics/src/analytics-app/charting/chart-contract.ts +0 -192
  359. package/template/.codex/skills/data-analytics/src/analytics-app/charting/chart-theme.ts +0 -203
  360. package/template/.codex/skills/data-analytics/src/analytics-app/charting/chart-tokens.css +0 -619
  361. package/template/.codex/skills/data-analytics/src/analytics-app/charting/chart-transforms.ts +0 -402
  362. package/template/.codex/skills/data-analytics/src/analytics-app/fonts/SystemSansVariableVF.woff2 +0 -0
  363. package/template/.codex/skills/data-analytics/src/analytics-app/imageExport.ts +0 -370
  364. package/template/.codex/skills/data-analytics/src/analytics-app/layout/AnalyticsLayoutCanvas.tsx +0 -536
  365. package/template/.codex/skills/data-analytics/src/analytics-app/layout/RichMarkdown.tsx +0 -681
  366. package/template/.codex/skills/data-analytics/src/analytics-app/layout/analyticsLayoutCore.ts +0 -164
  367. package/template/.codex/skills/data-analytics/src/analytics-app/main.tsx +0 -21
  368. package/template/.codex/skills/data-analytics/src/analytics-app/scripts/chart_contract.py +0 -472
  369. package/template/.codex/skills/data-analytics/src/analytics-app/scripts/check_analytics_app_runtime_links.py +0 -75
  370. package/template/.codex/skills/data-analytics/src/analytics-app/scripts/design_contract.py +0 -142
  371. package/template/.codex/skills/data-analytics/src/analytics-app/scripts/package_utils.py +0 -142
  372. package/template/.codex/skills/data-analytics/src/analytics-app/scripts/tests/test_package_utils.py +0 -377
  373. package/template/.codex/skills/data-analytics/src/analytics-app/styles.css +0 -3468
  374. package/template/.codex/skills/data-analytics/src/analytics-app/tables/DataTable.d.ts +0 -44
  375. package/template/.codex/skills/data-analytics/src/analytics-app/tables/DataTable.jsx +0 -639
  376. package/template/.codex/skills/data-analytics/src/analytics-app/tables/data-table.css +0 -327
  377. package/template/.codex/skills/data-analytics/src/analytics-app/tokens.css +0 -225
  378. package/template/.codex/skills/data-analytics/src/analytics-app/types.ts +0 -204
  379. package/template/.codex/skills/data-analytics/src/analytics-app-core.md +0 -85
  380. package/template/.codex/skills/data-analytics/src/codex-style-contract.md +0 -30
  381. package/template/.codex/skills/data-analytics/src/datascience-artifact-widget.html +0 -12
  382. package/template/.codex/skills/data-analytics/src/datascience-artifact-widget.jsx +0 -1008
  383. package/template/.codex/skills/data-analytics/src/datascience-chart-widget.css +0 -2117
  384. package/template/.codex/skills/data-analytics/src/datascience-chart-widget.html +0 -122
  385. package/template/.codex/skills/data-analytics/src/datascience-chart-widget.js +0 -3588
  386. package/template/.codex/skills/data-analytics/src/datascience-table-widget.css +0 -483
  387. package/template/.codex/skills/data-analytics/src/datascience-table-widget.html +0 -32
  388. package/template/.codex/skills/data-analytics/src/datascience-table-widget.js +0 -333
  389. package/template/.codex/skills/data-analytics/src/mcp-host.js +0 -153
  390. package/template/.codex/skills/data-analytics/src/recharts-config.js +0 -315
  391. package/template/.codex/skills/data-analytics/src/recharts-renderer.jsx +0 -294
  392. package/template/.codex/skills/data-analytics/src/sql-source-view.css +0 -33
  393. package/template/.codex/skills/data-analytics/src/sql-source-view.js +0 -157
  394. package/template/.codex/skills/data-analytics/src/styles/codex-theme.css +0 -121
  395. package/template/.codex/skills/data-analytics/src/table-renderer.jsx +0 -28
  396. package/template/.codex/skills/data-analytics/tests/chart-transforms.test.mjs +0 -87
  397. package/template/.codex/skills/data-analytics/tests/funnel-smoke.html +0 -105
  398. package/template/.codex/skills/data-analytics/tests/inline-widget-compare.html +0 -233
  399. package/template/.codex/skills/data-analytics/tests/mcp-server.test.mjs +0 -1500
  400. package/template/.codex/skills/data-analytics/tests/native-style-contract.test.mjs +0 -219
  401. package/template/.codex/skills/data-analytics/tests/recharts-config.test.mjs +0 -144
  402. package/template/.codex/skills/data-analytics/tests/recharts-renderer.test.mjs +0 -11
  403. package/template/.codex/skills/data-analytics/tests/rich-markdown.test.mjs +0 -54
  404. package/template/.codex/skills/data-analytics/tests/widget-render-harness.html +0 -321
  405. package/template/.codex/skills/data-analytics/tsconfig.json +0 -19
  406. package/template/.codex/skills/data-analytics/vite.config.ts +0 -46
  407. package/template/.codex/skills/grill-with-docs/SKILL.md +0 -20
  408. package/template/.codex/skills/grill-with-docs/agents/openai.yaml +0 -5
  409. package/template/.codex/skills/improve-codebase-architecture/agents/openai.yaml +0 -5
  410. package/template/.codex/skills/prototype/UI.md +0 -112
  411. package/template/.codex/skills/setup-matt-pocock-skills/domain.md +0 -37
  412. package/template/.codex/skills/to-questionnaire/SKILL.md +0 -55
  413. package/template/.codex/skills/to-questionnaire/agents/openai.yaml +0 -5
  414. package/template/.codex/skills/wait-what/SKILL.md +0 -7
  415. package/template/.codex/skills/wait-what/agents/openai.yaml +0 -5
  416. package/template/.cursor/skills/grill-with-docs/SKILL.md +0 -20
  417. package/template/.cursor/skills/grill-with-docs/agents/openai.yaml +0 -5
  418. package/template/.cursor/skills/improve-codebase-architecture/agents/openai.yaml +0 -5
  419. package/template/.cursor/skills/prototype/UI.md +0 -112
  420. package/template/.cursor/skills/setup-matt-pocock-skills/domain.md +0 -37
  421. package/template/.cursor/skills/to-questionnaire/SKILL.md +0 -55
  422. package/template/.cursor/skills/to-questionnaire/agents/openai.yaml +0 -5
  423. package/template/.cursor/skills/wait-what/SKILL.md +0 -7
  424. package/template/.cursor/skills/wait-what/agents/openai.yaml +0 -5
  425. package/template/.pi/skills/grill-with-docs/SKILL.md +0 -20
  426. package/template/.pi/skills/grill-with-docs/agents/openai.yaml +0 -5
  427. package/template/.pi/skills/improve-codebase-architecture/agents/openai.yaml +0 -5
  428. package/template/.pi/skills/prototype/UI.md +0 -112
  429. package/template/.pi/skills/setup-matt-pocock-skills/domain.md +0 -37
  430. package/template/.pi/skills/to-questionnaire/SKILL.md +0 -55
  431. package/template/.pi/skills/to-questionnaire/agents/openai.yaml +0 -5
  432. package/template/.pi/skills/wait-what/SKILL.md +0 -7
  433. package/template/.pi/skills/wait-what/agents/openai.yaml +0 -5
  434. package/template/.template-spec/agents/domain.md +0 -31
  435. /package/template/.agents/skills/{improve-codebase-architecture → codebase-design/references}/HTML-REPORT.md +0 -0
  436. /package/template/.codex/skills/{improve-codebase-architecture → codebase-design/references}/HTML-REPORT.md +0 -0
  437. /package/template/.cursor/skills/{improve-codebase-architecture → codebase-design/references}/HTML-REPORT.md +0 -0
  438. /package/template/.pi/skills/{improve-codebase-architecture → codebase-design/references}/HTML-REPORT.md +0 -0
@@ -1,613 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import base64
4
- import re
5
- import shutil
6
- import subprocess
7
- from io import BytesIO
8
- from pathlib import Path
9
- from typing import Any
10
-
11
- from .constants import DEFAULT_RENDER_WORKERS, DOC_CONTENT_WIDTH_PT
12
- from .html_parser import inline_svg_report_styles
13
- from .quality import expected_chart_colors, inspect_image_object
14
- from .utils import collapse_ws
15
-
16
-
17
- def svg_float(value: Any, default: float = 0.0) -> float:
18
- if value is None:
19
- return default
20
- match = re.search(r"-?[0-9]+(?:\.[0-9]+)?", str(value))
21
- return float(match.group(0)) if match else default
22
-
23
-
24
- def parse_hex_color(
25
- value: Any, default: tuple[int, int, int] = (17, 24, 39)
26
- ) -> tuple[int, int, int] | None:
27
- if value is None:
28
- return default
29
- color = str(value).strip()
30
- if color in {"none", "transparent"}:
31
- return None
32
- if color.startswith("#"):
33
- raw = color[1:]
34
- if len(raw) == 3:
35
- raw = "".join(ch * 2 for ch in raw)
36
- if len(raw) == 6:
37
- return (int(raw[0:2], 16), int(raw[2:4], 16), int(raw[4:6], 16))
38
- return default
39
-
40
-
41
- def color_with_opacity(color: tuple[int, int, int], opacity: Any) -> tuple[int, int, int]:
42
- alpha = svg_float(opacity, 1.0)
43
- alpha = max(0.0, min(1.0, alpha))
44
- return (
45
- round(255 * (1 - alpha) + color[0] * alpha),
46
- round(255 * (1 - alpha) + color[1] * alpha),
47
- round(255 * (1 - alpha) + color[2] * alpha),
48
- )
49
-
50
-
51
- def svg_path_points(path_data: str) -> list[tuple[float, float]]:
52
- points: list[tuple[float, float]] = []
53
- for match in re.finditer(
54
- r"[ML]\s*(-?[0-9]+(?:\.[0-9]+)?)\s*,?\s*(-?[0-9]+(?:\.[0-9]+)?)",
55
- path_data,
56
- flags=re.IGNORECASE,
57
- ):
58
- points.append((float(match.group(1)), float(match.group(2))))
59
- return points
60
-
61
-
62
- def load_svg_font(size: int, bold: bool = False) -> Any:
63
- try:
64
- from PIL import ImageFont
65
- except ImportError: # pragma: no cover - dependency check path
66
- return None
67
-
68
- paths = []
69
- if bold:
70
- paths.extend(
71
- [
72
- "/System/Library/Fonts/Supplemental/Arial Bold.ttf",
73
- "/System/Library/Fonts/Supplemental/Arial Bold Italic.ttf",
74
- "/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf",
75
- ]
76
- )
77
- paths.extend(
78
- [
79
- "/System/Library/Fonts/Supplemental/Arial.ttf",
80
- "/System/Library/Fonts/SFNS.ttf",
81
- "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",
82
- ]
83
- )
84
- for path in paths:
85
- if Path(path).exists():
86
- return ImageFont.truetype(path, size)
87
- return ImageFont.load_default()
88
-
89
-
90
- def render_simple_svg_with_pillow(
91
- svg_markup: str, path: Path, width_px: int, height_px: int
92
- ) -> None:
93
- """Render the SVG subset produced by the report builders.
94
-
95
- This intentionally covers the report-chart primitives we commonly emit
96
- (`rect`, `line`, and `text`) so conversions do not depend on visible browser
97
- automation or system Cairo libraries.
98
- """
99
-
100
- try:
101
- from bs4 import BeautifulSoup
102
- from PIL import Image, ImageDraw
103
- except ImportError as exc: # pragma: no cover - dependency check path
104
- raise RuntimeError("Pillow SVG fallback requires beautifulsoup4 and pillow") from exc
105
-
106
- scale = 2
107
- soup = BeautifulSoup(inline_svg_report_styles(svg_markup), "xml")
108
- svg = soup.find("svg") or soup
109
- image = Image.new("RGB", (width_px * scale, height_px * scale), (255, 255, 255))
110
- draw = ImageDraw.Draw(image)
111
-
112
- def scaled_points_from_path(path_data: str) -> list[tuple[float, float]]:
113
- points: list[tuple[float, float]] = []
114
- for match in re.finditer(
115
- r"[ML]\s*(-?[0-9]+(?:\.[0-9]+)?)\s+(-?[0-9]+(?:\.[0-9]+)?)", path_data
116
- ):
117
- points.append((float(match.group(1)) * scale, float(match.group(2)) * scale))
118
- return points
119
-
120
- for el in svg.find_all(True):
121
- if el.name == "rect":
122
- fill = parse_hex_color(el.get("fill"), (255, 255, 255))
123
- if fill is None:
124
- continue
125
- fill = color_with_opacity(fill, el.get("opacity"))
126
- x = svg_float(el.get("x")) * scale
127
- y = svg_float(el.get("y")) * scale
128
- w = svg_float(el.get("width"), width_px) * scale
129
- h = svg_float(el.get("height"), height_px) * scale
130
- radius = max(svg_float(el.get("rx")), svg_float(el.get("ry"))) * scale
131
- box = [x, y, x + w, y + h]
132
- if radius:
133
- draw.rounded_rectangle(box, radius=radius, fill=fill)
134
- else:
135
- draw.rectangle(box, fill=fill)
136
- elif el.name == "path":
137
- points = [(x * scale, y * scale) for x, y in svg_path_points(str(el.get("d") or ""))]
138
- if len(points) < 2:
139
- continue
140
- fill = parse_hex_color(el.get("fill"), None)
141
- if fill is not None and str(el.get("fill")).strip().lower() != "none":
142
- draw.polygon(points, fill=color_with_opacity(fill, el.get("opacity")))
143
- stroke = parse_hex_color(el.get("stroke"), None)
144
- if stroke is not None:
145
- width = max(1, round(svg_float(el.get("stroke-width"), 1) * scale))
146
- draw.line(points, fill=stroke, width=width, joint="curve")
147
- elif el.name == "circle":
148
- cx = svg_float(el.get("cx")) * scale
149
- cy = svg_float(el.get("cy")) * scale
150
- radius = svg_float(el.get("r")) * scale
151
- box = [cx - radius, cy - radius, cx + radius, cy + radius]
152
- fill = parse_hex_color(el.get("fill"), None)
153
- stroke = parse_hex_color(el.get("stroke"), None)
154
- width = max(1, round(svg_float(el.get("stroke-width"), 1) * scale))
155
- if fill is not None:
156
- draw.ellipse(box, fill=color_with_opacity(fill, el.get("opacity")))
157
- if stroke is not None:
158
- draw.ellipse(box, outline=stroke, width=width)
159
- elif el.name == "line":
160
- stroke = parse_hex_color(el.get("stroke"))
161
- if stroke is None:
162
- continue
163
- x1 = svg_float(el.get("x1")) * scale
164
- y1 = svg_float(el.get("y1")) * scale
165
- x2 = svg_float(el.get("x2")) * scale
166
- y2 = svg_float(el.get("y2")) * scale
167
- width = max(1, round(svg_float(el.get("stroke-width"), 1) * scale))
168
- draw.line([x1, y1, x2, y2], fill=stroke, width=width)
169
- if el.get("stroke-linecap") == "round":
170
- radius = width / 2
171
- for x, y in [(x1, y1), (x2, y2)]:
172
- draw.ellipse([x - radius, y - radius, x + radius, y + radius], fill=stroke)
173
- elif el.name == "path":
174
- points = scaled_points_from_path(str(el.get("d") or ""))
175
- if len(points) < 2:
176
- continue
177
- fill = parse_hex_color(el.get("fill"), None)
178
- if fill is not None and str(el.get("d") or "").strip().endswith("Z"):
179
- draw.polygon(points, fill=fill)
180
- stroke = parse_hex_color(el.get("stroke"), None)
181
- if stroke is not None:
182
- width = max(1, round(svg_float(el.get("stroke-width"), 1) * scale))
183
- draw.line(points, fill=stroke, width=width, joint="curve")
184
- if el.get("stroke-linecap") == "round":
185
- radius = width / 2
186
- for x, y in (points[0], points[-1]):
187
- draw.ellipse([x - radius, y - radius, x + radius, y + radius], fill=stroke)
188
- elif el.name == "circle":
189
- fill = parse_hex_color(el.get("fill"), None)
190
- stroke = parse_hex_color(el.get("stroke"), None)
191
- cx = svg_float(el.get("cx")) * scale
192
- cy = svg_float(el.get("cy")) * scale
193
- radius = svg_float(el.get("r")) * scale
194
- box = [cx - radius, cy - radius, cx + radius, cy + radius]
195
- if fill is not None:
196
- draw.ellipse(box, fill=fill)
197
- if stroke is not None:
198
- width = max(1, round(svg_float(el.get("stroke-width"), 1) * scale))
199
- draw.ellipse(box, outline=stroke, width=width)
200
- elif el.name == "text":
201
- text = collapse_ws(el.get_text("", strip=True)).strip()
202
- if not text:
203
- continue
204
- fill = parse_hex_color(el.get("fill"))
205
- if fill is None:
206
- continue
207
- size = max(1, round(svg_float(el.get("font-size"), 12) * scale))
208
- weight = svg_float(el.get("font-weight"), 400)
209
- font = load_svg_font(size, bold=weight >= 600)
210
- anchor = {"middle": "ms", "end": "rs"}.get(str(el.get("text-anchor", "")).strip(), "ls")
211
- draw.text(
212
- (svg_float(el.get("x")) * scale, svg_float(el.get("y")) * scale),
213
- text,
214
- fill=fill,
215
- font=font,
216
- anchor=anchor,
217
- )
218
-
219
- image.save(path, optimize=True)
220
-
221
-
222
- def load_report_font(size: int, bold: bool = False) -> Any:
223
- try:
224
- from PIL import ImageFont
225
- except ImportError: # pragma: no cover - dependency check path
226
- return None
227
-
228
- paths = []
229
- if bold:
230
- paths.extend(
231
- [
232
- "/System/Library/Fonts/Supplemental/Arial Bold.ttf",
233
- "/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf",
234
- ]
235
- )
236
- paths.extend(
237
- [
238
- "/System/Library/Fonts/Supplemental/Arial.ttf",
239
- "/System/Library/Fonts/SFNS.ttf",
240
- "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",
241
- ]
242
- )
243
- for path in paths:
244
- if Path(path).exists():
245
- return ImageFont.truetype(path, size)
246
- return ImageFont.load_default()
247
-
248
-
249
- def draw_right_aligned_text(
250
- draw: Any, xy: tuple[int, int], text: str, font: Any, fill: Any
251
- ) -> None:
252
- bbox = draw.textbbox((0, 0), text, font=font)
253
- draw.text((xy[0] - (bbox[2] - bbox[0]), xy[1]), text, font=font, fill=fill)
254
-
255
-
256
- def render_two_col_table_grid(chart: dict[str, Any], path: Path) -> None:
257
- try:
258
- from PIL import Image, ImageDraw
259
- except ImportError as exc: # pragma: no cover - dependency check path
260
- raise RuntimeError("Two-column table rendering requires pillow") from exc
261
-
262
- scale = 2
263
- css_w = 920
264
- gap = 20
265
- pad_x = 18
266
- pad_y = 4
267
- panel_count = max(1, len(chart["panels"]))
268
- panel_w = (css_w - gap * (panel_count - 1) - pad_x * 2) / panel_count
269
- title_h = 28
270
- header_h = 32
271
- row_h = 34
272
- panel_heights = [
273
- title_h + header_h + max(0, len(panel["rows"]) - 1) * row_h for panel in chart["panels"]
274
- ]
275
- css_h = pad_y * 2 + max(panel_heights)
276
- image = Image.new("RGB", (css_w * scale, css_h * scale), (255, 255, 255))
277
- draw = ImageDraw.Draw(image)
278
-
279
- ink = (32, 37, 43)
280
- muted = (98, 109, 121)
281
- faint = (229, 234, 239)
282
- green = (38, 132, 95)
283
- red = (199, 81, 70)
284
-
285
- title_font = load_report_font(13 * scale, bold=True)
286
- header_font = load_report_font(13 * scale, bold=True)
287
- body_font = load_report_font(13 * scale)
288
- body_bold_font = load_report_font(13 * scale, bold=True)
289
-
290
- def sx(value: float) -> int:
291
- return round(value * scale)
292
-
293
- for panel_idx, panel in enumerate(chart["panels"]):
294
- x0 = pad_x + panel_idx * (panel_w + gap)
295
- y0 = pad_y
296
- rows = panel["rows"]
297
- styles = panel.get("cell_styles", [[[] for _ in row] for row in rows])
298
- title = str(panel.get("title") or "").upper()
299
- draw.text((sx(x0), sx(y0 + 2)), title, font=title_font, fill=muted)
300
-
301
- table_y = y0 + title_h
302
- col_widths = [panel_w * 0.40, panel_w * 0.20, panel_w * 0.20, panel_w * 0.20]
303
- col_lefts = [x0]
304
- for width in col_widths[:-1]:
305
- col_lefts.append(col_lefts[-1] + width)
306
- table_right = x0 + sum(col_widths)
307
-
308
- for r, row in enumerate(rows):
309
- row_top = table_y + (0 if r == 0 else header_h + (r - 1) * row_h)
310
- current_h = header_h if r == 0 else row_h
311
- line_y = row_top + current_h
312
- draw.line((sx(x0), sx(line_y), sx(table_right), sx(line_y)), fill=faint, width=scale)
313
- for c, text in enumerate(row):
314
- cell_styles = set(styles[r][c]) if r < len(styles) and c < len(styles[r]) else set()
315
- is_numeric = c > 0
316
- color = muted if r == 0 else ink
317
- if "positive" in cell_styles:
318
- color = green
319
- elif "negative" in cell_styles:
320
- color = red
321
- font = header_font if r == 0 or "bold" in cell_styles else body_font
322
- if "positive" in cell_styles or "negative" in cell_styles:
323
- font = body_bold_font
324
- y_text = row_top + (8 if r == 0 else 9)
325
- if is_numeric:
326
- draw_right_aligned_text(
327
- draw,
328
- (sx(col_lefts[c] + col_widths[c] - 7), sx(y_text)),
329
- text,
330
- font,
331
- color,
332
- )
333
- else:
334
- draw.text((sx(col_lefts[c] + 7), sx(y_text)), text, font=font, fill=color)
335
-
336
- image.save(path, optimize=True)
337
- chart["image_width_px"] = css_w * scale
338
- chart["image_height_px"] = css_h * scale
339
- chart["docs_width_pt"] = DOC_CONTENT_WIDTH_PT
340
- chart["docs_height_pt"] = round(DOC_CONTENT_WIDTH_PT * css_h / css_w, 1)
341
- chart["render_preflight_stats"] = inspect_image_object(
342
- image,
343
- expected_chart_colors(chart),
344
- exact_color_scan=True,
345
- )
346
-
347
-
348
- def load_bar_chart_font() -> Any:
349
- try:
350
- from PIL import ImageFont
351
- except ImportError as exc: # pragma: no cover - dependency check path
352
- raise RuntimeError("Bar chart rendering requires pillow") from exc
353
-
354
- for font_path in [
355
- "/System/Library/Fonts/SFNS.ttf",
356
- "/System/Library/Fonts/Supplemental/Arial.ttf",
357
- "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",
358
- ]:
359
- if Path(font_path).exists():
360
- return ImageFont.truetype(font_path, 28)
361
- return ImageFont.load_default()
362
-
363
-
364
- def png_is_blank_or_near_empty(candidate: Path) -> bool:
365
- try:
366
- from PIL import Image
367
- except ImportError:
368
- return False
369
- try:
370
- with Image.open(candidate) as image:
371
- rgb_image = image.convert("RGB")
372
- if hasattr(rgb_image, "get_flattened_data"):
373
- pixels = list(rgb_image.get_flattened_data())
374
- else:
375
- pixels = list(rgb_image.getdata())
376
- except Exception:
377
- return True
378
- if not pixels:
379
- return True
380
- sample = pixels[: min(len(pixels), 10000)]
381
- if len(set(sample)) <= 1 and len(set(pixels)) <= 1:
382
- return True
383
- non_white = sum(1 for red, green, blue in pixels if min(red, green, blue) < 245)
384
- return non_white / len(pixels) < 0.002
385
-
386
-
387
- def render_svg_chart_image(chart: dict[str, Any], out_dir: Path) -> None:
388
- image_dir = out_dir / "chart_images"
389
- path = out_dir / chart["image_file"]
390
- svg_markup = chart["svg_markup"].encode("utf-8")
391
- try:
392
- import cairosvg # type: ignore[import-not-found]
393
-
394
- cairosvg.svg2png(bytestring=svg_markup, write_to=str(path))
395
- except Exception:
396
- rsvg_convert = shutil.which("rsvg-convert")
397
- if rsvg_convert:
398
- subprocess.run(
399
- [rsvg_convert, "-f", "png", "-o", str(path)],
400
- input=svg_markup,
401
- check=True,
402
- )
403
- else:
404
- width_px = int(chart.get("source_width_px", 1000))
405
- height_px = int(chart.get("source_height_px", 600))
406
- try:
407
- render_simple_svg_with_pillow(chart["svg_markup"], path, width_px, height_px)
408
- except Exception:
409
- pass
410
- if path.exists() and png_is_blank_or_near_empty(path):
411
- path.unlink()
412
- if not path.exists():
413
- try:
414
- from playwright.sync_api import sync_playwright
415
- except ImportError as exc: # pragma: no cover - dependency check path
416
- raise SystemExit(
417
- "SVG chart rendering requires cairosvg, rsvg-convert, or "
418
- "python playwright with an installed Chromium browser; the "
419
- "built-in Pillow fallback could not render this SVG."
420
- ) from exc
421
- width_px = int(chart.get("source_width_px", 1000))
422
- height_px = int(chart.get("source_height_px", 600))
423
- tmp_html = image_dir / f"{chart['id'].lower()}_render.html"
424
- tmp_html.write_text(
425
- "<!doctype html><meta charset='utf-8'>"
426
- "<style>body{margin:0;background:white}svg{display:block}</style>"
427
- + chart["svg_markup"],
428
- encoding="utf-8",
429
- )
430
- with sync_playwright() as playwright:
431
- browser = playwright.chromium.launch(headless=True)
432
- page = browser.new_page(
433
- viewport={"width": width_px, "height": height_px},
434
- device_scale_factor=2,
435
- )
436
- page.goto(tmp_html.resolve().as_uri())
437
- page.locator("svg").screenshot(path=str(path))
438
- browser.close()
439
- tmp_html.unlink(missing_ok=True)
440
- chart["image_width_px"] = chart.get("source_width_px", 1000)
441
- chart["image_height_px"] = chart.get("source_height_px", 600)
442
-
443
-
444
- def render_bar_chart_image(chart: dict[str, Any], out_dir: Path) -> None:
445
- try:
446
- from PIL import Image, ImageDraw
447
- except ImportError as exc: # pragma: no cover - dependency check path
448
- raise RuntimeError("Bar chart rendering requires pillow") from exc
449
-
450
- css_w = 760
451
- label_w = 92
452
- value_w = 84
453
- gap = 12
454
- track_w = css_w - label_w - value_w - 2 * gap
455
- row_h = 28
456
- chart_gap = 10
457
- pad_y = 6
458
- scale = 2
459
- ink = (23, 32, 38)
460
- track = (232, 238, 241)
461
- accent = (15, 118, 110)
462
- blue = (29, 78, 216)
463
- font = load_bar_chart_font()
464
-
465
- rows = chart["rows"]
466
- width = css_w * scale
467
- height = (pad_y * 2 + len(rows) * row_h + (len(rows) - 1) * chart_gap) * scale
468
- image = Image.new("RGB", (width, height), (255, 255, 255))
469
- draw = ImageDraw.Draw(image)
470
- fill_color = blue if chart.get("bar_color") == "blue" else accent
471
- radius = 6 * scale
472
-
473
- for idx, row in enumerate(rows):
474
- y = (pad_y + idx * (row_h + chart_gap)) * scale
475
- draw.text((0, y - 2 * scale), row["label"], font=font, fill=ink)
476
- track_x = (label_w + gap) * scale
477
- track_y = y + 5 * scale
478
- track_width = track_w * scale
479
- track_height = 18 * scale
480
- draw.rounded_rectangle(
481
- [track_x, track_y, track_x + track_width, track_y + track_height],
482
- radius=radius,
483
- fill=track,
484
- )
485
- fill_width = max(0, min(track_width, track_width * float(row["pct"]) / 100.0))
486
- draw.rounded_rectangle(
487
- [track_x, track_y, track_x + fill_width, track_y + track_height],
488
- radius=radius,
489
- fill=fill_color,
490
- )
491
- bbox = draw.textbbox((0, 0), row["value"], font=font)
492
- value_width = bbox[2] - bbox[0]
493
- value_x = (label_w + gap + track_w + gap + value_w) * scale - value_width
494
- draw.text((value_x, y - 2 * scale), row["value"], font=font, fill=ink)
495
-
496
- path = out_dir / chart["image_file"]
497
- image.save(path, optimize=True)
498
- chart["image_width_px"] = width
499
- chart["image_height_px"] = height
500
- chart["docs_width_pt"] = DOC_CONTENT_WIDTH_PT
501
- chart["docs_height_pt"] = round(DOC_CONTENT_WIDTH_PT * height / width, 1)
502
- chart["render_preflight_stats"] = inspect_image_object(image, expected_chart_colors(chart))
503
-
504
-
505
- def render_embedded_image(chart: dict[str, Any], out_dir: Path) -> None:
506
- try:
507
- from PIL import Image, ImageOps
508
- except ImportError as exc: # pragma: no cover - dependency check path
509
- raise RuntimeError("Embedded image rendering requires pillow") from exc
510
-
511
- src = str(chart.get("src") or "")
512
- match = re.match(r"data:image/[^;]+;base64,(.+)", src, flags=re.DOTALL)
513
- if not match:
514
- raise RuntimeError("Only base64 data URI report images are supported")
515
-
516
- raw = base64.b64decode(re.sub(r"\s+", "", match.group(1)), validate=False)
517
- path = out_dir / chart["image_file"]
518
- with Image.open(BytesIO(raw)) as image:
519
- image = ImageOps.exif_transpose(image)
520
- if image.mode == "RGBA":
521
- background = Image.new("RGB", image.size, (255, 255, 255))
522
- background.paste(image, mask=image.getchannel("A"))
523
- image = background
524
- elif image.mode != "RGB":
525
- image = image.convert("RGB")
526
- width, height = image.size
527
- image.save(path, format="PNG", optimize=True)
528
- chart["image_width_px"] = width
529
- chart["image_height_px"] = height
530
- chart["docs_width_pt"] = DOC_CONTENT_WIDTH_PT
531
- chart["docs_height_pt"] = round(DOC_CONTENT_WIDTH_PT * height / width, 1) if width else 240
532
- chart["render_preflight_stats"] = inspect_image_object(image, expected_chart_colors(chart))
533
-
534
-
535
- def render_single_chart_image(chart: dict[str, Any], out_dir: Path) -> None:
536
- kind = chart.get("kind")
537
- if kind == "two_col_table_grid":
538
- render_two_col_table_grid(chart, out_dir / chart["image_file"])
539
- elif kind == "svg":
540
- render_svg_chart_image(chart, out_dir)
541
- elif kind == "bar_chart":
542
- render_bar_chart_image(chart, out_dir)
543
- elif kind == "embedded_image":
544
- render_embedded_image(chart, out_dir)
545
- else:
546
- raise RuntimeError(f"Unsupported chart image kind: {kind}")
547
-
548
-
549
- def choose_render_workers(charts: list[dict[str, Any]], requested_workers: int) -> int:
550
- """Pick a conservative local render worker count.
551
-
552
- The renderer mix matters more than CPU count. SVG-only reports spend most
553
- of their time inside external/native renderers, so modest concurrency is a
554
- meaningful speedup. Pillow-heavy reports stay serial by default because the
555
- extra thread overhead is less predictably useful for those small images.
556
- """
557
- if not charts:
558
- return 1
559
- requested = int(requested_workers)
560
- if requested > 0:
561
- return min(requested, len(charts))
562
- if all(chart.get("kind") == "svg" for chart in charts):
563
- return min(6, len(charts))
564
- return 1
565
-
566
-
567
- def render_chart_images(
568
- manifest: dict[str, Any], out_dir: Path, render_workers: int = DEFAULT_RENDER_WORKERS
569
- ) -> None:
570
- """Render every visual block before any remote Docs write happens.
571
-
572
- The output PNGs are the quality boundary for charts and multi-column table
573
- groups. Rendering them in parallel is safe because each chart writes to a
574
- distinct filename and the manifest order is preserved for Docs insertion.
575
- """
576
- charts = manifest.get("chart_images", [])
577
- if not charts:
578
- return
579
-
580
- needs_pillow = any(
581
- chart.get("kind") in {"bar_chart", "embedded_image", "two_col_table_grid"}
582
- for chart in charts
583
- )
584
- if needs_pillow:
585
- try:
586
- __import__("PIL.Image")
587
- except ImportError as exc: # pragma: no cover - dependency check path
588
- raise SystemExit(
589
- "Bar chart-image mode requires Pillow. Install pillow or rerun with "
590
- "`--chart-mode table` to use the old native-table approximation."
591
- ) from exc
592
-
593
- image_dir = out_dir / "chart_images"
594
- image_dir.mkdir(parents=True, exist_ok=True)
595
-
596
- workers = choose_render_workers(charts, render_workers)
597
- if workers == 1 or len(charts) == 1:
598
- for chart in charts:
599
- render_single_chart_image(chart, out_dir)
600
- return
601
-
602
- from concurrent.futures import ThreadPoolExecutor, as_completed
603
-
604
- with ThreadPoolExecutor(max_workers=min(workers, len(charts))) as executor:
605
- futures = {
606
- executor.submit(render_single_chart_image, chart, out_dir): chart for chart in charts
607
- }
608
- for future in as_completed(futures):
609
- chart = futures[future]
610
- try:
611
- future.result()
612
- except Exception as exc:
613
- raise RuntimeError(f"Failed to render {chart.get('id')}: {exc}") from exc
@@ -1,54 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import re
4
- from typing import Any
5
-
6
- from .constants import DOC_CONTENT_WIDTH_PT
7
-
8
- NUMERIC_TABLE_CELL_RE = re.compile(r"^[\s$%+,\-()./:0-9xXkKmMbBtT]+$")
9
-
10
-
11
- def table_column_widths(table: dict[str, Any], columns: int) -> list[float]:
12
- if columns <= 0:
13
- return []
14
-
15
- total_width = float(table.get("docs_width_pt", DOC_CONTENT_WIDTH_PT))
16
- kind = table.get("kind")
17
- if kind == "metric_cards" or columns <= 4:
18
- width = total_width / columns
19
- return [round(width, 1)] * columns
20
-
21
- if columns == 5:
22
- first = 120.0
23
- elif columns >= 6:
24
- first = 90.0
25
- else:
26
- first = total_width / columns
27
-
28
- first = min(first, total_width / columns * 1.15)
29
- remaining = (total_width - first) / (columns - 1)
30
- return [round(first, 1)] + [round(remaining, 1)] * (columns - 1)
31
-
32
-
33
- def table_cell_is_numeric(text: str) -> bool:
34
- stripped = text.strip()
35
- return bool(
36
- stripped
37
- and any(char.isdigit() for char in stripped)
38
- and NUMERIC_TABLE_CELL_RE.match(stripped)
39
- )
40
-
41
-
42
- def numeric_table_columns(rows: list[list[str]]) -> set[int]:
43
- if not rows:
44
- return set()
45
- numeric_columns: set[int] = set()
46
- for column_index in range(len(rows[0])):
47
- values = [
48
- row[column_index]
49
- for row in rows[1:]
50
- if column_index < len(row) and row[column_index].strip()
51
- ]
52
- if values and all(table_cell_is_numeric(value) for value in values):
53
- numeric_columns.add(column_index)
54
- return numeric_columns
@@ -1,16 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import re
4
- from typing import Any
5
-
6
-
7
- def rgb(color: dict[str, float]) -> dict[str, Any]:
8
- return {"color": {"rgbColor": color}}
9
-
10
-
11
- def docs_range(start: int, end: int) -> dict[str, int]:
12
- return {"startIndex": start + 1, "endIndex": end + 1}
13
-
14
-
15
- def collapse_ws(text: str) -> str:
16
- return re.sub(r"\s+", " ", text)
@@ -1,9 +0,0 @@
1
- #!/usr/bin/env python3
2
- """Stable CLI wrapper for the Report-to-Google-Doc planning helper."""
3
-
4
- from __future__ import annotations
5
-
6
- from report_to_google_doc.cli import main
7
-
8
- if __name__ == "__main__":
9
- main()