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,829 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import re
4
- from pathlib import Path
5
- from typing import Any
6
-
7
- try:
8
- from bs4 import BeautifulSoup, NavigableString, Tag
9
- except ImportError as exc: # pragma: no cover - dependency check path
10
- BeautifulSoup = NavigableString = Tag = None # type: ignore[assignment,misc]
11
- BS4_IMPORT_ERROR = exc
12
- else:
13
- BS4_IMPORT_ERROR = None
14
-
15
- from .constants import DOC_CONTENT_WIDTH_PT, SVG_REPORT_STYLE_DEFAULTS
16
- from .model import Builder
17
- from .utils import collapse_ws
18
-
19
- FONT_WEIGHT_BOLD_RE = re.compile(r"font-weight\s*:\s*([^;}\s]+)", re.IGNORECASE)
20
- CSS_RULE_RE = re.compile(r"([^{}]+)\{([^{}]*)\}", re.DOTALL)
21
-
22
-
23
- def require_bs4() -> None:
24
- if BS4_IMPORT_ERROR is not None:
25
- raise SystemExit(
26
- "This helper requires beautifulsoup4. Install it in the active Python "
27
- "environment before running this helper."
28
- ) from BS4_IMPORT_ERROR
29
-
30
-
31
- def append_text(builder: Builder, text: str) -> None:
32
- text = collapse_ws(text)
33
- if not text:
34
- return
35
- if text.isspace():
36
- if builder.offset and not builder.text().endswith((" ", "\n")):
37
- builder.add(" ")
38
- return
39
- if builder.offset and not builder.text().endswith((" ", "\n")) and text[0] not in " .,;:!?)%]":
40
- builder.add(" ")
41
- builder.add(text)
42
-
43
-
44
- def classes(node: Tag) -> set[str]:
45
- raw = node.get("class") or []
46
- return set(raw if isinstance(raw, list) else str(raw).split())
47
-
48
-
49
- def direct_tag_children(node: Tag) -> list[Tag]:
50
- return [child for child in node.children if isinstance(child, Tag)]
51
-
52
-
53
- def direct_children_with_class(node: Tag, class_name: str) -> list[Tag]:
54
- return [child for child in direct_tag_children(node) if class_name in classes(child)]
55
-
56
-
57
- def font_weight_is_bold(value: str) -> bool:
58
- value = value.strip().lower()
59
- if value in {"bold", "bolder"}:
60
- return True
61
- try:
62
- return int(value) >= 600
63
- except ValueError:
64
- return False
65
-
66
-
67
- def inline_style_is_bold(style: str | None) -> bool:
68
- if not style:
69
- return False
70
- match = FONT_WEIGHT_BOLD_RE.search(style)
71
- return bool(match and font_weight_is_bold(match.group(1)))
72
-
73
-
74
- def table_first_column_is_bold(raw_html: str) -> bool:
75
- accepted_selectors = {
76
- "td:first-child",
77
- "td:nth-child(1)",
78
- "tbody td:first-child",
79
- "tbody td:nth-child(1)",
80
- "table td:first-child",
81
- "table td:nth-child(1)",
82
- "table tbody td:first-child",
83
- "table tbody td:nth-child(1)",
84
- }
85
- for selectors, body in CSS_RULE_RE.findall(raw_html):
86
- weight = FONT_WEIGHT_BOLD_RE.search(body)
87
- if not weight or not font_weight_is_bold(weight.group(1)):
88
- continue
89
- normalized_selectors = {
90
- re.sub(r"\s+", " ", selector.strip().lower()) for selector in selectors.split(",")
91
- }
92
- if normalized_selectors & accepted_selectors:
93
- return True
94
- return False
95
-
96
-
97
- def append_inline(builder: Builder, node: Tag | NavigableString) -> None:
98
- if isinstance(node, NavigableString):
99
- append_text(builder, str(node))
100
- return
101
- if not isinstance(node, Tag):
102
- return
103
-
104
- before = builder.offset
105
- for child in node.children:
106
- append_inline(builder, child)
107
- after = builder.offset
108
- if after <= before:
109
- return
110
-
111
- tag_classes = classes(node)
112
- styles: list[str] = []
113
- if node.name in {"strong", "b"}:
114
- styles.append("bold")
115
- if node.name in {"em", "i"}:
116
- styles.append("italic")
117
- if node.name == "code":
118
- styles.append("code")
119
- if "positive" in tag_classes:
120
- styles.append("positive")
121
- if "negative" in tag_classes:
122
- styles.append("negative")
123
- if node.name == "a" and node.get("href"):
124
- styles.append("link")
125
-
126
- for style in styles:
127
- entry: dict[str, Any] = {
128
- "start": before,
129
- "end": after,
130
- "style": style,
131
- "text": builder.text()[before:after],
132
- }
133
- if style == "link":
134
- entry["url"] = node["href"]
135
- builder.inline_styles.append(entry)
136
-
137
-
138
- def add_paragraph(builder: Builder, node: Tag, block_type: str | None = None) -> None:
139
- start = builder.offset
140
- append_inline(builder, node)
141
- end = builder.offset
142
- if end > start:
143
- builder.add("\n")
144
- if block_type:
145
- builder.blocks.append({"start": start, "end": end + 1, "type": block_type})
146
-
147
-
148
- def add_heading(builder: Builder, node: Tag) -> None:
149
- start = builder.offset
150
- append_inline(builder, node)
151
- end = builder.offset
152
- level = int(node.name[1]) if node.name and node.name[1:].isdigit() else 2
153
- builder.add("\n")
154
- builder.headings.append(
155
- {"start": start, "end": end, "level": level, "text": builder.text()[start:end]}
156
- )
157
-
158
-
159
- def cell_text_styles_and_links(
160
- cell: Tag, first_column_bold: bool = False
161
- ) -> tuple[str, list[str], list[dict[str, Any]]]:
162
- local_builder = Builder()
163
- append_inline(local_builder, cell)
164
- raw_text = local_builder.text()
165
- leading_trim = len(raw_text) - len(raw_text.lstrip())
166
- text = raw_text.strip()
167
- styles = []
168
- if cell.find(["strong", "b"]) or cell.name == "th" or inline_style_is_bold(cell.get("style")):
169
- styles.append("bold")
170
- if first_column_bold and cell.name == "td" and "bold" not in styles:
171
- styles.append("bold")
172
- if cell.find("code"):
173
- styles.append("code")
174
- cell_classes = classes(cell)
175
- if "positive" in cell_classes or "pos" in cell_classes or "strong" in cell_classes:
176
- styles.append("positive")
177
- if "negative" in cell_classes or "neg" in cell_classes or "weak" in cell_classes:
178
- styles.append("negative")
179
- if "neutral" in cell_classes:
180
- styles.append("neutral")
181
- links = []
182
- for style in local_builder.inline_styles:
183
- if style.get("style") != "link":
184
- continue
185
- start = max(0, style["start"] - leading_trim)
186
- end = min(len(text), style["end"] - leading_trim)
187
- while start < end and text[start].isspace():
188
- start += 1
189
- while end > start and text[end - 1].isspace():
190
- end -= 1
191
- if start >= end:
192
- continue
193
- links.append(
194
- {
195
- "start": start,
196
- "end": end,
197
- "url": style["url"],
198
- "text": text[start:end],
199
- }
200
- )
201
- return text, styles, links
202
-
203
-
204
- def table_from_html(
205
- node: Tag,
206
- first_column_bold: bool = False,
207
- ) -> tuple[list[list[str]], list[list[list[str]]], list[list[list[dict[str, Any]]]]]:
208
- rows: list[list[str]] = []
209
- styles: list[list[list[str]]] = []
210
- links: list[list[list[dict[str, Any]]]] = []
211
- for tr in node.find_all("tr"):
212
- row: list[str] = []
213
- style_row: list[list[str]] = []
214
- link_row: list[list[dict[str, Any]]] = []
215
- for cell_index, cell in enumerate(tr.find_all(["th", "td"], recursive=False)):
216
- text, cell_styles, cell_links = cell_text_styles_and_links(
217
- cell, first_column_bold=first_column_bold and cell_index == 0
218
- )
219
- row.append(text)
220
- style_row.append(cell_styles)
221
- link_row.append(cell_links)
222
- if row:
223
- rows.append(row)
224
- styles.append(style_row)
225
- links.append(link_row)
226
- return rows, styles, links
227
-
228
-
229
- def panel_has_only_heading_and_table(panel: Tag) -> bool:
230
- """Return true when a two-col panel can be safely replaced by a table image."""
231
-
232
- table = panel.find("table")
233
- if not isinstance(table, Tag):
234
- return False
235
-
236
- table_text = collapse_ws(table.get_text(" ", strip=True)).strip()
237
- for child in direct_tag_children(panel):
238
- if child.name in {"h2", "h3", "h4", "h5", "h6"}:
239
- continue
240
- if child is table:
241
- continue
242
- if child.find("table"):
243
- child_text = collapse_ws(child.get_text(" ", strip=True)).strip()
244
- if child_text == table_text:
245
- continue
246
- if collapse_ws(child.get_text(" ", strip=True)).strip():
247
- return False
248
- return True
249
-
250
-
251
- def two_col_can_render_as_table_grid(node: Tag) -> bool:
252
- panels = direct_tag_children(node)
253
- return bool(panels) and all(panel_has_only_heading_and_table(panel) for panel in panels)
254
-
255
-
256
- def add_two_col_layout(builder: Builder, node: Tag) -> None:
257
- panels: list[dict[str, Any]] = []
258
- for child in node.find_all(recursive=False):
259
- if not isinstance(child, Tag):
260
- continue
261
- table = child.find("table")
262
- if not isinstance(table, Tag):
263
- continue
264
- title_node = child.find(["h2", "h3", "h4", "h5", "h6"])
265
- title = collapse_ws(title_node.get_text(" ", strip=True) if title_node else "").strip()
266
- rows, styles, _links = table_from_html(table, first_column_bold=False)
267
- if rows:
268
- panels.append({"title": title, "rows": rows, "cell_styles": styles})
269
-
270
- if not panels:
271
- return
272
-
273
- builder.chart_counter += 1
274
- chart_id = f"CHART_IMAGE_{builder.chart_counter:02d}"
275
- placeholder = f"[[{chart_id}]]"
276
- start, end = builder.add(placeholder)
277
- builder.add("\n\n")
278
- image_file = f"chart_images/{chart_id.lower()}.png"
279
- builder.chart_images.append(
280
- {
281
- "id": chart_id,
282
- "kind": "two_col_table_grid",
283
- "panels": panels,
284
- "placeholder": placeholder,
285
- "placeholder_start": start,
286
- "placeholder_end": end,
287
- "image_file": image_file,
288
- "docs_width_pt": DOC_CONTENT_WIDTH_PT,
289
- }
290
- )
291
- builder.placeholders.append(
292
- {
293
- "id": chart_id,
294
- "kind": "chart_image",
295
- "text_to_find": placeholder,
296
- "start": start,
297
- "end": end,
298
- }
299
- )
300
-
301
-
302
- def add_table_placeholder(
303
- builder: Builder,
304
- kind: str,
305
- rows: list[list[str]],
306
- styles: list[list[list[str]]] | None = None,
307
- links: list[list[list[dict[str, Any]]]] | None = None,
308
- bar_color: str | None = None,
309
- ) -> None:
310
- if not rows:
311
- return
312
- builder.table_counter += 1
313
- table_id = f"{kind.upper()}_{builder.table_counter:02d}"
314
- placeholder = f"[[{table_id}]]"
315
- start, end = builder.add(placeholder)
316
- builder.add("\n\n")
317
- table = {
318
- "id": table_id,
319
- "kind": kind,
320
- "rows": rows,
321
- "cell_styles": styles or [[[] for _ in row] for row in rows],
322
- "cell_links": links or [[[] for _ in row] for row in rows],
323
- "placeholder": placeholder,
324
- "placeholder_start": start,
325
- "placeholder_end": end,
326
- }
327
- if bar_color:
328
- table["bar_color"] = bar_color
329
- builder.tables.append(table)
330
- builder.placeholders.append(
331
- {
332
- "id": table_id,
333
- "kind": kind,
334
- "text_to_find": placeholder,
335
- "start": start,
336
- "end": end,
337
- }
338
- )
339
-
340
-
341
- def first_text_for_selectors(node: Tag, selectors: list[str]) -> str:
342
- for selector in selectors:
343
- found = node.select_one(selector)
344
- if isinstance(found, Tag):
345
- text = collapse_ws(found.get_text(" ", strip=True)).strip()
346
- if text:
347
- return text
348
- return ""
349
-
350
-
351
- def metric_nodes(node: Tag) -> list[Tag]:
352
- direct_metrics = direct_children_with_class(node, "metric")
353
- if direct_metrics:
354
- return direct_metrics
355
- return [metric for metric in node.select(".metric") if isinstance(metric, Tag)]
356
-
357
-
358
- def add_metric_row(builder: Builder, node: Tag) -> None:
359
- row: list[str] = []
360
- style_row: list[list[str]] = []
361
- for metric in metric_nodes(node):
362
- value = first_text_for_selectors(metric, [".value", ".metric-value", ".k", "strong", "b"])
363
- label = first_text_for_selectors(metric, [".label", ".metric-label", ".l", "span"])
364
- note = first_text_for_selectors(metric, [".note", ".metric-note", ".sub"])
365
- pieces = [piece for piece in (value, label, note) if piece]
366
- if not pieces:
367
- pieces = [collapse_ws(metric.get_text(" ", strip=True)).strip()]
368
- row.append("\n".join(piece for piece in pieces if piece))
369
- style_row.append(["metric"])
370
- if not row:
371
- return
372
- add_table_placeholder(builder, "metric_cards", [row], [style_row])
373
-
374
-
375
- def add_pill_row(builder: Builder, node: Tag) -> None:
376
- labels = [collapse_ws(pill.get_text(" ", strip=True)).strip() for pill in node.select(".pill")]
377
- labels = [label for label in labels if label]
378
- if not labels:
379
- return
380
- start, end = builder.add(" | ".join(labels))
381
- builder.add("\n")
382
- builder.blocks.append({"start": start, "end": end + 1, "type": "muted"})
383
-
384
-
385
- def add_muted_text(builder: Builder, text: str) -> None:
386
- text = collapse_ws(text).strip()
387
- if not text:
388
- return
389
- start, end = builder.add(text)
390
- builder.add("\n")
391
- builder.blocks.append({"start": start, "end": end + 1, "type": "muted"})
392
-
393
-
394
- def add_embedded_image(builder: Builder, img: Tag, caption: str = "") -> bool:
395
- src = str(img.get("src") or "").strip()
396
- if not src:
397
- return False
398
-
399
- builder.chart_counter += 1
400
- chart_id = f"CHART_IMAGE_{builder.chart_counter:02d}"
401
- placeholder = f"[[{chart_id}]]"
402
- start, end = builder.add(placeholder)
403
- builder.add("\n\n")
404
- image_file = f"chart_images/{chart_id.lower()}.png"
405
- builder.chart_images.append(
406
- {
407
- "id": chart_id,
408
- "kind": "embedded_image",
409
- "src": src,
410
- "alt": collapse_ws(str(img.get("alt") or "")).strip(),
411
- "caption": caption,
412
- "placeholder": placeholder,
413
- "placeholder_start": start,
414
- "placeholder_end": end,
415
- "image_file": image_file,
416
- "docs_width_pt": DOC_CONTENT_WIDTH_PT,
417
- }
418
- )
419
- builder.placeholders.append(
420
- {
421
- "id": chart_id,
422
- "kind": "chart_image",
423
- "text_to_find": placeholder,
424
- "start": start,
425
- "end": end,
426
- }
427
- )
428
- return True
429
-
430
-
431
- def figure_caption_text(node: Tag) -> str:
432
- parts: list[str] = []
433
- for selector in ["figcaption", ".caption", ".spark-axis"]:
434
- for caption_node in node.select(selector):
435
- if isinstance(caption_node, Tag):
436
- text = collapse_ws(caption_node.get_text(" ", strip=True)).strip()
437
- if text and text not in parts:
438
- parts.append(text)
439
- return " ".join(parts)
440
-
441
-
442
- def add_figure(builder: Builder, node: Tag) -> bool:
443
- img = node.find("img")
444
- if isinstance(img, Tag):
445
- caption = figure_caption_text(node)
446
- added = add_embedded_image(builder, img, caption=caption)
447
- if added and caption:
448
- add_muted_text(builder, caption)
449
- return added
450
-
451
- svg = node.find("svg")
452
- if isinstance(svg, Tag):
453
- add_svg_chart(builder, svg)
454
- caption = figure_caption_text(node)
455
- if caption:
456
- add_muted_text(builder, caption)
457
- return True
458
-
459
- return False
460
-
461
-
462
- def css_bar_widths(stylesheet_text: str) -> dict[str, float]:
463
- widths: dict[str, float] = {}
464
- for selectors, body in CSS_RULE_RE.findall(stylesheet_text):
465
- match = re.search(r"width\s*:\s*([0-9.]+)%", body)
466
- if not match:
467
- continue
468
- pct = float(match.group(1))
469
- for selector in selectors.split(","):
470
- class_names = re.findall(r"\.([A-Za-z0-9_-]+)", selector)
471
- if not class_names or not ({"bar", "fill", "bar-fill"} & set(class_names)):
472
- continue
473
- for class_name in class_names:
474
- if class_name not in {"bar", "fill", "bar-fill"}:
475
- widths[class_name] = pct
476
- return widths
477
-
478
-
479
- def bar_width_pct(fill: Tag | None, width_by_class: dict[str, float]) -> float:
480
- if not isinstance(fill, Tag):
481
- return 100.0
482
- match = re.search(r"width\s*:\s*([0-9.]+)", str(fill.get("style", "")))
483
- if match:
484
- return float(match.group(1))
485
- for class_name in classes(fill):
486
- if class_name in width_by_class:
487
- return width_by_class[class_name]
488
- return 100.0
489
-
490
-
491
- def add_bar_chart(builder: Builder, node: Tag, width_by_class: dict[str, float]) -> None:
492
- chart_rows: list[dict[str, Any]] = []
493
- bar_color = "blue" if node.select_one(".fill.blue, .bar-fill.blue, .bar.blue") else "accent"
494
- for line in node.select(".bar-line, .bar-row"):
495
- spans = line.find_all("span")
496
- label_node = line.select_one(".bar-label, .label")
497
- value_node = line.select_one(".bar-value, .value")
498
- bar_head = line.select_one(".bar-head")
499
- if isinstance(bar_head, Tag):
500
- label_node = label_node or bar_head.find("span")
501
- value_node = value_node or bar_head.find("strong") or bar_head.find("b")
502
- direct_parts = [
503
- child
504
- for child in direct_tag_children(line)
505
- if "bar-track" not in classes(child)
506
- and not (classes(child) & {"bar", "fill", "bar-fill"})
507
- and collapse_ws(child.get_text(" ", strip=True)).strip()
508
- ]
509
- if not isinstance(label_node, Tag) and spans:
510
- label_node = spans[0]
511
- if not isinstance(label_node, Tag) and direct_parts:
512
- label_node = direct_parts[0]
513
- if not isinstance(value_node, Tag) and len(spans) >= 2:
514
- value_node = spans[-1]
515
- if not isinstance(value_node, Tag) and len(direct_parts) >= 2:
516
- value_node = direct_parts[-1]
517
- if not isinstance(label_node, Tag) or not isinstance(value_node, Tag):
518
- continue
519
- label = collapse_ws(label_node.get_text(" ", strip=True))
520
- value = collapse_ws(value_node.get_text(" ", strip=True))
521
- fill = line.select_one(".fill, .bar-fill, .bar")
522
- pct = bar_width_pct(fill, width_by_class)
523
- chart_rows.append({"label": label, "value": value, "pct": pct})
524
- if not chart_rows:
525
- return
526
-
527
- if builder.chart_mode == "table":
528
- rows: list[list[str]] = []
529
- style_rows: list[list[list[str]]] = []
530
- for row in chart_rows:
531
- blocks = max(1, round(row["pct"] / 5))
532
- rows.append([row["label"], "█" * blocks, row["value"]])
533
- style_rows.append([[], ["bar"], []])
534
- add_table_placeholder(builder, "bar_chart", rows, style_rows, bar_color=bar_color)
535
- return
536
-
537
- builder.chart_counter += 1
538
- chart_id = f"CHART_IMAGE_{builder.chart_counter:02d}"
539
- placeholder = f"[[{chart_id}]]"
540
- start, end = builder.add(placeholder)
541
- builder.add("\n\n")
542
- image_file = f"chart_images/{chart_id.lower()}.png"
543
- builder.chart_images.append(
544
- {
545
- "id": chart_id,
546
- "kind": "bar_chart",
547
- "aria_label": node.get("aria-label", ""),
548
- "rows": chart_rows,
549
- "bar_color": bar_color,
550
- "placeholder": placeholder,
551
- "placeholder_start": start,
552
- "placeholder_end": end,
553
- "image_file": image_file,
554
- }
555
- )
556
- builder.placeholders.append(
557
- {
558
- "id": chart_id,
559
- "kind": "chart_image",
560
- "text_to_find": placeholder,
561
- "start": start,
562
- "end": end,
563
- }
564
- )
565
-
566
-
567
- def svg_dimensions(svg: Tag) -> tuple[int, int]:
568
- width = svg.get("width")
569
- height = svg.get("height")
570
- try:
571
- return int(float(str(width))), int(float(str(height)))
572
- except (TypeError, ValueError):
573
- pass
574
- view_box = svg.get("viewBox") or svg.get("viewbox")
575
- if view_box:
576
- parts = str(view_box).replace(",", " ").split()
577
- if len(parts) == 4:
578
- try:
579
- return int(float(parts[2])), int(float(parts[3]))
580
- except ValueError:
581
- pass
582
- return 1000, 600
583
-
584
-
585
- def inline_svg_report_styles(svg_markup: str) -> str:
586
- """Apply report chart CSS classes as explicit SVG attributes.
587
-
588
- Sanitized reports commonly keep chart colors in the page stylesheet while
589
- SVG elements only carry classes. Once the SVG is extracted into the Docs
590
- conversion plan, renderers that do not have the original stylesheet can
591
- silently lose bars or labels. Inlining the known report chart classes keeps
592
- the generated PNG visually faithful and renderer-independent.
593
- """
594
-
595
- soup = BeautifulSoup(svg_markup, "xml")
596
- svg = soup.find("svg") or soup
597
- for el in svg.find_all(True):
598
- merged: dict[str, str] = {}
599
- for class_name in classes(el):
600
- merged.update(SVG_REPORT_STYLE_DEFAULTS.get(class_name, {}))
601
- for attr, value in merged.items():
602
- if el.get(attr) is None:
603
- el[attr] = value
604
- return str(svg)
605
-
606
-
607
- def add_svg_chart(builder: Builder, node: Tag) -> None:
608
- svg = node if node.name == "svg" else node.find("svg")
609
- if not isinstance(svg, Tag):
610
- return
611
-
612
- builder.chart_counter += 1
613
- chart_id = f"CHART_IMAGE_{builder.chart_counter:02d}"
614
- placeholder = f"[[{chart_id}]]"
615
- start, end = builder.add(placeholder)
616
- builder.add("\n\n")
617
-
618
- width_px, height_px = svg_dimensions(svg)
619
- docs_height = round(DOC_CONTENT_WIDTH_PT * height_px / width_px, 1) if width_px else 240
620
- image_file = f"chart_images/{chart_id.lower()}.png"
621
- builder.chart_images.append(
622
- {
623
- "id": chart_id,
624
- "kind": "svg",
625
- "aria_label": svg.get("aria-label", node.get("aria-label", "")),
626
- "svg_markup": inline_svg_report_styles(str(svg)),
627
- "source_width_px": width_px,
628
- "source_height_px": height_px,
629
- "placeholder": placeholder,
630
- "placeholder_start": start,
631
- "placeholder_end": end,
632
- "image_file": image_file,
633
- "docs_width_pt": DOC_CONTENT_WIDTH_PT,
634
- "docs_height_pt": docs_height,
635
- }
636
- )
637
- builder.placeholders.append(
638
- {
639
- "id": chart_id,
640
- "kind": "chart_image",
641
- "text_to_find": placeholder,
642
- "start": start,
643
- "end": end,
644
- }
645
- )
646
-
647
-
648
- def parse_html(path: Path, chart_mode: str = "image") -> dict[str, Any]:
649
- require_bs4()
650
- raw_html = path.read_text(encoding="utf-8")
651
- soup = BeautifulSoup(raw_html, "html.parser")
652
- root = soup.find("main") or soup.body or soup
653
- builder = Builder(chart_mode=chart_mode)
654
- stylesheet_text = "\n".join(style.get_text("\n") for style in soup.find_all("style"))
655
- first_column_bold = table_first_column_is_bold(stylesheet_text)
656
- bar_width_by_class = css_bar_widths(stylesheet_text)
657
-
658
- blockish_tags = {"h1", "h2", "h3", "h4", "p", "table", "ul", "ol", "figure", "img", "svg"}
659
- blockish_classes = {
660
- "bar-chart",
661
- "charts",
662
- "callout",
663
- "chart",
664
- "figure",
665
- "implication",
666
- "bars",
667
- "metric-grid",
668
- "metrics",
669
- "pillrow",
670
- "summary",
671
- "spark",
672
- "two-col",
673
- }
674
-
675
- def has_blockish_child(node: Tag) -> bool:
676
- for child in direct_tag_children(node):
677
- if child.name in blockish_tags or classes(child) & blockish_classes:
678
- return True
679
- if node.find(list(blockish_tags)):
680
- return True
681
- return any(node.find(class_=class_name) for class_name in blockish_classes)
682
-
683
- def process_children(node: Tag) -> None:
684
- for child in node.children:
685
- if isinstance(child, Tag):
686
- process_node(child)
687
-
688
- def add_summary_callout(builder: Builder, node: Tag) -> None:
689
- start = builder.offset
690
- append_inline(builder, node)
691
- end = builder.offset
692
- if end > start:
693
- builder.add("\n")
694
- builder.blocks.append({"start": start, "end": end + 1, "type": "summary_callout"})
695
-
696
- def process_node(node: Tag) -> None:
697
- node_classes = classes(node)
698
- if "two-col" in node_classes:
699
- if two_col_can_render_as_table_grid(node):
700
- add_two_col_layout(builder, node)
701
- else:
702
- builder.two_col_text_blocks += 1
703
- process_children(node)
704
- return
705
- if node.name in {"h1", "h2", "h3", "h4"}:
706
- add_heading(builder, node)
707
- return
708
- if node.name == "figure" or "figure" in node_classes:
709
- if add_figure(builder, node):
710
- return
711
- process_children(node)
712
- return
713
- if node.name == "img":
714
- add_embedded_image(builder, node)
715
- return
716
- if node.name == "p":
717
- if "note" in node_classes:
718
- block_type = "note"
719
- elif "source" in node_classes or "source-list" in node_classes:
720
- block_type = "source_list"
721
- elif "sub" in node_classes:
722
- block_type = "muted"
723
- else:
724
- block_type = None
725
- add_paragraph(builder, node, block_type)
726
- return
727
- if (
728
- "metric-grid" in node_classes
729
- or "metrics" in node_classes
730
- or direct_children_with_class(node, "metric")
731
- ):
732
- add_metric_row(builder, node)
733
- return
734
- if node.name == "table":
735
- rows, styles, links = table_from_html(node, first_column_bold=first_column_bold)
736
- add_table_placeholder(builder, "table", rows, styles, links)
737
- return
738
- if node.name in {"ul", "ol"}:
739
- start = builder.offset
740
- for li in node.find_all("li", recursive=False):
741
- li_start = builder.offset
742
- append_inline(builder, li)
743
- if builder.offset > li_start:
744
- builder.add("\n")
745
- end = builder.offset
746
- builder.add("\n")
747
- if end > start:
748
- builder.lists.append({"start": start, "end": end, "ordered": node.name == "ol"})
749
- return
750
- child_tags = direct_tag_children(node)
751
- if "pillrow" in node_classes or (
752
- child_tags and all("pill" in classes(child) for child in child_tags)
753
- ):
754
- add_pill_row(builder, node)
755
- return
756
- if "callout" in node_classes or "implication" in node_classes:
757
- add_summary_callout(builder, node)
758
- return
759
- if "bar-chart" in node_classes or "bars" in node_classes:
760
- add_bar_chart(builder, node, bar_width_by_class)
761
- return
762
- if "chart" in node_classes and node.find("svg"):
763
- add_svg_chart(builder, node)
764
- return
765
- if node.name == "svg":
766
- add_svg_chart(builder, node)
767
- return
768
-
769
- if not has_blockish_child(node) and collapse_ws(node.get_text(" ", strip=True)).strip():
770
- add_paragraph(builder, node)
771
- return
772
- process_children(node)
773
-
774
- for child in root.children:
775
- if isinstance(child, Tag):
776
- process_node(child)
777
-
778
- title = (soup.title.get_text(" ", strip=True) if soup.title else "").strip()
779
- h1 = root.find("h1")
780
- if h1:
781
- title = collapse_ws(h1.get_text(" ", strip=True)).strip() or title
782
- two_col_blocks = root.select(".two-col")
783
- bar_blocks = [block for block in root.select(".bar-chart, .bars") if block.name != "svg"]
784
-
785
- return {
786
- "source_html": str(path),
787
- "title": title,
788
- "skeleton_text": builder.text().rstrip() + "\n",
789
- "headings": builder.headings,
790
- "inline_styles": builder.inline_styles,
791
- "blocks": builder.blocks,
792
- "lists": builder.lists,
793
- "placeholders": builder.placeholders,
794
- "tables": builder.tables,
795
- "chart_images": builder.chart_images,
796
- "counts": {
797
- "headings": len(builder.headings),
798
- "inline_styles": len(builder.inline_styles),
799
- "blocks": len(builder.blocks),
800
- "lists": len(builder.lists),
801
- "tables": len(builder.tables),
802
- "chart_images": len(builder.chart_images),
803
- "two_col_source_blocks": len(two_col_blocks),
804
- "two_col_image_blocks": sum(
805
- 1 for chart in builder.chart_images if chart.get("kind") == "two_col_table_grid"
806
- ),
807
- "two_col_text_blocks": builder.two_col_text_blocks,
808
- "embedded_image_blocks": sum(
809
- 1 for chart in builder.chart_images if chart.get("kind") == "embedded_image"
810
- ),
811
- "svg_image_blocks": sum(
812
- 1 for chart in builder.chart_images if chart.get("kind") == "svg"
813
- ),
814
- "bar_source_blocks": len(bar_blocks),
815
- "bar_image_blocks": sum(
816
- 1 for chart in builder.chart_images if chart.get("kind") == "bar_chart"
817
- ),
818
- "bar_table_blocks": sum(
819
- 1 for table in builder.tables if table.get("kind") == "bar_chart"
820
- ),
821
- "images": len(root.find_all("img")),
822
- "svgs": len(root.find_all("svg")),
823
- "canvas": len(root.find_all("canvas")),
824
- },
825
- "source_flags": {
826
- "auth_page_detected": "login.microsoftonline.com" in raw_html
827
- or title.strip().lower() == "sign in to your account"
828
- },
829
- }