hyperweave 0.3.3__tar.gz → 0.3.4__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 (422) hide show
  1. {hyperweave-0.3.3 → hyperweave-0.3.4}/CHANGELOG.md +21 -0
  2. {hyperweave-0.3.3 → hyperweave-0.3.4}/PKG-INFO +1 -1
  3. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/_version.py +2 -2
  4. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/cli.py +234 -27
  5. hyperweave-0.3.4/tests/test_doctor.py +208 -0
  6. hyperweave-0.3.4/tests/test_install_hook.py +233 -0
  7. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_telemetry_integration.py +11 -10
  8. {hyperweave-0.3.3 → hyperweave-0.3.4}/.dockerignore +0 -0
  9. {hyperweave-0.3.3 → hyperweave-0.3.4}/.github/workflows/ci.yml +0 -0
  10. {hyperweave-0.3.3 → hyperweave-0.3.4}/.github/workflows/deploy.yml +0 -0
  11. {hyperweave-0.3.3 → hyperweave-0.3.4}/.github/workflows/publish.yml +0 -0
  12. {hyperweave-0.3.3 → hyperweave-0.3.4}/.gitignore +0 -0
  13. {hyperweave-0.3.3 → hyperweave-0.3.4}/.pre-commit-config.yaml +0 -0
  14. {hyperweave-0.3.3 → hyperweave-0.3.4}/Dockerfile +0 -0
  15. {hyperweave-0.3.3 → hyperweave-0.3.4}/LICENSE +0 -0
  16. {hyperweave-0.3.3 → hyperweave-0.3.4}/README.md +0 -0
  17. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/buttons/button-liquid.svg +0 -0
  18. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/cards/card-butterfly.svg +0 -0
  19. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/cards/card-python.svg +0 -0
  20. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/cards/card-sunflower.svg +0 -0
  21. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/cards/card-waves.svg +0 -0
  22. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/brutalist-emerald/badge_critical.svg +0 -0
  23. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/brutalist-emerald/badge_passing.svg +0 -0
  24. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/brutalist-emerald/badge_warning.svg +0 -0
  25. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/brutalist-emerald/banner.svg +0 -0
  26. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/brutalist-emerald/icons/discord.svg +0 -0
  27. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/brutalist-emerald/icons/notion.svg +0 -0
  28. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/brutalist-emerald/icons/reddit.svg +0 -0
  29. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/brutalist-emerald/icons/spotify.svg +0 -0
  30. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/brutalist-emerald/icons/youtube.svg +0 -0
  31. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/brutalist-emerald/marquee_counter.svg +0 -0
  32. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/brutalist-emerald/marquee_horizontal.svg +0 -0
  33. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/brutalist-emerald/marquee_vertical.svg +0 -0
  34. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/brutalist-emerald/profile-cards/chart_stars_full.svg +0 -0
  35. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/brutalist-emerald/profile-cards/stats.svg +0 -0
  36. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/brutalist-emerald/strip.svg +0 -0
  37. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/chrome-horizon/badge_critical.svg +0 -0
  38. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/chrome-horizon/badge_passing.svg +0 -0
  39. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/chrome-horizon/badge_warning.svg +0 -0
  40. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/chrome-horizon/banner.svg +0 -0
  41. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/chrome-horizon/icons/bluesky.svg +0 -0
  42. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/chrome-horizon/icons/github.svg +0 -0
  43. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/chrome-horizon/icons/instagram.svg +0 -0
  44. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/chrome-horizon/icons/mastodon.svg +0 -0
  45. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/chrome-horizon/icons/x.svg +0 -0
  46. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/chrome-horizon/marquee_counter.svg +0 -0
  47. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/chrome-horizon/marquee_horizontal.svg +0 -0
  48. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/chrome-horizon/marquee_vertical.svg +0 -0
  49. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/chrome-horizon/profile-cards/chart_stars_full.svg +0 -0
  50. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/chrome-horizon/profile-cards/stats.svg +0 -0
  51. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/chrome-horizon/strip.svg +0 -0
  52. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/telemetry/master_card.svg +0 -0
  53. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/telemetry/receipt.svg +0 -0
  54. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/telemetry/receipt_claude-code_medium.svg +0 -0
  55. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/telemetry/receipt_codex_large.svg +0 -0
  56. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/telemetry/receipt_voltage_xlarge.svg +0 -0
  57. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/telemetry/rhythm_strip.svg +0 -0
  58. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/telemetry/rhythm_strip_voltage_xlarge.svg +0 -0
  59. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/footers/inneraura-footer-liquid.svg +0 -0
  60. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/footers/inneraura-footer-purple.svg +0 -0
  61. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/footers/inneraura-footer.svg +0 -0
  62. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/hyperweave-banner.svg +0 -0
  63. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/icons/cobalt-sapphire-discord.svg +0 -0
  64. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/icons/cobalt-sapphire-docs.svg +0 -0
  65. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/icons/cobalt-sapphire-github.svg +0 -0
  66. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/icons/cobalt-sapphire-instagram.svg +0 -0
  67. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/icons/cobalt-sapphire-linkedin.svg +0 -0
  68. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/icons/cobalt-sapphire-tiktok.svg +0 -0
  69. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/icons/cobalt-sapphire-x.svg +0 -0
  70. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/icons/cobalt-sapphire-youtube.svg +0 -0
  71. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/marquees/badge-showcase-triple.svg +0 -0
  72. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/marquees/genome-marquee-triple.svg +0 -0
  73. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/marquees/sample-badges.svg +0 -0
  74. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/mintlify-assets/404.svg +0 -0
  75. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/mintlify-assets/callout-icons.svg +0 -0
  76. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/mintlify-assets/divider.svg +0 -0
  77. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/mintlify-assets/favicon.svg +0 -0
  78. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/mintlify-assets/hero-banner.svg +0 -0
  79. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/mintlify-assets/hyperweave-banner-v2.svg +0 -0
  80. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/mintlify-assets/hyperweave-navbar-logo.svg +0 -0
  81. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/mintlify-assets/loader.svg +0 -0
  82. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/mintlify-assets/og-image.svg +0 -0
  83. {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/timelines/hyperweave-roadmap.svg +0 -0
  84. {hyperweave-0.3.3 → hyperweave-0.3.4}/docs/assets/favicon.svg +0 -0
  85. {hyperweave-0.3.3 → hyperweave-0.3.4}/docs/assets/hyperweave-banner.svg +0 -0
  86. {hyperweave-0.3.3 → hyperweave-0.3.4}/docs/assets/hyperweave-navbar-logo.svg +0 -0
  87. {hyperweave-0.3.3 → hyperweave-0.3.4}/docs/assets/og-image.svg +0 -0
  88. {hyperweave-0.3.3 → hyperweave-0.3.4}/docs/explanation/architecture.mdx +0 -0
  89. {hyperweave-0.3.3 → hyperweave-0.3.4}/docs/explanation/camo-compatibility.mdx +0 -0
  90. {hyperweave-0.3.3 → hyperweave-0.3.4}/docs/explanation/cim-compliance.mdx +0 -0
  91. {hyperweave-0.3.3 → hyperweave-0.3.4}/docs/explanation/genome-profile-system.mdx +0 -0
  92. {hyperweave-0.3.3 → hyperweave-0.3.4}/docs/explanation/metadata-tiers.mdx +0 -0
  93. {hyperweave-0.3.3 → hyperweave-0.3.4}/docs/how-to/add-motion-to-badges.mdx +0 -0
  94. {hyperweave-0.3.3 → hyperweave-0.3.4}/docs/how-to/create-session-receipts.mdx +0 -0
  95. {hyperweave-0.3.3 → hyperweave-0.3.4}/docs/how-to/set-up-claude-code-hooks.mdx +0 -0
  96. {hyperweave-0.3.3 → hyperweave-0.3.4}/docs/how-to/use-live-data-badges.mdx +0 -0
  97. {hyperweave-0.3.3 → hyperweave-0.3.4}/docs/introduction.mdx +0 -0
  98. {hyperweave-0.3.3 → hyperweave-0.3.4}/docs/mint.json +0 -0
  99. {hyperweave-0.3.3 → hyperweave-0.3.4}/docs/quickstart.mdx +0 -0
  100. {hyperweave-0.3.3 → hyperweave-0.3.4}/docs/reference/cli.mdx +0 -0
  101. {hyperweave-0.3.3 → hyperweave-0.3.4}/docs/reference/compose-spec.mdx +0 -0
  102. {hyperweave-0.3.3 → hyperweave-0.3.4}/docs/reference/genomes.mdx +0 -0
  103. {hyperweave-0.3.3 → hyperweave-0.3.4}/docs/reference/http-api.mdx +0 -0
  104. {hyperweave-0.3.3 → hyperweave-0.3.4}/docs/reference/mcp-tools.mdx +0 -0
  105. {hyperweave-0.3.3 → hyperweave-0.3.4}/docs/reference/motions.mdx +0 -0
  106. {hyperweave-0.3.3 → hyperweave-0.3.4}/docs/reference/telemetry-contract.mdx +0 -0
  107. {hyperweave-0.3.3 → hyperweave-0.3.4}/docs/spec/hyperweave-protocol.mdx +0 -0
  108. {hyperweave-0.3.3 → hyperweave-0.3.4}/docs/tutorials/build-an-artifact-kit.mdx +0 -0
  109. {hyperweave-0.3.3 → hyperweave-0.3.4}/docs/tutorials/compose-your-first-badge.mdx +0 -0
  110. {hyperweave-0.3.3 → hyperweave-0.3.4}/docs/tutorials/install-session-telemetry.mdx +0 -0
  111. {hyperweave-0.3.3 → hyperweave-0.3.4}/fly.toml +0 -0
  112. {hyperweave-0.3.3 → hyperweave-0.3.4}/hooks/install.py +0 -0
  113. {hyperweave-0.3.3 → hyperweave-0.3.4}/hooks/session_end.sh +0 -0
  114. {hyperweave-0.3.3 → hyperweave-0.3.4}/justfile +0 -0
  115. {hyperweave-0.3.3 → hyperweave-0.3.4}/pyproject.toml +0 -0
  116. {hyperweave-0.3.3 → hyperweave-0.3.4}/scripts/extract_font_metrics.py +0 -0
  117. {hyperweave-0.3.3 → hyperweave-0.3.4}/scripts/extract_glyphs.py +0 -0
  118. {hyperweave-0.3.3 → hyperweave-0.3.4}/scripts/generate_proofset.py +0 -0
  119. {hyperweave-0.3.3 → hyperweave-0.3.4}/scripts/probe_live_stats.py +0 -0
  120. {hyperweave-0.3.3 → hyperweave-0.3.4}/scripts/probe_star_history.py +0 -0
  121. {hyperweave-0.3.3 → hyperweave-0.3.4}/scripts/stress_test.py +0 -0
  122. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/__init__.py +0 -0
  123. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/__main__.py +0 -0
  124. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/compose/__init__.py +0 -0
  125. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/compose/assembler.py +0 -0
  126. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/compose/bar_chart.py +0 -0
  127. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/compose/context.py +0 -0
  128. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/compose/engine.py +0 -0
  129. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/compose/lanes.py +0 -0
  130. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/compose/layout.py +0 -0
  131. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/compose/palette.py +0 -0
  132. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/compose/reasoning.py +0 -0
  133. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/compose/resolver.py +0 -0
  134. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/compose/resolvers/__init__.py +0 -0
  135. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/compose/resolvers/chart.py +0 -0
  136. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/compose/resolvers/stats.py +0 -0
  137. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/compose/rhythm.py +0 -0
  138. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/compose/rhythm_strip.py +0 -0
  139. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/compose/treemap.py +0 -0
  140. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/compose/validate_paradigms.py +0 -0
  141. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/config/__init__.py +0 -0
  142. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/config/genome_validator.py +0 -0
  143. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/config/loader.py +0 -0
  144. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/config/registry.py +0 -0
  145. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/config/settings.py +0 -0
  146. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/connectors/__init__.py +0 -0
  147. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/connectors/arxiv.py +0 -0
  148. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/connectors/base.py +0 -0
  149. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/connectors/cache.py +0 -0
  150. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/connectors/github.py +0 -0
  151. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/connectors/rest.py +0 -0
  152. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/core/__init__.py +0 -0
  153. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/core/cell_layout.py +0 -0
  154. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/core/color.py +0 -0
  155. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/core/contracts.py +0 -0
  156. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/core/enums.py +0 -0
  157. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/core/font_metrics.py +0 -0
  158. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/core/models.py +0 -0
  159. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/core/paradigm.py +0 -0
  160. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/core/schema.py +0 -0
  161. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/core/state.py +0 -0
  162. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/core/text.py +0 -0
  163. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/core/thresholds.py +0 -0
  164. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/badge_modes.yaml +0 -0
  165. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/css/accessibility.css +0 -0
  166. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/css/bridge.css +0 -0
  167. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/css/expression.css +0 -0
  168. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/css/status.css +0 -0
  169. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/font-metrics/chakra-petch.json +0 -0
  170. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/font-metrics/inter.json +0 -0
  171. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/font-metrics/jetbrains-mono.json +0 -0
  172. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/font-metrics/orbitron.json +0 -0
  173. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/fonts/barlow-condensed-700.b64 +0 -0
  174. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/fonts/barlow-condensed-700.meta.json +0 -0
  175. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/fonts/barlow-condensed-900.b64 +0 -0
  176. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/fonts/barlow-condensed-900.meta.json +0 -0
  177. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/fonts/chakra-petch.b64 +0 -0
  178. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/fonts/chakra-petch.meta.json +0 -0
  179. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/fonts/jetbrains-mono.b64 +0 -0
  180. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/fonts/jetbrains-mono.meta.json +0 -0
  181. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/fonts/orbitron.b64 +0 -0
  182. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/fonts/orbitron.meta.json +0 -0
  183. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/genomes/automata.json +0 -0
  184. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/genomes/brutalist.json +0 -0
  185. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/genomes/chrome.json +0 -0
  186. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/genomes/telemetry-claude-code.json +0 -0
  187. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/genomes/telemetry-codex.json +0 -0
  188. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/genomes/telemetry-cream.json +0 -0
  189. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/genomes/telemetry-voltage.json +0 -0
  190. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/glyphs.json +0 -0
  191. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/motions/border/chromatic-pulse.yaml +0 -0
  192. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/motions/border/corner-trace.yaml +0 -0
  193. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/motions/border/dual-orbit.yaml +0 -0
  194. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/motions/border/entanglement.yaml +0 -0
  195. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/motions/border/rimrun.yaml +0 -0
  196. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/motions/static.yaml +0 -0
  197. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/paradigms/brutalist.yaml +0 -0
  198. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/paradigms/cellular.yaml +0 -0
  199. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/paradigms/chrome.yaml +0 -0
  200. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/paradigms/default.yaml +0 -0
  201. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/policies/normal.json +0 -0
  202. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/policies/permissive.json +0 -0
  203. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/policies/ungoverned.json +0 -0
  204. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/profiles/brutalist.contract.json +0 -0
  205. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/profiles/brutalist.yaml +0 -0
  206. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/profiles/chrome.contract.json +0 -0
  207. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/profiles/chrome.yaml +0 -0
  208. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/reasoning/__init__.py +0 -0
  209. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/reasoning/brutalist.yaml +0 -0
  210. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/specimens.yaml +0 -0
  211. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/telemetry/model-pricing.yaml +0 -0
  212. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/telemetry/runtimes/claude-code.yaml +0 -0
  213. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/telemetry/runtimes/codex.yaml +0 -0
  214. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/telemetry/stage-config.yaml +0 -0
  215. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/telemetry/stage-labels.yaml +0 -0
  216. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/telemetry/tool-colors.yaml +0 -0
  217. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/terminals/arrow.json +0 -0
  218. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/terminals/aurora.json +0 -0
  219. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/terminals/beacon.json +0 -0
  220. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/terminals/bracket3d.json +0 -0
  221. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/terminals/chevron.json +0 -0
  222. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/terminals/crosshair.json +0 -0
  223. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/terminals/diamond.json +0 -0
  224. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/terminals/rocket.json +0 -0
  225. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/terminals/rules/bar.json +0 -0
  226. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/terminals/rules/dashed.json +0 -0
  227. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/terminals/rules/five-wave.json +0 -0
  228. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/terminals/rules/spectral.json +0 -0
  229. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/terminals/rules/straight.json +0 -0
  230. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/terminals/rules/wave.json +0 -0
  231. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/terminals/stijl.json +0 -0
  232. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/kit.py +0 -0
  233. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/mcp/__init__.py +0 -0
  234. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/mcp/__main__.py +0 -0
  235. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/mcp/server.py +0 -0
  236. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/py.typed +0 -0
  237. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/render/__init__.py +0 -0
  238. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/render/chart_engine.py +0 -0
  239. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/render/fonts.py +0 -0
  240. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/render/glyphs.py +0 -0
  241. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/render/motion.py +0 -0
  242. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/render/templates.py +0 -0
  243. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/serve/__init__.py +0 -0
  244. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/serve/app.py +0 -0
  245. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/serve/data_tokens.py +0 -0
  246. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/telemetry/__init__.py +0 -0
  247. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/telemetry/capture.py +0 -0
  248. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/telemetry/codex_parser.py +0 -0
  249. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/telemetry/contract.py +0 -0
  250. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/telemetry/corrections.py +0 -0
  251. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/telemetry/cost.py +0 -0
  252. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/telemetry/models.py +0 -0
  253. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/telemetry/parser.py +0 -0
  254. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/telemetry/receipt_paths.py +0 -0
  255. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/telemetry/runtimes.py +0 -0
  256. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/telemetry/stages.py +0 -0
  257. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/components/chart-area.svg.j2 +0 -0
  258. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/components/chart-axes.svg.j2 +0 -0
  259. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/components/chart-empty-state.svg.j2 +0 -0
  260. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/components/chart-gridlines.svg.j2 +0 -0
  261. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/components/chart-markers/circle.svg.j2 +0 -0
  262. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/components/chart-markers/diamond.svg.j2 +0 -0
  263. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/components/chart-markers/endpoint-diamond.svg.j2 +0 -0
  264. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/components/chart-markers/endpoint-rect.svg.j2 +0 -0
  265. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/components/chart-markers/rect.svg.j2 +0 -0
  266. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/components/chart-milestone-brutalist.svg.j2 +0 -0
  267. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/components/chart-milestone.svg.j2 +0 -0
  268. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/components/chart-polyline.svg.j2 +0 -0
  269. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/components/filter.svg.j2 +0 -0
  270. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/components/glyph-inline.svg.j2 +0 -0
  271. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/components/glyph.svg.j2 +0 -0
  272. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/components/gradient.svg.j2 +0 -0
  273. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/components/metadata.svg.j2 +0 -0
  274. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/components/metric.svg.j2 +0 -0
  275. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/components/phase-segment.svg.j2 +0 -0
  276. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/components/rule.svg.j2 +0 -0
  277. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/components/status.svg.j2 +0 -0
  278. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/components/terminal.svg.j2 +0 -0
  279. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/document.svg.j2 +0 -0
  280. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/error-badge.svg.j2 +0 -0
  281. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/badge/brutalist-content.j2 +0 -0
  282. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/badge/brutalist-dark-content.j2 +0 -0
  283. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/badge/brutalist-defs.j2 +0 -0
  284. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/badge/brutalist-light-content.j2 +0 -0
  285. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/badge/cellular-content.j2 +0 -0
  286. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/badge/cellular-defs.j2 +0 -0
  287. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/badge/chrome-content.j2 +0 -0
  288. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/badge/chrome-defs.j2 +0 -0
  289. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/badge/default-content.j2 +0 -0
  290. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/badge/default-defs.j2 +0 -0
  291. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/badge.svg.j2 +0 -0
  292. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/catalog.svg.j2 +0 -0
  293. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/chart/brutalist-content.j2 +0 -0
  294. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/chart/brutalist-dark-content.j2 +0 -0
  295. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/chart/brutalist-defs.j2 +0 -0
  296. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/chart/brutalist-light-content.j2 +0 -0
  297. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/chart/cellular-content.j2 +0 -0
  298. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/chart/cellular-defs.j2 +0 -0
  299. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/chart/chrome-content.j2 +0 -0
  300. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/chart/chrome-defs.j2 +0 -0
  301. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/chart.svg.j2 +0 -0
  302. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/divider/brutalist-seam.svg.j2 +0 -0
  303. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/divider/chrome-band.svg.j2 +0 -0
  304. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/divider.svg.j2 +0 -0
  305. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/icon/brutalist-content.j2 +0 -0
  306. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/icon/brutalist-defs.j2 +0 -0
  307. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/icon/cellular-content.j2 +0 -0
  308. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/icon/cellular-defs.j2 +0 -0
  309. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/icon/chrome-content.j2 +0 -0
  310. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/icon/chrome-defs.j2 +0 -0
  311. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/icon/default-content.j2 +0 -0
  312. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/icon/default-defs.j2 +0 -0
  313. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/icon.svg.j2 +0 -0
  314. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/marquee-horizontal/brutalist-content.j2 +0 -0
  315. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/marquee-horizontal/brutalist-defs.j2 +0 -0
  316. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/marquee-horizontal/brutalist-overlay.j2 +0 -0
  317. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/marquee-horizontal/cellular-content.j2 +0 -0
  318. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/marquee-horizontal/cellular-defs.j2 +0 -0
  319. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/marquee-horizontal/cellular-overlay.j2 +0 -0
  320. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/marquee-horizontal/chrome-content.j2 +0 -0
  321. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/marquee-horizontal/chrome-defs.j2 +0 -0
  322. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/marquee-horizontal/chrome-overlay.j2 +0 -0
  323. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/marquee-horizontal/default-content.j2 +0 -0
  324. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/marquee-horizontal/default-defs.j2 +0 -0
  325. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/marquee-horizontal.svg.j2 +0 -0
  326. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/master-card.svg.j2 +0 -0
  327. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/receipt.svg.j2 +0 -0
  328. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/rhythm-strip.svg.j2 +0 -0
  329. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/stats/brutalist-content.j2 +0 -0
  330. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/stats/brutalist-dark-content.j2 +0 -0
  331. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/stats/brutalist-defs.j2 +0 -0
  332. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/stats/brutalist-light-content.j2 +0 -0
  333. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/stats/cellular-content.j2 +0 -0
  334. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/stats/cellular-defs.j2 +0 -0
  335. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/stats/chrome-content.j2 +0 -0
  336. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/stats/chrome-defs.j2 +0 -0
  337. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/stats.svg.j2 +0 -0
  338. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/strip/brutalist-content.j2 +0 -0
  339. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/strip/brutalist-dark-content.j2 +0 -0
  340. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/strip/brutalist-defs.j2 +0 -0
  341. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/strip/brutalist-light-content.j2 +0 -0
  342. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/strip/brutalist-status.j2 +0 -0
  343. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/strip/cellular-content.j2 +0 -0
  344. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/strip/cellular-defs.j2 +0 -0
  345. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/strip/cellular-status.j2 +0 -0
  346. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/strip/chrome-content.j2 +0 -0
  347. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/strip/chrome-defs.j2 +0 -0
  348. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/strip/chrome-status.j2 +0 -0
  349. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/strip/default-content.j2 +0 -0
  350. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/strip/default-defs.j2 +0 -0
  351. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/strip/default-status.j2 +0 -0
  352. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/strip.svg.j2 +0 -0
  353. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/motions/border/chromatic-pulse.svg.j2 +0 -0
  354. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/motions/border/corner-trace.svg.j2 +0 -0
  355. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/motions/border/dual-orbit.svg.j2 +0 -0
  356. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/motions/border/entanglement.svg.j2 +0 -0
  357. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/motions/border/rimrun.svg.j2 +0 -0
  358. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/partials/provider-glyphs.svg.j2 +0 -0
  359. {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/partials/state-signal-cascade.j2 +0 -0
  360. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/__init__.py +0 -0
  361. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/conftest.py +0 -0
  362. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/fixtures/codex_session.jsonl +0 -0
  363. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/fixtures/codex_session_patches.jsonl +0 -0
  364. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/fixtures/github_contributions/synthetic.html +0 -0
  365. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/fixtures/session.json +0 -0
  366. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/fixtures/session.jsonl +0 -0
  367. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/fixtures/synthetic_session.jsonl +0 -0
  368. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/helpers.py +0 -0
  369. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/snapshots/url_stability/divider_band_chrome_static.svg +0 -0
  370. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/snapshots/url_stability/icon_github_chrome_static.svg +0 -0
  371. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_assembler.py +0 -0
  372. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_badge_brutalist_dark.py +0 -0
  373. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_badge_cellular.py +0 -0
  374. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_badge_layout.py +0 -0
  375. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_badge_mode.py +0 -0
  376. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_chart_engine.py +0 -0
  377. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_chart_frame.py +0 -0
  378. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_chromatic_coverage_validator.py +0 -0
  379. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_chrome_variants.py +0 -0
  380. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_codex_parser.py +0 -0
  381. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_compose_bar_chart.py +0 -0
  382. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_compose_rhythm_strip.py +0 -0
  383. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_compose_treemap.py +0 -0
  384. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_compose_variant_field.py +0 -0
  385. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_connectors.py +0 -0
  386. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_core.py +0 -0
  387. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_data_tokens.py +0 -0
  388. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_divider_cellular.py +0 -0
  389. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_divider_genome_specific.py +0 -0
  390. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_font_gating.py +0 -0
  391. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_font_metrics_chakra.py +0 -0
  392. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_genome_automata.py +0 -0
  393. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_github_scrape.py +0 -0
  394. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_kit.py +0 -0
  395. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_marquee_v0_2_16.py +0 -0
  396. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_mcp.py +0 -0
  397. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_paradigm_cellular.py +0 -0
  398. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_paradigm_dispatch.py +0 -0
  399. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_paradigm_extensibility.py +0 -0
  400. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_parse_transcript_auto.py +0 -0
  401. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_proofset.py +0 -0
  402. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_receipt_paths.py +0 -0
  403. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_receipt_token_compliance.py +0 -0
  404. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_render.py +0 -0
  405. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_resolver_rhythm.py +0 -0
  406. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_runtime_registries.py +0 -0
  407. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_serve.py +0 -0
  408. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_serve_live_state.py +0 -0
  409. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_slot_metric_state.py +0 -0
  410. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_state_inference.py +0 -0
  411. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_stats_brutalist.py +0 -0
  412. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_stats_card.py +0 -0
  413. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_strip_brutalist_grammar.py +0 -0
  414. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_strip_cellular.py +0 -0
  415. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_strip_status_toggle.py +0 -0
  416. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_telemetry.py +0 -0
  417. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_telemetry_contract_per_stage.py +0 -0
  418. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_telemetry_skin_dispatch.py +0 -0
  419. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_tool_class_completeness.py +0 -0
  420. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_url_stability.py +0 -0
  421. {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_variant_default_resolution.py +0 -0
  422. {hyperweave-0.3.3 → hyperweave-0.3.4}/uv.lock +0 -0
@@ -5,6 +5,27 @@ 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.3.4] - 2026-05-13
9
+
10
+ `install-hook` now detects Claude Code and Codex automatically. A new `hyperweave doctor` command shows hook status, transcripts, and recent receipts at a glance.
11
+
12
+ ### Added
13
+
14
+ - **`hyperweave doctor`** — shows hook registration, transcript directories, recent receipts, and version info per runtime.
15
+ - **`install-hook --runtime all`** — registers hooks for both runtimes regardless of auto-detection.
16
+
17
+ ### Changed
18
+
19
+ - **`install-hook` default** — without `--runtime`, detects which runtimes are installed and registers hooks for each. `--runtime claude-code` or `--runtime codex` scopes to one.
20
+
21
+ ### Fixed
22
+
23
+ - **Receipt footer** — restores the full relative path (`.hyperweave/receipts/{slug}.svg`); v0.3.3 had stripped the directory prefix.
24
+
25
+ ### Notes
26
+
27
+ - Codex receipts refresh live as the session progresses, reflecting cumulative state after each turn.
28
+
8
29
  ## [0.3.3] - 2026-05-12
9
30
 
10
31
  ### Fixed
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hyperweave
3
- Version: 0.3.3
3
+ Version: 0.3.4
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.3.3'
22
- __version_tuple__ = version_tuple = (0, 3, 3)
21
+ __version__ = version = '0.3.4'
22
+ __version_tuple__ = version_tuple = (0, 3, 4)
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -363,9 +363,13 @@ def session(
363
363
  genome_slug = _normalize_genome_slug(genome) if genome else ""
364
364
 
365
365
  # Pre-compute the receipt's on-disk filename (when applicable) so the
366
- # footer can render the same human-readable basename as the file the
367
- # user sees. The compose pipeline reads receipt_filename_hint when set;
368
- # an empty hint falls back to the legacy UUID-path footer (HTTP / MCP).
366
+ # footer can render the same path as the file the user sees. The compose
367
+ # pipeline reads receipt_filename_hint when set; an empty hint falls back
368
+ # to the legacy UUID-path footer (HTTP / MCP). Pass the FULL relative
369
+ # path (not just the basename) so the footer is self-documenting — a
370
+ # reader sees ".hyperweave/receipts/{slug}.svg" and knows where to find
371
+ # the file without prior context. Long footers trigger left-truncation
372
+ # of the constant prefix at resolver.py:_truncate_path_left.
369
373
  filename_hint = ""
370
374
  if action == "receipt" and not output:
371
375
  from datetime import datetime as _dt
@@ -390,10 +394,10 @@ def session(
390
394
  session_id=sid,
391
395
  prompt_text=first_prompt,
392
396
  )
393
- filename_hint = output.name
397
+ filename_hint = str(output)
394
398
  elif action == "receipt" and output:
395
- # Explicit --output: the user picked a basename; surface it.
396
- filename_hint = output.name
399
+ # Explicit --output: surface whatever path shape the user provided.
400
+ filename_hint = str(output)
397
401
 
398
402
  spec = ComposeSpec(
399
403
  type=frame_type,
@@ -567,12 +571,13 @@ def _install_codex_hook(hook_command: str, full_slug: str) -> None:
567
571
  """Write a Stop hook to ``~/.codex/hooks.json`` + enable codex_hooks feature.
568
572
 
569
573
  Per developers.openai.com/codex/hooks, Codex CLI fires Stop hooks
570
- PER-TURN (not per-session). Receipts therefore render at every turn
571
- boundary rather than once at session end. Document this caveat
572
- prominentlyusers may want to manually invoke
573
- ``hyperweave session receipt <transcript-path>`` once a session
574
- completes instead. v0.2.24 will revisit when codex notify-config
575
- surfaces a session-scoped event.
574
+ PER-TURN (after every assistant response). The receipt rewrites the
575
+ same deterministic filename each turn, so the on-disk file becomes a
576
+ live mid-session telemetry window opening it during a long session
577
+ shows the current state, and the final write at session-end carries
578
+ the complete cumulative receipt. This is intentional; future versions
579
+ will lean into live-receipt consumers (file watchers, dashboards)
580
+ rather than collapse it back to a single session-end event.
576
581
 
577
582
  Also writes ``[features] codex_hooks = true`` to ``~/.codex/config.toml``
578
583
  (preserving any other keys); the feature flag is required for the
@@ -628,8 +633,8 @@ def _install_codex_hook(hook_command: str, full_slug: str) -> None:
628
633
  typer.echo(f"Installed Stop hook in {hooks_path}{pinned}")
629
634
  typer.echo(f"Set [features] codex_hooks = true in {config_path}")
630
635
  typer.echo(
631
- "Note: Codex Stop fires per-turn — receipts render multiple times per session. "
632
- "v0.2.24 will refine to a session-scoped event.",
636
+ "Note: Codex Stop fires per-turn — the receipt file refreshes live as the "
637
+ "session progresses, always reflecting current cumulative state.",
633
638
  err=True,
634
639
  )
635
640
 
@@ -643,6 +648,37 @@ _HOOK_INSTALLERS = {
643
648
  "codex": _install_codex_hook,
644
649
  }
645
650
 
651
+ # Runtime → (config_dirname_under_home, cli_binary_name). Drives both the
652
+ # auto-detect path (config dir OR binary on PATH) and `hyperweave doctor`
653
+ # state reporting. Config-dir presence means "agent has been run at least
654
+ # once"; binary-on-PATH covers fresh installs where the dir hasn't been
655
+ # created yet. The installers create their dirs on demand, so installing
656
+ # for a binary-only runtime is safe.
657
+ _RUNTIME_DETECTION = {
658
+ "claude-code": (".claude", "claude"),
659
+ "codex": (".codex", "codex"),
660
+ }
661
+
662
+
663
+ def _detect_installed_runtimes() -> list[tuple[str, str]]:
664
+ """Detect installed agent runtimes via config-dir-OR-binary-on-PATH.
665
+
666
+ Returns ``(runtime_key, signal)`` tuples in ``_RUNTIME_DETECTION`` order.
667
+ Signal is ``"initialized"`` when the runtime's config dir exists (agent
668
+ has been run at least once), ``"binary_only"`` when only the CLI is on
669
+ PATH (fresh install, config dir not created yet). Runtimes with
670
+ neither signal are omitted entirely.
671
+ """
672
+ import shutil
673
+
674
+ detected: list[tuple[str, str]] = []
675
+ for runtime, (dirname, binname) in _RUNTIME_DETECTION.items():
676
+ if (Path.home() / dirname).exists():
677
+ detected.append((runtime, "initialized"))
678
+ elif shutil.which(binname):
679
+ detected.append((runtime, "binary_only"))
680
+ return detected
681
+
646
682
 
647
683
  @app.command("install-hook")
648
684
  def install_hook(
@@ -662,28 +698,55 @@ def install_hook(
662
698
  typer.Option(
663
699
  "--runtime",
664
700
  help=(
665
- "Agent runtime to install the receipt hook for. 'claude-code' (default) "
666
- "writes a SessionEnd hook to ~/.claude/settings.json. 'codex' writes a "
667
- "Stop hook to ~/.codex/hooks.json plus enables [features] codex_hooks "
668
- "in ~/.codex/config.toml. Codex Stop is per-turn, not per-session — "
669
- "see release notes for caveats."
701
+ "Agent runtime to install the receipt hook for. Empty (default) "
702
+ "auto-detects installed runtimes (~/.claude, ~/.codex, or 'claude'/"
703
+ "'codex' on PATH) and registers for each present. 'claude-code' "
704
+ "writes a SessionEnd hook to ~/.claude/settings.json. 'codex' writes "
705
+ "a Stop hook to ~/.codex/hooks.json plus [features] codex_hooks in "
706
+ "~/.codex/config.toml. 'all' forces both regardless of detection."
670
707
  ),
671
708
  ),
672
- ] = "claude-code",
709
+ ] = "",
673
710
  ) -> None:
674
- """Install a session-receipt hook for the chosen agent runtime."""
711
+ """Install session-receipt hooks for installed agent runtimes.
712
+
713
+ Default behavior detects which agent CLIs are installed (Claude Code,
714
+ Codex) via config dir presence or binary on PATH, and registers receipt
715
+ hooks for each. Pass ``--runtime <name>`` to scope to a single runtime,
716
+ or ``--runtime all`` to force both regardless of detection.
717
+ """
675
718
  from hyperweave.compose.resolver import _genome_supports_receipts
676
719
 
677
- if runtime not in _HOOK_INSTALLERS:
720
+ # Resolve targets:
721
+ # "" (default) → auto-detect installed runtimes (config dir OR binary)
722
+ # "all" → both runtimes regardless of detection
723
+ # "<name>" → just that runtime (legacy explicit form)
724
+ if runtime == "":
725
+ detected = _detect_installed_runtimes()
726
+ if not detected:
727
+ typer.echo(
728
+ "Error: no agent runtime detected (~/.claude, ~/.codex, or "
729
+ "'claude'/'codex' on PATH). Install Claude Code or Codex CLI, "
730
+ "or pass --runtime <name> to force.",
731
+ err=True,
732
+ )
733
+ raise typer.Exit(1)
734
+ targets = [rt for rt, _signal in detected]
735
+ elif runtime == "all":
736
+ targets = list(_HOOK_INSTALLERS)
737
+ elif runtime in _HOOK_INSTALLERS:
738
+ targets = [runtime]
739
+ else:
678
740
  typer.echo(
679
- f"Error: unknown runtime '{runtime}'. Supported: {sorted(_HOOK_INSTALLERS)}",
741
+ f"Error: unknown runtime '{runtime}'. Supported: {sorted(_HOOK_INSTALLERS)} or 'all'.",
680
742
  err=True,
681
743
  )
682
744
  raise typer.Exit(1)
683
745
 
684
- # Validate --genome BEFORE writing the hook. install-hook fails loud (unlike
685
- # the receipt CLI which silently falls through) because pinning a bad genome
686
- # would produce silent surprises every session-end until someone notices.
746
+ # Validate --genome BEFORE writing any hook. install-hook fails loud
747
+ # (unlike the receipt CLI which silently falls through) because pinning
748
+ # a bad genome would produce silent surprises every session-end until
749
+ # someone notices. Validate once even when targeting multiple runtimes.
687
750
  full_slug = ""
688
751
  if genome:
689
752
  full_slug = _normalize_genome_slug(genome)
@@ -698,7 +761,151 @@ def install_hook(
698
761
 
699
762
  hook_command = f"hyperweave session receipt --genome {full_slug}" if full_slug else "hyperweave session receipt"
700
763
 
701
- _HOOK_INSTALLERS[runtime](hook_command, full_slug)
764
+ for target in targets:
765
+ _HOOK_INSTALLERS[target](hook_command, full_slug)
766
+
767
+
768
+ def _doctor_runtime_status(runtime: str, home_dir: Path) -> str:
769
+ """Parse a runtime's hook config and return a one-line status string.
770
+
771
+ Returns ``✓`` when the hyperweave hook is wired correctly, ``✗`` when
772
+ the runtime is initialized but no hyperweave hook is registered, or
773
+ ``⚠`` when the wiring is partial (malformed config; codex missing the
774
+ [features] codex_hooks flag). The string is rendered verbatim by
775
+ ``doctor``.
776
+ """
777
+ import json
778
+
779
+ if runtime == "claude-code":
780
+ settings_path = home_dir / "settings.json"
781
+ if not settings_path.exists():
782
+ return (
783
+ f"✗ {runtime}: ~/.claude/ exists but no settings.json — "
784
+ f"run 'hyperweave install-hook --runtime {runtime}'"
785
+ )
786
+ try:
787
+ settings = json.loads(settings_path.read_text())
788
+ except json.JSONDecodeError:
789
+ return f"⚠ {runtime}: ~/.claude/settings.json is malformed"
790
+ for entry in settings.get("hooks", {}).get("SessionEnd", []) or []:
791
+ if not isinstance(entry, dict):
792
+ continue
793
+ for hook in entry.get("hooks", []) or []:
794
+ if not isinstance(hook, dict):
795
+ continue
796
+ cmd = str(hook.get("command", ""))
797
+ if "hyperweave session" in cmd:
798
+ return f"✓ {runtime}: hook registered — {cmd}"
799
+ return f"✗ {runtime}: initialized but no hyperweave hook — run 'hyperweave install-hook --runtime {runtime}'"
800
+
801
+ if runtime == "codex":
802
+ hooks_path = home_dir / "hooks.json"
803
+ config_path = home_dir / "config.toml"
804
+ registered_cmd: str | None = None
805
+ if hooks_path.exists():
806
+ try:
807
+ hooks = json.loads(hooks_path.read_text())
808
+ except json.JSONDecodeError:
809
+ return f"⚠ {runtime}: ~/.codex/hooks.json is malformed"
810
+ for entry in hooks.get("Stop", []) or []:
811
+ if not isinstance(entry, dict):
812
+ continue
813
+ cmd = str(entry.get("command", ""))
814
+ if "hyperweave session" in cmd:
815
+ registered_cmd = cmd
816
+ break
817
+ if not registered_cmd:
818
+ return (
819
+ f"✗ {runtime}: initialized but no hyperweave hook — run 'hyperweave install-hook --runtime {runtime}'"
820
+ )
821
+ # [features] codex_hooks = true must be present for the hook to fire;
822
+ # the install command writes it, but a hand-edited config could miss it.
823
+ feature_ok = False
824
+ if config_path.exists():
825
+ in_features = False
826
+ for line in config_path.read_text().splitlines():
827
+ stripped = line.strip()
828
+ if stripped == "[features]":
829
+ in_features = True
830
+ continue
831
+ if in_features and stripped.startswith("["):
832
+ in_features = False
833
+ continue
834
+ if in_features and stripped.startswith("codex_hooks") and "true" in stripped:
835
+ feature_ok = True
836
+ break
837
+ if not feature_ok:
838
+ return (
839
+ f"⚠ {runtime}: hook registered but [features] codex_hooks = true "
840
+ f"is missing — re-run 'hyperweave install-hook --runtime {runtime}'"
841
+ )
842
+ return f"✓ {runtime}: hook registered — {registered_cmd}"
843
+
844
+ return f"? {runtime}: unknown runtime"
845
+
846
+
847
+ @app.command()
848
+ def doctor() -> None:
849
+ """Diagnose hyperweave telemetry wiring across agent runtimes.
850
+
851
+ Reports per-runtime detection state (initialized / binary-only /
852
+ absent), hook registration status, transcript dir state, and recent
853
+ receipt activity in the current directory. Read-only — never
854
+ modifies any config. Always exits 0.
855
+ """
856
+ import shutil
857
+ from datetime import datetime, timedelta
858
+
859
+ from hyperweave import __version__
860
+
861
+ typer.echo(f"hyperweave doctor — v{__version__}")
862
+ typer.echo("")
863
+ typer.echo("Runtimes:")
864
+ for runtime, (dirname, binname) in _RUNTIME_DETECTION.items():
865
+ home_dir = Path.home() / dirname
866
+ if home_dir.exists():
867
+ typer.echo(f" {_doctor_runtime_status(runtime, home_dir)}")
868
+ elif bin_path := shutil.which(binname):
869
+ typer.echo(
870
+ f" ⚠ {runtime}: CLI on PATH at {bin_path} but ~/{dirname}/ "
871
+ f"not initialized — run '{binname}' once, then "
872
+ f"'hyperweave install-hook --runtime {runtime}'"
873
+ )
874
+ else:
875
+ typer.echo(f" ✗ {runtime}: not detected")
876
+
877
+ typer.echo("")
878
+ typer.echo("Transcripts:")
879
+ for runtime, subdir in (("claude-code", "projects"), ("codex", "sessions")):
880
+ dirname = _RUNTIME_DETECTION[runtime][0]
881
+ root = Path.home() / dirname / subdir
882
+ display_root = f"~/{dirname}/{subdir}"
883
+ if not root.exists():
884
+ typer.echo(f" {runtime}: {display_root} (not found)")
885
+ continue
886
+ files = list(root.rglob("*.jsonl"))
887
+ if not files:
888
+ typer.echo(f" {runtime}: {display_root}/ (empty)")
889
+ continue
890
+ most_recent = max(files, key=lambda p: p.stat().st_mtime)
891
+ mtime = datetime.fromtimestamp(most_recent.stat().st_mtime)
892
+ typer.echo(f" {runtime}: {len(files)} transcript(s), most recent {mtime:%Y-%m-%d %H:%M}")
893
+
894
+ typer.echo("")
895
+ typer.echo("Receipts (./.hyperweave/receipts/):")
896
+ receipts_dir = Path(".hyperweave") / "receipts"
897
+ if not receipts_dir.exists():
898
+ typer.echo(" (no receipts directory in cwd)")
899
+ return
900
+ svgs = [p for p in receipts_dir.iterdir() if p.is_file() and p.suffix == ".svg"]
901
+ if not svgs:
902
+ typer.echo(" (no receipts)")
903
+ return
904
+ cutoff = datetime.now() - timedelta(days=7)
905
+ recent = [p for p in svgs if datetime.fromtimestamp(p.stat().st_mtime) > cutoff]
906
+ most_recent = max(svgs, key=lambda p: p.stat().st_mtime)
907
+ typer.echo(f" {len(recent)} receipt(s) in last 7 days, {len(svgs)} total")
908
+ typer.echo(f" most recent: {most_recent.name}")
702
909
 
703
910
 
704
911
  @app.command("validate-genome")
@@ -0,0 +1,208 @@
1
+ """Coverage for the v0.3.4 ``hyperweave doctor`` diagnostic command.
2
+
3
+ Doctor is read-only — it never modifies any config. Assertions probe
4
+ the rendered stdout against fixture filesystem state set up under
5
+ ``tmp_path``. ``Path.home`` and ``shutil.which`` are stubbed so the
6
+ command never touches real ``~/.claude`` / ``~/.codex`` directories.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import json
12
+ import shutil
13
+ from pathlib import Path
14
+ from typing import TYPE_CHECKING, Any
15
+
16
+ from typer.testing import CliRunner
17
+
18
+ from hyperweave.cli import app
19
+
20
+ if TYPE_CHECKING:
21
+ from pytest import MonkeyPatch
22
+
23
+
24
+ def _patch_home(monkeypatch: MonkeyPatch, home: Path) -> None:
25
+ monkeypatch.setattr(Path, "home", staticmethod(lambda: home))
26
+
27
+
28
+ def _patch_which(monkeypatch: MonkeyPatch, binaries: dict[str, str | None]) -> None:
29
+ def _which(name: str, *_: Any, **__: Any) -> str | None:
30
+ return binaries.get(name)
31
+
32
+ monkeypatch.setattr(shutil, "which", _which)
33
+
34
+
35
+ def _write_claude_settings_with_hook(home: Path, command: str) -> None:
36
+ settings_dir = home / ".claude"
37
+ settings_dir.mkdir(parents=True, exist_ok=True)
38
+ settings = {"hooks": {"SessionEnd": [{"hooks": [{"type": "command", "command": command, "timeout": 10}]}]}}
39
+ (settings_dir / "settings.json").write_text(json.dumps(settings, indent=2))
40
+
41
+
42
+ def _write_codex_hook(
43
+ home: Path,
44
+ command: str,
45
+ *,
46
+ with_feature_flag: bool = True,
47
+ ) -> None:
48
+ codex_dir = home / ".codex"
49
+ codex_dir.mkdir(parents=True, exist_ok=True)
50
+ hooks = {"Stop": [{"type": "command", "command": command, "timeout": 10}]}
51
+ (codex_dir / "hooks.json").write_text(json.dumps(hooks, indent=2))
52
+ config_lines = ["[features]", "codex_hooks = true"] if with_feature_flag else ["[other]", "key = 1"]
53
+ (codex_dir / "config.toml").write_text("\n".join(config_lines) + "\n")
54
+
55
+
56
+ # ─────────────────────────────────────────────────────────────────────────────
57
+ # Doctor — runtime detection states
58
+ # ─────────────────────────────────────────────────────────────────────────────
59
+
60
+
61
+ def test_doctor_neither_runtime_detected(monkeypatch: MonkeyPatch, tmp_path: Path) -> None:
62
+ _patch_home(monkeypatch, tmp_path)
63
+ _patch_which(monkeypatch, {"claude": None, "codex": None})
64
+ monkeypatch.chdir(tmp_path)
65
+
66
+ runner = CliRunner()
67
+ result = runner.invoke(app, ["doctor"])
68
+ assert result.exit_code == 0
69
+ assert "✗ claude-code: not detected" in result.stdout
70
+ assert "✗ codex: not detected" in result.stdout
71
+
72
+
73
+ def test_doctor_codex_initialized_with_hook_and_feature_flag(monkeypatch: MonkeyPatch, tmp_path: Path) -> None:
74
+ _patch_home(monkeypatch, tmp_path)
75
+ _patch_which(monkeypatch, {"claude": None, "codex": None})
76
+ _write_codex_hook(tmp_path, "hyperweave session receipt --genome telemetry-voltage")
77
+ monkeypatch.chdir(tmp_path)
78
+
79
+ runner = CliRunner()
80
+ result = runner.invoke(app, ["doctor"])
81
+ assert result.exit_code == 0
82
+ assert "✓ codex: hook registered" in result.stdout
83
+ assert "hyperweave session receipt --genome telemetry-voltage" in result.stdout
84
+
85
+
86
+ def test_doctor_codex_initialized_but_no_hook(monkeypatch: MonkeyPatch, tmp_path: Path) -> None:
87
+ """The user's actual bug scenario: ~/.codex exists but no hyperweave hook."""
88
+ _patch_home(monkeypatch, tmp_path)
89
+ _patch_which(monkeypatch, {"claude": None, "codex": None})
90
+ (tmp_path / ".codex").mkdir()
91
+
92
+ monkeypatch.chdir(tmp_path)
93
+
94
+ runner = CliRunner()
95
+ result = runner.invoke(app, ["doctor"])
96
+ assert result.exit_code == 0
97
+ assert "✗ codex: initialized but no hyperweave hook" in result.stdout
98
+ assert "hyperweave install-hook --runtime codex" in result.stdout
99
+
100
+
101
+ def test_doctor_codex_hook_registered_but_feature_flag_missing(monkeypatch: MonkeyPatch, tmp_path: Path) -> None:
102
+ """Codex Stop hook only fires when [features] codex_hooks = true is set."""
103
+ _patch_home(monkeypatch, tmp_path)
104
+ _patch_which(monkeypatch, {"claude": None, "codex": None})
105
+ _write_codex_hook(tmp_path, "hyperweave session receipt", with_feature_flag=False)
106
+ monkeypatch.chdir(tmp_path)
107
+
108
+ runner = CliRunner()
109
+ result = runner.invoke(app, ["doctor"])
110
+ assert result.exit_code == 0
111
+ assert "⚠ codex" in result.stdout
112
+ assert "codex_hooks" in result.stdout
113
+
114
+
115
+ def test_doctor_codex_binary_only_state(monkeypatch: MonkeyPatch, tmp_path: Path) -> None:
116
+ """Fresh Codex install: CLI is on PATH but ~/.codex/ hasn't been created."""
117
+ _patch_home(monkeypatch, tmp_path)
118
+ _patch_which(monkeypatch, {"claude": None, "codex": "/usr/local/bin/codex"})
119
+ monkeypatch.chdir(tmp_path)
120
+
121
+ runner = CliRunner()
122
+ result = runner.invoke(app, ["doctor"])
123
+ assert result.exit_code == 0
124
+ assert "⚠ codex: CLI on PATH at /usr/local/bin/codex" in result.stdout
125
+ assert "not initialized" in result.stdout
126
+
127
+
128
+ def test_doctor_both_runtimes_initialized_with_hooks(monkeypatch: MonkeyPatch, tmp_path: Path) -> None:
129
+ _patch_home(monkeypatch, tmp_path)
130
+ _patch_which(monkeypatch, {"claude": None, "codex": None})
131
+ _write_claude_settings_with_hook(tmp_path, "hyperweave session receipt")
132
+ _write_codex_hook(tmp_path, "hyperweave session receipt")
133
+ monkeypatch.chdir(tmp_path)
134
+
135
+ runner = CliRunner()
136
+ result = runner.invoke(app, ["doctor"])
137
+ assert result.exit_code == 0
138
+ assert "✓ claude-code: hook registered" in result.stdout
139
+ assert "✓ codex: hook registered" in result.stdout
140
+
141
+
142
+ # ─────────────────────────────────────────────────────────────────────────────
143
+ # Doctor — transcripts + receipts sections
144
+ # ─────────────────────────────────────────────────────────────────────────────
145
+
146
+
147
+ def test_doctor_reports_transcript_counts_when_present(monkeypatch: MonkeyPatch, tmp_path: Path) -> None:
148
+ _patch_home(monkeypatch, tmp_path)
149
+ _patch_which(monkeypatch, {"claude": None, "codex": None})
150
+
151
+ codex_sessions = tmp_path / ".codex" / "sessions" / "2026" / "05"
152
+ codex_sessions.mkdir(parents=True)
153
+ (codex_sessions / "rollout-a.jsonl").write_text("{}\n")
154
+ (codex_sessions / "rollout-b.jsonl").write_text("{}\n")
155
+
156
+ monkeypatch.chdir(tmp_path)
157
+ runner = CliRunner()
158
+ result = runner.invoke(app, ["doctor"])
159
+ assert result.exit_code == 0
160
+ assert "codex: 2 transcript(s)" in result.stdout
161
+
162
+
163
+ def test_doctor_reports_receipt_count_when_directory_exists(monkeypatch: MonkeyPatch, tmp_path: Path) -> None:
164
+ _patch_home(monkeypatch, tmp_path)
165
+ _patch_which(monkeypatch, {"claude": None, "codex": None})
166
+
167
+ receipts_dir = tmp_path / ".hyperweave" / "receipts"
168
+ receipts_dir.mkdir(parents=True)
169
+ (receipts_dir / "20260513_test_one.svg").write_text("<svg/>")
170
+ (receipts_dir / "20260513_test_two.svg").write_text("<svg/>")
171
+
172
+ monkeypatch.chdir(tmp_path)
173
+ runner = CliRunner()
174
+ result = runner.invoke(app, ["doctor"])
175
+ assert result.exit_code == 0
176
+ assert "2 receipt(s) in last 7 days, 2 total" in result.stdout
177
+ # One of the two filenames surfaces as the most-recent line.
178
+ assert "most recent: 20260513_test_" in result.stdout
179
+
180
+
181
+ def test_doctor_reports_no_receipts_directory(monkeypatch: MonkeyPatch, tmp_path: Path) -> None:
182
+ _patch_home(monkeypatch, tmp_path)
183
+ _patch_which(monkeypatch, {"claude": None, "codex": None})
184
+ monkeypatch.chdir(tmp_path)
185
+
186
+ runner = CliRunner()
187
+ result = runner.invoke(app, ["doctor"])
188
+ assert result.exit_code == 0
189
+ assert "no receipts directory in cwd" in result.stdout
190
+
191
+
192
+ def test_doctor_always_exits_zero(monkeypatch: MonkeyPatch, tmp_path: Path) -> None:
193
+ """Doctor is purely diagnostic — broken state must not exit non-zero."""
194
+ _patch_home(monkeypatch, tmp_path)
195
+ _patch_which(monkeypatch, {"claude": None, "codex": None})
196
+
197
+ # Malformed claude settings.json + codex hooks.json should not crash.
198
+ (tmp_path / ".claude").mkdir()
199
+ (tmp_path / ".claude" / "settings.json").write_text("not json")
200
+ (tmp_path / ".codex").mkdir()
201
+ (tmp_path / ".codex" / "hooks.json").write_text("not json")
202
+
203
+ monkeypatch.chdir(tmp_path)
204
+ runner = CliRunner()
205
+ result = runner.invoke(app, ["doctor"])
206
+ assert result.exit_code == 0
207
+ # Both runtimes report the malformed state via ⚠ markers, not crashes.
208
+ assert "malformed" in result.stdout