hyperweave 0.2.7__tar.gz → 0.2.8__tar.gz

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 (360) hide show
  1. {hyperweave-0.2.7 → hyperweave-0.2.8}/CHANGELOG.md +19 -0
  2. {hyperweave-0.2.7 → hyperweave-0.2.8}/PKG-INFO +1 -1
  3. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/_version.py +2 -2
  4. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/compose/context.py +9 -5
  5. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/connectors/base.py +63 -0
  6. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/connectors/github.py +178 -24
  7. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/render/chart_engine.py +112 -98
  8. hyperweave-0.2.8/src/hyperweave/templates/components/chart-area.svg.j2 +11 -0
  9. hyperweave-0.2.8/src/hyperweave/templates/components/chart-axes.svg.j2 +2 -0
  10. hyperweave-0.2.8/src/hyperweave/templates/components/chart-empty-state.svg.j2 +8 -0
  11. hyperweave-0.2.8/src/hyperweave/templates/components/chart-gridlines.svg.j2 +2 -0
  12. hyperweave-0.2.8/src/hyperweave/templates/components/chart-milestone.svg.j2 +7 -0
  13. hyperweave-0.2.8/src/hyperweave/templates/components/chart-polyline.svg.j2 +10 -0
  14. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/frames/chart/brutalist-content.j2 +22 -8
  15. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/frames/chart/chrome-content.j2 +21 -7
  16. {hyperweave-0.2.7 → hyperweave-0.2.8}/tests/test_chart_engine.py +74 -22
  17. {hyperweave-0.2.7 → hyperweave-0.2.8}/tests/test_connectors.py +381 -0
  18. {hyperweave-0.2.7 → hyperweave-0.2.8}/.dockerignore +0 -0
  19. {hyperweave-0.2.7 → hyperweave-0.2.8}/.github/workflows/ci.yml +0 -0
  20. {hyperweave-0.2.7 → hyperweave-0.2.8}/.github/workflows/deploy.yml +0 -0
  21. {hyperweave-0.2.7 → hyperweave-0.2.8}/.github/workflows/publish.yml +0 -0
  22. {hyperweave-0.2.7 → hyperweave-0.2.8}/.gitignore +0 -0
  23. {hyperweave-0.2.7 → hyperweave-0.2.8}/.pre-commit-config.yaml +0 -0
  24. {hyperweave-0.2.7 → hyperweave-0.2.8}/Dockerfile +0 -0
  25. {hyperweave-0.2.7 → hyperweave-0.2.8}/LICENSE +0 -0
  26. {hyperweave-0.2.7 → hyperweave-0.2.8}/README.md +0 -0
  27. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/buttons/button-liquid.svg +0 -0
  28. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/cards/card-butterfly.svg +0 -0
  29. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/cards/card-python.svg +0 -0
  30. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/cards/card-sunflower.svg +0 -0
  31. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/cards/card-waves.svg +0 -0
  32. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/examples/brutalist-emerald/badge_critical.svg +0 -0
  33. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/examples/brutalist-emerald/badge_passing.svg +0 -0
  34. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/examples/brutalist-emerald/badge_warning.svg +0 -0
  35. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/examples/brutalist-emerald/banner.svg +0 -0
  36. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/examples/brutalist-emerald/icons/discord.svg +0 -0
  37. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/examples/brutalist-emerald/icons/notion.svg +0 -0
  38. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/examples/brutalist-emerald/icons/reddit.svg +0 -0
  39. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/examples/brutalist-emerald/icons/spotify.svg +0 -0
  40. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/examples/brutalist-emerald/icons/youtube.svg +0 -0
  41. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/examples/brutalist-emerald/marquee_counter.svg +0 -0
  42. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/examples/brutalist-emerald/marquee_horizontal.svg +0 -0
  43. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/examples/brutalist-emerald/marquee_vertical.svg +0 -0
  44. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/examples/brutalist-emerald/profile-cards/chart_stars_full.svg +0 -0
  45. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/examples/brutalist-emerald/profile-cards/stats.svg +0 -0
  46. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/examples/brutalist-emerald/strip.svg +0 -0
  47. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/examples/chrome-horizon/badge_critical.svg +0 -0
  48. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/examples/chrome-horizon/badge_passing.svg +0 -0
  49. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/examples/chrome-horizon/badge_warning.svg +0 -0
  50. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/examples/chrome-horizon/banner.svg +0 -0
  51. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/examples/chrome-horizon/icons/bluesky.svg +0 -0
  52. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/examples/chrome-horizon/icons/github.svg +0 -0
  53. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/examples/chrome-horizon/icons/instagram.svg +0 -0
  54. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/examples/chrome-horizon/icons/mastodon.svg +0 -0
  55. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/examples/chrome-horizon/icons/x.svg +0 -0
  56. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/examples/chrome-horizon/marquee_counter.svg +0 -0
  57. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/examples/chrome-horizon/marquee_horizontal.svg +0 -0
  58. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/examples/chrome-horizon/marquee_vertical.svg +0 -0
  59. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/examples/chrome-horizon/profile-cards/chart_stars_full.svg +0 -0
  60. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/examples/chrome-horizon/profile-cards/stats.svg +0 -0
  61. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/examples/chrome-horizon/strip.svg +0 -0
  62. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/examples/telemetry/master_card.svg +0 -0
  63. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/examples/telemetry/receipt.svg +0 -0
  64. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/examples/telemetry/rhythm_strip.svg +0 -0
  65. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/footers/inneraura-footer-liquid.svg +0 -0
  66. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/footers/inneraura-footer-purple.svg +0 -0
  67. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/footers/inneraura-footer.svg +0 -0
  68. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/hyperweave-banner.svg +0 -0
  69. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/icons/cobalt-sapphire-discord.svg +0 -0
  70. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/icons/cobalt-sapphire-docs.svg +0 -0
  71. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/icons/cobalt-sapphire-github.svg +0 -0
  72. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/icons/cobalt-sapphire-instagram.svg +0 -0
  73. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/icons/cobalt-sapphire-linkedin.svg +0 -0
  74. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/icons/cobalt-sapphire-tiktok.svg +0 -0
  75. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/icons/cobalt-sapphire-x.svg +0 -0
  76. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/icons/cobalt-sapphire-youtube.svg +0 -0
  77. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/marquees/badge-showcase-triple.svg +0 -0
  78. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/marquees/genome-marquee-triple.svg +0 -0
  79. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/marquees/sample-badges.svg +0 -0
  80. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/mintlify-assets/404.svg +0 -0
  81. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/mintlify-assets/callout-icons.svg +0 -0
  82. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/mintlify-assets/divider.svg +0 -0
  83. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/mintlify-assets/favicon.svg +0 -0
  84. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/mintlify-assets/hero-banner.svg +0 -0
  85. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/mintlify-assets/hyperweave-banner-v2.svg +0 -0
  86. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/mintlify-assets/hyperweave-navbar-logo.svg +0 -0
  87. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/mintlify-assets/loader.svg +0 -0
  88. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/mintlify-assets/og-image.svg +0 -0
  89. {hyperweave-0.2.7 → hyperweave-0.2.8}/assets/timelines/hyperweave-roadmap.svg +0 -0
  90. {hyperweave-0.2.7 → hyperweave-0.2.8}/docs/assets/favicon.svg +0 -0
  91. {hyperweave-0.2.7 → hyperweave-0.2.8}/docs/assets/hyperweave-banner.svg +0 -0
  92. {hyperweave-0.2.7 → hyperweave-0.2.8}/docs/assets/hyperweave-navbar-logo.svg +0 -0
  93. {hyperweave-0.2.7 → hyperweave-0.2.8}/docs/assets/og-image.svg +0 -0
  94. {hyperweave-0.2.7 → hyperweave-0.2.8}/docs/explanation/architecture.mdx +0 -0
  95. {hyperweave-0.2.7 → hyperweave-0.2.8}/docs/explanation/camo-compatibility.mdx +0 -0
  96. {hyperweave-0.2.7 → hyperweave-0.2.8}/docs/explanation/cim-compliance.mdx +0 -0
  97. {hyperweave-0.2.7 → hyperweave-0.2.8}/docs/explanation/genome-profile-system.mdx +0 -0
  98. {hyperweave-0.2.7 → hyperweave-0.2.8}/docs/explanation/metadata-tiers.mdx +0 -0
  99. {hyperweave-0.2.7 → hyperweave-0.2.8}/docs/how-to/add-motion-to-badges.mdx +0 -0
  100. {hyperweave-0.2.7 → hyperweave-0.2.8}/docs/how-to/create-session-receipts.mdx +0 -0
  101. {hyperweave-0.2.7 → hyperweave-0.2.8}/docs/how-to/set-up-claude-code-hooks.mdx +0 -0
  102. {hyperweave-0.2.7 → hyperweave-0.2.8}/docs/how-to/use-live-data-badges.mdx +0 -0
  103. {hyperweave-0.2.7 → hyperweave-0.2.8}/docs/introduction.mdx +0 -0
  104. {hyperweave-0.2.7 → hyperweave-0.2.8}/docs/mint.json +0 -0
  105. {hyperweave-0.2.7 → hyperweave-0.2.8}/docs/quickstart.mdx +0 -0
  106. {hyperweave-0.2.7 → hyperweave-0.2.8}/docs/reference/cli.mdx +0 -0
  107. {hyperweave-0.2.7 → hyperweave-0.2.8}/docs/reference/compose-spec.mdx +0 -0
  108. {hyperweave-0.2.7 → hyperweave-0.2.8}/docs/reference/genomes.mdx +0 -0
  109. {hyperweave-0.2.7 → hyperweave-0.2.8}/docs/reference/http-api.mdx +0 -0
  110. {hyperweave-0.2.7 → hyperweave-0.2.8}/docs/reference/mcp-tools.mdx +0 -0
  111. {hyperweave-0.2.7 → hyperweave-0.2.8}/docs/reference/motions.mdx +0 -0
  112. {hyperweave-0.2.7 → hyperweave-0.2.8}/docs/reference/telemetry-contract.mdx +0 -0
  113. {hyperweave-0.2.7 → hyperweave-0.2.8}/docs/spec/hyperweave-protocol.mdx +0 -0
  114. {hyperweave-0.2.7 → hyperweave-0.2.8}/docs/tutorials/build-an-artifact-kit.mdx +0 -0
  115. {hyperweave-0.2.7 → hyperweave-0.2.8}/docs/tutorials/compose-your-first-badge.mdx +0 -0
  116. {hyperweave-0.2.7 → hyperweave-0.2.8}/docs/tutorials/install-session-telemetry.mdx +0 -0
  117. {hyperweave-0.2.7 → hyperweave-0.2.8}/fly.toml +0 -0
  118. {hyperweave-0.2.7 → hyperweave-0.2.8}/hooks/install.py +0 -0
  119. {hyperweave-0.2.7 → hyperweave-0.2.8}/hooks/session_end.sh +0 -0
  120. {hyperweave-0.2.7 → hyperweave-0.2.8}/justfile +0 -0
  121. {hyperweave-0.2.7 → hyperweave-0.2.8}/pyproject.toml +0 -0
  122. {hyperweave-0.2.7 → hyperweave-0.2.8}/scripts/extract_font_metrics.py +0 -0
  123. {hyperweave-0.2.7 → hyperweave-0.2.8}/scripts/extract_glyphs.py +0 -0
  124. {hyperweave-0.2.7 → hyperweave-0.2.8}/scripts/generate_hw_compliant.py +0 -0
  125. {hyperweave-0.2.7 → hyperweave-0.2.8}/scripts/generate_proofset.py +0 -0
  126. {hyperweave-0.2.7 → hyperweave-0.2.8}/scripts/stress_test.py +0 -0
  127. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/__init__.py +0 -0
  128. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/__main__.py +0 -0
  129. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/cli.py +0 -0
  130. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/compose/__init__.py +0 -0
  131. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/compose/assembler.py +0 -0
  132. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/compose/engine.py +0 -0
  133. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/compose/lanes.py +0 -0
  134. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/compose/resolver.py +0 -0
  135. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/compose/resolvers/__init__.py +0 -0
  136. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/compose/resolvers/chart.py +0 -0
  137. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/compose/resolvers/stats.py +0 -0
  138. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/compose/resolvers/timeline.py +0 -0
  139. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/compose/rhythm.py +0 -0
  140. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/compose/validate_paradigms.py +0 -0
  141. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/config/__init__.py +0 -0
  142. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/config/genome_validator.py +0 -0
  143. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/config/loader.py +0 -0
  144. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/config/registry.py +0 -0
  145. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/config/settings.py +0 -0
  146. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/connectors/__init__.py +0 -0
  147. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/connectors/arxiv.py +0 -0
  148. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/connectors/cache.py +0 -0
  149. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/connectors/rest.py +0 -0
  150. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/core/__init__.py +0 -0
  151. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/core/color.py +0 -0
  152. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/core/contracts.py +0 -0
  153. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/core/enums.py +0 -0
  154. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/core/font_metrics.py +0 -0
  155. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/core/models.py +0 -0
  156. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/core/paradigm.py +0 -0
  157. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/core/schema.py +0 -0
  158. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/core/state.py +0 -0
  159. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/core/text.py +0 -0
  160. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/core/thresholds.py +0 -0
  161. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/css/accessibility.css +0 -0
  162. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/css/bridge.css +0 -0
  163. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/css/expression.css +0 -0
  164. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/css/phase-colors.css +0 -0
  165. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/css/status.css +0 -0
  166. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/css/telemetry.css +0 -0
  167. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/font-metrics/inter.json +0 -0
  168. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/font-metrics/jetbrains-mono.json +0 -0
  169. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/font-metrics/orbitron.json +0 -0
  170. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/fonts/jetbrains-mono.b64 +0 -0
  171. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/fonts/jetbrains-mono.meta.json +0 -0
  172. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/fonts/orbitron.b64 +0 -0
  173. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/fonts/orbitron.meta.json +0 -0
  174. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/genomes/brutalist-emerald.json +0 -0
  175. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/genomes/chrome-horizon.json +0 -0
  176. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/genomes/telemetry-void.json +0 -0
  177. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/glyphs.json +0 -0
  178. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/motions/border/chromatic-pulse.yaml +0 -0
  179. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/motions/border/corner-trace.yaml +0 -0
  180. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/motions/border/dual-orbit.yaml +0 -0
  181. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/motions/border/entanglement.yaml +0 -0
  182. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/motions/border/rimrun.yaml +0 -0
  183. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/motions/kinetic/bars.yaml +0 -0
  184. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/motions/kinetic/breach.yaml +0 -0
  185. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/motions/kinetic/broadcast.yaml +0 -0
  186. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/motions/kinetic/cascade.yaml +0 -0
  187. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/motions/kinetic/collapse.yaml +0 -0
  188. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/motions/kinetic/converge.yaml +0 -0
  189. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/motions/kinetic/crash.yaml +0 -0
  190. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/motions/kinetic/drop.yaml +0 -0
  191. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/motions/kinetic/pulse.yaml +0 -0
  192. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/motions/static.yaml +0 -0
  193. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/paradigms/brutalist.yaml +0 -0
  194. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/paradigms/chrome.yaml +0 -0
  195. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/paradigms/default.yaml +0 -0
  196. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/policies/normal.json +0 -0
  197. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/policies/permissive.json +0 -0
  198. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/policies/ungoverned.json +0 -0
  199. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/profiles/brutalist.contract.json +0 -0
  200. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/profiles/brutalist.yaml +0 -0
  201. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/profiles/chrome.contract.json +0 -0
  202. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/profiles/chrome.yaml +0 -0
  203. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/specimens.yaml +0 -0
  204. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/telemetry/model-pricing.yaml +0 -0
  205. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/telemetry/stage-config.yaml +0 -0
  206. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/telemetry/stage-labels.yaml +0 -0
  207. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/telemetry/tool-classes.yaml +0 -0
  208. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/telemetry/tool-colors.yaml +0 -0
  209. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/terminals/arrow.json +0 -0
  210. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/terminals/aurora.json +0 -0
  211. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/terminals/beacon.json +0 -0
  212. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/terminals/bracket3d.json +0 -0
  213. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/terminals/chevron.json +0 -0
  214. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/terminals/crosshair.json +0 -0
  215. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/terminals/diamond.json +0 -0
  216. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/terminals/rocket.json +0 -0
  217. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/terminals/rules/bar.json +0 -0
  218. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/terminals/rules/dashed.json +0 -0
  219. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/terminals/rules/five-wave.json +0 -0
  220. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/terminals/rules/spectral.json +0 -0
  221. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/terminals/rules/straight.json +0 -0
  222. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/terminals/rules/wave.json +0 -0
  223. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/data/terminals/stijl.json +0 -0
  224. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/kit.py +0 -0
  225. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/mcp/__init__.py +0 -0
  226. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/mcp/__main__.py +0 -0
  227. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/mcp/server.py +0 -0
  228. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/py.typed +0 -0
  229. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/render/__init__.py +0 -0
  230. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/render/fonts.py +0 -0
  231. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/render/glyphs.py +0 -0
  232. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/render/motion.py +0 -0
  233. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/render/templates.py +0 -0
  234. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/serve/__init__.py +0 -0
  235. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/serve/app.py +0 -0
  236. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/telemetry/__init__.py +0 -0
  237. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/telemetry/capture.py +0 -0
  238. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/telemetry/contract.py +0 -0
  239. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/telemetry/corrections.py +0 -0
  240. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/telemetry/cost.py +0 -0
  241. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/telemetry/models.py +0 -0
  242. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/telemetry/parser.py +0 -0
  243. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/telemetry/stages.py +0 -0
  244. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/components/chart-markers/circle.svg.j2 +0 -0
  245. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/components/chart-markers/diamond.svg.j2 +0 -0
  246. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/components/chart-markers/endpoint-diamond.svg.j2 +0 -0
  247. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/components/chart-markers/endpoint-rect.svg.j2 +0 -0
  248. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/components/chart-markers/rect.svg.j2 +0 -0
  249. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/components/filter.svg.j2 +0 -0
  250. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/components/glyph-inline.svg.j2 +0 -0
  251. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/components/glyph.svg.j2 +0 -0
  252. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/components/gradient.svg.j2 +0 -0
  253. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/components/metadata.svg.j2 +0 -0
  254. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/components/metric.svg.j2 +0 -0
  255. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/components/phase-segment.svg.j2 +0 -0
  256. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/components/rule.svg.j2 +0 -0
  257. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/components/status.svg.j2 +0 -0
  258. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/components/terminal.svg.j2 +0 -0
  259. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/components/treemap.svg.j2 +0 -0
  260. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/document.svg.j2 +0 -0
  261. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/error-badge.svg.j2 +0 -0
  262. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/frames/badge/brutalist-content.j2 +0 -0
  263. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/frames/badge/brutalist-defs.j2 +0 -0
  264. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/frames/badge/chrome-content.j2 +0 -0
  265. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/frames/badge/chrome-defs.j2 +0 -0
  266. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/frames/badge/default-content.j2 +0 -0
  267. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/frames/badge/default-defs.j2 +0 -0
  268. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/frames/badge.svg.j2 +0 -0
  269. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/frames/banner/brutalist-defs.j2 +0 -0
  270. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/frames/banner/chrome-content.j2 +0 -0
  271. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/frames/banner/chrome-defs.j2 +0 -0
  272. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/frames/banner/default-content.j2 +0 -0
  273. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/frames/banner/default-defs.j2 +0 -0
  274. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/frames/banner.svg.j2 +0 -0
  275. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/frames/catalog.svg.j2 +0 -0
  276. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/frames/chart/brutalist-defs.j2 +0 -0
  277. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/frames/chart/chrome-defs.j2 +0 -0
  278. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/frames/chart.svg.j2 +0 -0
  279. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/frames/divider.svg.j2 +0 -0
  280. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/frames/icon/brutalist-content.j2 +0 -0
  281. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/frames/icon/brutalist-defs.j2 +0 -0
  282. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/frames/icon/chrome-content.j2 +0 -0
  283. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/frames/icon/chrome-defs.j2 +0 -0
  284. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/frames/icon/default-content.j2 +0 -0
  285. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/frames/icon/default-defs.j2 +0 -0
  286. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/frames/icon.svg.j2 +0 -0
  287. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/frames/marquee-counter/brutalist-content.j2 +0 -0
  288. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/frames/marquee-counter/brutalist-defs.j2 +0 -0
  289. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/frames/marquee-counter/chrome-content.j2 +0 -0
  290. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/frames/marquee-counter/chrome-defs.j2 +0 -0
  291. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/frames/marquee-counter.svg.j2 +0 -0
  292. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/frames/marquee-horizontal/brutalist-content.j2 +0 -0
  293. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/frames/marquee-horizontal/brutalist-defs.j2 +0 -0
  294. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/frames/marquee-horizontal/chrome-content.j2 +0 -0
  295. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/frames/marquee-horizontal/chrome-defs.j2 +0 -0
  296. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/frames/marquee-horizontal.svg.j2 +0 -0
  297. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/frames/marquee-vertical/brutalist-content.j2 +0 -0
  298. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/frames/marquee-vertical/brutalist-defs.j2 +0 -0
  299. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/frames/marquee-vertical/chrome-content.j2 +0 -0
  300. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/frames/marquee-vertical/chrome-defs.j2 +0 -0
  301. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/frames/marquee-vertical.svg.j2 +0 -0
  302. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/frames/master-card.svg.j2 +0 -0
  303. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/frames/receipt.svg.j2 +0 -0
  304. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/frames/rhythm-strip.svg.j2 +0 -0
  305. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/frames/stats/brutalist-content.j2 +0 -0
  306. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/frames/stats/brutalist-defs.j2 +0 -0
  307. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/frames/stats/chrome-content.j2 +0 -0
  308. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/frames/stats/chrome-defs.j2 +0 -0
  309. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/frames/stats.svg.j2 +0 -0
  310. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/frames/strip/brutalist-content.j2 +0 -0
  311. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/frames/strip/brutalist-defs.j2 +0 -0
  312. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/frames/strip/brutalist-status.j2 +0 -0
  313. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/frames/strip/chrome-content.j2 +0 -0
  314. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/frames/strip/chrome-defs.j2 +0 -0
  315. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/frames/strip/chrome-status.j2 +0 -0
  316. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/frames/strip/default-content.j2 +0 -0
  317. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/frames/strip/default-defs.j2 +0 -0
  318. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/frames/strip/default-status.j2 +0 -0
  319. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/frames/strip.svg.j2 +0 -0
  320. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/frames/timeline/default-content.j2 +0 -0
  321. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/frames/timeline.svg.j2 +0 -0
  322. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/motions/border/chromatic-pulse.svg.j2 +0 -0
  323. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/motions/border/corner-trace.svg.j2 +0 -0
  324. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/motions/border/dual-orbit.svg.j2 +0 -0
  325. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/motions/border/entanglement.svg.j2 +0 -0
  326. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/motions/border/rimrun.svg.j2 +0 -0
  327. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/motions/kinetic/bars.svg.j2 +0 -0
  328. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/motions/kinetic/breach.svg.j2 +0 -0
  329. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/motions/kinetic/broadcast.svg.j2 +0 -0
  330. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/motions/kinetic/cascade.svg.j2 +0 -0
  331. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/motions/kinetic/collapse.svg.j2 +0 -0
  332. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/motions/kinetic/converge.svg.j2 +0 -0
  333. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/motions/kinetic/crash.svg.j2 +0 -0
  334. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/motions/kinetic/drop.svg.j2 +0 -0
  335. {hyperweave-0.2.7 → hyperweave-0.2.8}/src/hyperweave/templates/motions/kinetic/pulse.svg.j2 +0 -0
  336. {hyperweave-0.2.7 → hyperweave-0.2.8}/tests/__init__.py +0 -0
  337. {hyperweave-0.2.7 → hyperweave-0.2.8}/tests/conftest.py +0 -0
  338. {hyperweave-0.2.7 → hyperweave-0.2.8}/tests/fixtures/github_contributions/synthetic.html +0 -0
  339. {hyperweave-0.2.7 → hyperweave-0.2.8}/tests/fixtures/session.json +0 -0
  340. {hyperweave-0.2.7 → hyperweave-0.2.8}/tests/fixtures/session.jsonl +0 -0
  341. {hyperweave-0.2.7 → hyperweave-0.2.8}/tests/helpers.py +0 -0
  342. {hyperweave-0.2.7 → hyperweave-0.2.8}/tests/test_assembler.py +0 -0
  343. {hyperweave-0.2.7 → hyperweave-0.2.8}/tests/test_chart_frame.py +0 -0
  344. {hyperweave-0.2.7 → hyperweave-0.2.8}/tests/test_core.py +0 -0
  345. {hyperweave-0.2.7 → hyperweave-0.2.8}/tests/test_github_scrape.py +0 -0
  346. {hyperweave-0.2.7 → hyperweave-0.2.8}/tests/test_kit.py +0 -0
  347. {hyperweave-0.2.7 → hyperweave-0.2.8}/tests/test_mcp.py +0 -0
  348. {hyperweave-0.2.7 → hyperweave-0.2.8}/tests/test_paradigm_dispatch.py +0 -0
  349. {hyperweave-0.2.7 → hyperweave-0.2.8}/tests/test_paradigm_extensibility.py +0 -0
  350. {hyperweave-0.2.7 → hyperweave-0.2.8}/tests/test_proofset.py +0 -0
  351. {hyperweave-0.2.7 → hyperweave-0.2.8}/tests/test_render.py +0 -0
  352. {hyperweave-0.2.7 → hyperweave-0.2.8}/tests/test_resolver_rhythm.py +0 -0
  353. {hyperweave-0.2.7 → hyperweave-0.2.8}/tests/test_serve.py +0 -0
  354. {hyperweave-0.2.7 → hyperweave-0.2.8}/tests/test_serve_live_state.py +0 -0
  355. {hyperweave-0.2.7 → hyperweave-0.2.8}/tests/test_state_inference.py +0 -0
  356. {hyperweave-0.2.7 → hyperweave-0.2.8}/tests/test_stats_card.py +0 -0
  357. {hyperweave-0.2.7 → hyperweave-0.2.8}/tests/test_telemetry.py +0 -0
  358. {hyperweave-0.2.7 → hyperweave-0.2.8}/tests/test_telemetry_integration.py +0 -0
  359. {hyperweave-0.2.7 → hyperweave-0.2.8}/tests/test_timeline.py +0 -0
  360. {hyperweave-0.2.7 → hyperweave-0.2.8}/uv.lock +0 -0
@@ -5,6 +5,25 @@ All notable changes to HyperWeave are documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.2.8] - 2026-04-20
9
+
10
+ ### Fixed
11
+
12
+ - **Star history charts now render readably on large repositories.** Previously, repos with more than ~40,000 stars produced a flat-then-vertical "hockey stick" because GitHub's stargazer REST endpoint hard-caps deep pagination, so the only data reachable was a small cluster of early-history stars followed by a single jump to today. Star history now sources from GitHub's GraphQL API and adapts its sampling window to the repo: small repos continue to get full lifetime views, large repos get a detailed recent-growth curve similar to the one star-history.com shows.
13
+ - **Star-count milestone labels no longer stack on top of each other.** When sampled points clustered temporally, the milestone labels (`500`, `1K`, `5K`, `10K`, ...) would render in a single illegible pile on top of the crossing point. Milestones now maintain a minimum 40-pixel horizontal gap; any labels that would overlap with an already-placed one are dropped in favor of the first (lowest-threshold) milestone in the cluster.
14
+
15
+ ### Changed
16
+
17
+ - **All chart rendering now flows through template partials.** The chart engine's remaining rendering paths — axes, gridlines, polyline, area fill, milestones, and the empty-state overlay — joined the marker layer in Jinja. The engine module returns structured Python data; Jinja partials under `templates/components/` produce the final SVG. No visual change; output is byte-identical for the shipped genomes on unchanged inputs.
18
+
19
+ ### Added
20
+
21
+ - **`fetch_graphql` connector primitive.** New async helper in the connector layer that handles POST with JSON bodies, GitHub bearer-token rotation, circuit-breaker coordination, and SSRF validation — mirroring the existing `fetch_json` contract. This unlocks future migration of the stats card's six REST sub-fetches to a single GraphQL call, and keeps a single canonical place for authenticated-POST plumbing.
22
+
23
+ ### Dev
24
+
25
+ - GraphQL stargazer pipeline is covered by unit tests for the primary path, REST fallback on failure, no-token skip, mega-repo window cap, small-repo history exhaustion, downsampling correctness, and current-UTC now-point stamping.
26
+
8
27
  ## [0.2.7] - 2026-04-20
9
28
 
10
29
  ### Fixed
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hyperweave
3
- Version: 0.2.7
3
+ Version: 0.2.8
4
4
  Summary: Headless visual output layer for AI agents. One API call → self-contained SVG.
5
5
  Project-URL: Repository, https://github.com/InnerAura/hyperweave
6
6
  Project-URL: Issues, https://github.com/InnerAura/hyperweave/issues
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '0.2.7'
22
- __version_tuple__ = version_tuple = (0, 2, 7)
21
+ __version__ = version = '0.2.8'
22
+ __version_tuple__ = version_tuple = (0, 2, 8)
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -337,12 +337,16 @@ def _ctx_chart(spec: ComposeSpec, resolved: ResolvedArtifact, css: dict[str, str
337
337
  ctx["chart_viewport_w"] = 0
338
338
  ctx["chart_viewport_h"] = 0
339
339
  ctx["chart_defs"] = ""
340
- ctx["chart_axes"] = ""
341
- ctx["chart_gridlines"] = ""
342
- ctx["chart_area"] = ""
343
- ctx["chart_polyline"] = ""
340
+ # Post-v0.2.8: axes / gridlines / milestones / markers all return structured
341
+ # lists; polyline / area / empty_state are dicts or None so templates can
342
+ # use ``{% if %}`` to guard includes without a StrictUndefined trap.
343
+ ctx["chart_axes"] = []
344
+ ctx["chart_gridlines"] = []
345
+ ctx["chart_area"] = None
346
+ ctx["chart_polyline"] = None
344
347
  ctx["chart_markers"] = []
345
- ctx["chart_milestones"] = ""
348
+ ctx["chart_milestones"] = []
349
+ ctx["chart_empty_state"] = None
346
350
  ctx["data_hw_status"] = "fresh"
347
351
  ctx.update(resolved.frame_context)
348
352
  return ctx
@@ -216,3 +216,66 @@ async def fetch_text(
216
216
  merged.update(headers)
217
217
  response = await fetch(url, provider=provider, headers=merged)
218
218
  return response.text
219
+
220
+
221
+ # GraphQL POST
222
+
223
+ _GITHUB_GRAPHQL_URL: str = "https://api.github.com/graphql"
224
+
225
+
226
+ async def fetch_graphql(
227
+ query: str,
228
+ variables: dict[str, Any] | None = None,
229
+ *,
230
+ provider: str = "github",
231
+ url: str = _GITHUB_GRAPHQL_URL,
232
+ ) -> dict[str, Any]:
233
+ """POST a GraphQL query and return the parsed JSON response.
234
+
235
+ Mirrors :func:`fetch_json`'s contract (SSRF validation, per-provider
236
+ circuit breaker, timeouts, GitHub Bearer-token injection) but speaks
237
+ POST with a JSON body. The single GraphQL endpoint for GitHub is
238
+ baked into the default URL so callers don't have to remember it.
239
+
240
+ GraphQL always returns HTTP 200 with a ``data`` field and an optional
241
+ ``errors`` list — HTTP-level failures trip the breaker, but query-level
242
+ errors (invalid field, missing perms) come through as response body
243
+ and are the caller's responsibility to inspect.
244
+ """
245
+ validate_url(url)
246
+
247
+ breaker = get_breaker(provider)
248
+ if not breaker.allow_request():
249
+ raise CircuitOpenError(
250
+ f"Circuit breaker open for provider {provider!r}. Retry after {breaker.recovery_timeout}s."
251
+ )
252
+
253
+ merged_headers: dict[str, str] = {
254
+ "User-Agent": f"HyperWeave/{__version__} (https://hyperweave.app)",
255
+ "Accept": "application/json",
256
+ "Content-Type": "application/json",
257
+ }
258
+ if provider == "github":
259
+ token = _get_github_token()
260
+ if token:
261
+ merged_headers["Authorization"] = f"Bearer {token}"
262
+
263
+ timeout = httpx.Timeout(
264
+ connect=CONNECT_TIMEOUT,
265
+ read=TOTAL_TIMEOUT,
266
+ write=TOTAL_TIMEOUT,
267
+ pool=TOTAL_TIMEOUT,
268
+ )
269
+
270
+ body: dict[str, Any] = {"query": query, "variables": variables or {}}
271
+
272
+ try:
273
+ async with httpx.AsyncClient(timeout=timeout) as client:
274
+ response = await client.post(url, headers=merged_headers, json=body)
275
+ response.raise_for_status()
276
+ breaker.record_success()
277
+ data: dict[str, Any] = response.json()
278
+ return data
279
+ except (httpx.HTTPStatusError, httpx.RequestError) as exc:
280
+ breaker.record_failure()
281
+ raise ConnectorError(f"GraphQL fetch failed for {provider!r}: {exc}") from exc
@@ -8,7 +8,14 @@ import re
8
8
  from datetime import UTC, datetime
9
9
  from typing import Any
10
10
 
11
- from hyperweave.connectors.base import fetch_json, fetch_text
11
+ from hyperweave.connectors.base import (
12
+ CircuitOpenError,
13
+ ConnectorError,
14
+ _get_github_token,
15
+ fetch_graphql,
16
+ fetch_json,
17
+ fetch_text,
18
+ )
12
19
  from hyperweave.connectors.cache import get_cache
13
20
 
14
21
  PROVIDER = "github"
@@ -144,6 +151,25 @@ _STARGAZER_PAGE_SIZE = 100
144
151
  _STARGAZER_PAGE_CAP = 400
145
152
  _STARGAZER_ACCEPT_HEADER = "application/vnd.github.v3.star+json"
146
153
 
154
+ # GraphQL-path constants. Walking backwards from "now" via cursor pagination
155
+ # bypasses the REST 400-page cap entirely. For small repos (≤2000 stars) we
156
+ # get full lifetime coverage; for mega-repos we get a recent-growth window,
157
+ # which is the behavior star-history.com uses for the same reason.
158
+ _GRAPHQL_PAGE_SIZE = 100
159
+ _GRAPHQL_MAX_PAGES = 20 # 20 * 100 = 2000 most-recent stargazers
160
+
161
+ _STARGAZER_GRAPHQL_QUERY = """
162
+ query StargazerWindow($owner: String!, $repo: String!, $cursor: String) {
163
+ repository(owner: $owner, name: $repo) {
164
+ stargazerCount
165
+ stargazers(last: 100, before: $cursor) {
166
+ pageInfo { startCursor hasPreviousPage }
167
+ edges { starredAt }
168
+ }
169
+ }
170
+ }
171
+ """
172
+
147
173
 
148
174
  async def fetch_stargazer_history(
149
175
  owner: str,
@@ -152,19 +178,14 @@ async def fetch_stargazer_history(
152
178
  ) -> dict[str, Any]:
153
179
  """Fetch sampled star history for ``owner/repo`` as cumulative data points.
154
180
 
155
- Strategy:
156
- 1. GET ``/repos/{owner}/{repo}`` total ``stargazers_count``.
157
- 2. Compute total pages (30 per page on the stargazers endpoint).
158
- 3. Sample ``sample_pages`` evenly distributed page numbers across
159
- ``[1, total_pages]`` and fetch them concurrently with the
160
- ``application/vnd.github.v3.star+json`` ``Accept`` header so each
161
- element contains a ``starred_at`` timestamp.
162
- 4. From each sampled page take the FIRST starred_at and use it as the
163
- time marker for the cumulative count at ``(page - 1) * 30``.
164
- 5. Cache under ``github:{owner}/{repo}:stargazer-history``.
165
-
166
- Returns a dict with keys ``points`` (list of ``{date, count}``), ``current_stars``,
167
- ``repo``, ``ttl``. Raises ``ValueError`` on invalid identifier.
181
+ Public dispatcher. Prefers GraphQL when a token is available (unlocks the
182
+ recent-growth window on mega-repos beyond GitHub's 400-page REST cap);
183
+ falls back to REST sampling on GraphQL failure or missing token. Caches
184
+ successful results under ``github:{owner}/{repo}:stargazer-history``.
185
+
186
+ Returns a dict with keys ``points`` (list of ``{date, count}``),
187
+ ``current_stars``, ``repo``, ``ttl``. Raises ``ValueError`` on invalid
188
+ identifier.
168
189
  """
169
190
  if not owner or not repo:
170
191
  raise ValueError("fetch_stargazer_history requires owner and repo")
@@ -176,25 +197,162 @@ async def fetch_stargazer_history(
176
197
  if cached is not None:
177
198
  return cached # type: ignore[no-any-return]
178
199
 
200
+ result: dict[str, Any] | None = None
201
+
202
+ # Primary path: GraphQL (requires auth). Walks backwards from most-recent
203
+ # so mega-repos get a detailed recent-growth curve instead of a hockey
204
+ # stick. A per-page budget of 20 * 100 = 2000 stargazers per cold fetch
205
+ # keeps us well under the 5000-points/hour GraphQL rate limit.
206
+ if _get_github_token():
207
+ try:
208
+ result = await _fetch_stargazer_history_graphql(owner, repo, sample_pages)
209
+ except (ConnectorError, CircuitOpenError):
210
+ result = None # fall through to REST
211
+
212
+ if result is None:
213
+ # Fallback path: REST sampling. Works unauth at 60 req/hr but caps at
214
+ # ~40k stars on mega-repos (GitHub's deep-pagination wall).
215
+ result = await _fetch_stargazer_history_rest(owner, repo, sample_pages)
216
+
217
+ cache.set(cache_key, result, STARGAZER_HISTORY_TTL)
218
+ return result
219
+
220
+
221
+ async def _fetch_stargazer_history_graphql(
222
+ owner: str,
223
+ repo: str,
224
+ sample_pages: int,
225
+ ) -> dict[str, Any]:
226
+ """GraphQL stargazer fetch — walks cursor pagination backwards from most-recent.
227
+
228
+ The REST ``/stargazers`` endpoint caps deep pagination at ~400 pages, so
229
+ for a 361k-star repo we could only ever see stars #1 to #40000 — the
230
+ early hype window — producing the flat-then-vertical "hockey stick"
231
+ curve. GraphQL cursor pagination has no such cap; we simply walk backward
232
+ from the endpoint, collect up to ``_GRAPHQL_MAX_PAGES`` pages, and stop
233
+ early if we exhaust the repo's history (small repos get full lifetime).
234
+ """
235
+ identifier = f"{owner}/{repo}"
236
+ variables: dict[str, Any] = {"owner": owner, "repo": repo, "cursor": None}
237
+
238
+ all_timestamps: list[str] = []
239
+ total_stars = 0
240
+
241
+ for _ in range(_GRAPHQL_MAX_PAGES):
242
+ response = await fetch_graphql(_STARGAZER_GRAPHQL_QUERY, variables, provider=PROVIDER)
243
+ repo_data = (response.get("data") or {}).get("repository")
244
+ if not repo_data:
245
+ # Repo doesn't exist or query errored — return empty honestly.
246
+ return {
247
+ "points": [],
248
+ "current_stars": 0,
249
+ "repo": identifier,
250
+ "ttl": STARGAZER_HISTORY_TTL,
251
+ }
252
+
253
+ total_stars = int(repo_data.get("stargazerCount", 0))
254
+ if total_stars == 0:
255
+ return {
256
+ "points": [],
257
+ "current_stars": 0,
258
+ "repo": identifier,
259
+ "ttl": STARGAZER_HISTORY_TTL,
260
+ }
261
+
262
+ stargazers = repo_data.get("stargazers") or {}
263
+ edges = stargazers.get("edges") or []
264
+ # GraphQL `last/before` returns edges in ASC chronological order.
265
+ # Prepend so the accumulated list stays sorted oldest→newest across
266
+ # multiple backward walks.
267
+ page_timestamps = [e["starredAt"] for e in edges if isinstance(e, dict) and e.get("starredAt")]
268
+ all_timestamps = page_timestamps + all_timestamps
269
+
270
+ page_info = stargazers.get("pageInfo") or {}
271
+ if not page_info.get("hasPreviousPage"):
272
+ break
273
+ variables["cursor"] = page_info.get("startCursor")
274
+
275
+ if not all_timestamps:
276
+ return {
277
+ "points": [],
278
+ "current_stars": total_stars,
279
+ "repo": identifier,
280
+ "ttl": STARGAZER_HISTORY_TTL,
281
+ }
282
+
283
+ points = _downsample_timestamps(all_timestamps, sample_pages, total_stars)
284
+ # Append honest "now" point — matches the v0.2.7 §1.4 contract.
285
+ points.append({"date": datetime.now(UTC).isoformat(), "count": total_stars})
286
+ points.sort(key=lambda p: p["date"])
287
+
288
+ return {
289
+ "points": points,
290
+ "current_stars": total_stars,
291
+ "repo": identifier,
292
+ "ttl": STARGAZER_HISTORY_TTL,
293
+ }
294
+
295
+
296
+ def _downsample_timestamps(
297
+ timestamps: list[str],
298
+ n_samples: int,
299
+ total_stars: int,
300
+ ) -> list[dict[str, Any]]:
301
+ """Reduce N ascending timestamps to ``n_samples`` evenly-spaced points.
302
+
303
+ The count at each sampled timestamp is computed backwards from
304
+ ``total_stars``: since ``timestamps`` represents the most-recent
305
+ ``len(timestamps)`` stargazers in chronological order, the final
306
+ timestamp corresponds to ``total_stars`` and the earliest to
307
+ ``total_stars - (n - 1)``.
308
+ """
309
+ n = len(timestamps)
310
+ if n == 0:
311
+ return []
312
+ base = total_stars - (n - 1)
313
+ if n <= n_samples:
314
+ return [{"date": ts, "count": base + idx} for idx, ts in enumerate(timestamps)]
315
+
316
+ # Pick n_samples evenly-spaced indices across [0, n-1], always including
317
+ # the endpoints so the curve starts and ends at the captured extremes.
318
+ if n_samples <= 1:
319
+ return [{"date": timestamps[-1], "count": total_stars}]
320
+ step = (n - 1) / (n_samples - 1)
321
+ indices = sorted({round(i * step) for i in range(n_samples)})
322
+ return [{"date": timestamps[idx], "count": base + idx} for idx in indices]
323
+
324
+
325
+ async def _fetch_stargazer_history_rest(
326
+ owner: str,
327
+ repo: str,
328
+ sample_pages: int = 12,
329
+ ) -> dict[str, Any]:
330
+ """REST-based stargazer sampling — the v0.2.7 behavior preserved as fallback.
331
+
332
+ Used when no ``HW_GITHUB_TOKENS`` is set or when the GraphQL path fails.
333
+ Samples evenly across pages ``[1, min(total_pages, 400)]`` and stamps the
334
+ now-point with the current UTC timestamp. Bounded by GitHub's 400-page
335
+ deep-pagination cap: produces a truthful but limited view of mega-repos.
336
+ """
337
+ identifier = f"{owner}/{repo}"
338
+
179
339
  # Step 1: total stars
180
340
  repo_url = f"https://api.github.com/repos/{identifier}"
181
341
  repo_data = await fetch_json(repo_url, provider=PROVIDER)
182
342
  total_stars = int(repo_data.get("stargazers_count", 0))
183
343
  if total_stars == 0:
184
- empty_result: dict[str, Any] = {
344
+ return {
185
345
  "points": [],
186
346
  "current_stars": 0,
187
347
  "repo": identifier,
188
348
  "ttl": STARGAZER_HISTORY_TTL,
189
349
  }
190
- cache.set(cache_key, empty_result, STARGAZER_HISTORY_TTL)
191
- return empty_result
192
350
 
193
351
  # Step 2: compute total pages (clamped at GitHub's deep-pagination cap)
194
352
  total_pages = max(1, math.ceil(total_stars / _STARGAZER_PAGE_SIZE))
195
353
  effective_pages = min(total_pages, _STARGAZER_PAGE_CAP)
196
354
 
197
- # Single-page case: repo has ≤ 30 stars. The "first starred_at of the page"
355
+ # Single-page case: repo has ≤ 100 stars. The "first starred_at of the page"
198
356
  # sampling trick would otherwise collapse to a single aggregated point plus
199
357
  # a duplicate-date "now" point, producing a zero time-range polyline. Use
200
358
  # each stargazer's own timestamp instead — the whole page fits in one call.
@@ -210,14 +368,12 @@ async def fetch_stargazer_history(
210
368
  for idx, entry in enumerate(page_payload):
211
369
  if isinstance(entry, dict) and entry.get("starred_at"):
212
370
  single_page_points.append({"date": entry["starred_at"], "count": idx + 1})
213
- single_page_result: dict[str, Any] = {
371
+ return {
214
372
  "points": single_page_points,
215
373
  "current_stars": total_stars,
216
374
  "repo": identifier,
217
375
  "ttl": STARGAZER_HISTORY_TTL,
218
376
  }
219
- cache.set(cache_key, single_page_result, STARGAZER_HISTORY_TTL)
220
- return single_page_result
221
377
 
222
378
  # Cap the sample count at the number of reachable pages.
223
379
  sample_count = min(sample_pages, effective_pages)
@@ -264,14 +420,12 @@ async def fetch_stargazer_history(
264
420
  points.append({"date": datetime.now(UTC).isoformat(), "count": total_stars})
265
421
  points.sort(key=lambda p: p["date"])
266
422
 
267
- result: dict[str, Any] = {
423
+ return {
268
424
  "points": points,
269
425
  "current_stars": total_stars,
270
426
  "repo": identifier,
271
427
  "ttl": STARGAZER_HISTORY_TTL,
272
428
  }
273
- cache.set(cache_key, result, STARGAZER_HISTORY_TTL)
274
- return result
275
429
 
276
430
 
277
431
  # ── Session 2A+2B: contribution calendar scraping ──────────────────────────