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.
- {hyperweave-0.3.3 → hyperweave-0.3.4}/CHANGELOG.md +21 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/PKG-INFO +1 -1
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/_version.py +2 -2
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/cli.py +234 -27
- hyperweave-0.3.4/tests/test_doctor.py +208 -0
- hyperweave-0.3.4/tests/test_install_hook.py +233 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_telemetry_integration.py +11 -10
- {hyperweave-0.3.3 → hyperweave-0.3.4}/.dockerignore +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/.github/workflows/ci.yml +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/.github/workflows/deploy.yml +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/.github/workflows/publish.yml +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/.gitignore +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/.pre-commit-config.yaml +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/Dockerfile +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/LICENSE +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/README.md +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/buttons/button-liquid.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/cards/card-butterfly.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/cards/card-python.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/cards/card-sunflower.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/cards/card-waves.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/brutalist-emerald/badge_critical.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/brutalist-emerald/badge_passing.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/brutalist-emerald/badge_warning.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/brutalist-emerald/banner.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/brutalist-emerald/icons/discord.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/brutalist-emerald/icons/notion.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/brutalist-emerald/icons/reddit.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/brutalist-emerald/icons/spotify.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/brutalist-emerald/icons/youtube.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/brutalist-emerald/marquee_counter.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/brutalist-emerald/marquee_horizontal.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/brutalist-emerald/marquee_vertical.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/brutalist-emerald/profile-cards/chart_stars_full.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/brutalist-emerald/profile-cards/stats.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/brutalist-emerald/strip.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/chrome-horizon/badge_critical.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/chrome-horizon/badge_passing.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/chrome-horizon/badge_warning.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/chrome-horizon/banner.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/chrome-horizon/icons/bluesky.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/chrome-horizon/icons/github.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/chrome-horizon/icons/instagram.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/chrome-horizon/icons/mastodon.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/chrome-horizon/icons/x.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/chrome-horizon/marquee_counter.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/chrome-horizon/marquee_horizontal.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/chrome-horizon/marquee_vertical.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/chrome-horizon/profile-cards/chart_stars_full.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/chrome-horizon/profile-cards/stats.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/chrome-horizon/strip.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/telemetry/master_card.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/telemetry/receipt.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/telemetry/receipt_claude-code_medium.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/telemetry/receipt_codex_large.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/telemetry/receipt_voltage_xlarge.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/telemetry/rhythm_strip.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/examples/telemetry/rhythm_strip_voltage_xlarge.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/footers/inneraura-footer-liquid.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/footers/inneraura-footer-purple.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/footers/inneraura-footer.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/hyperweave-banner.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/icons/cobalt-sapphire-discord.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/icons/cobalt-sapphire-docs.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/icons/cobalt-sapphire-github.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/icons/cobalt-sapphire-instagram.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/icons/cobalt-sapphire-linkedin.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/icons/cobalt-sapphire-tiktok.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/icons/cobalt-sapphire-x.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/icons/cobalt-sapphire-youtube.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/marquees/badge-showcase-triple.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/marquees/genome-marquee-triple.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/marquees/sample-badges.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/mintlify-assets/404.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/mintlify-assets/callout-icons.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/mintlify-assets/divider.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/mintlify-assets/favicon.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/mintlify-assets/hero-banner.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/mintlify-assets/hyperweave-banner-v2.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/mintlify-assets/hyperweave-navbar-logo.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/mintlify-assets/loader.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/mintlify-assets/og-image.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/assets/timelines/hyperweave-roadmap.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/docs/assets/favicon.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/docs/assets/hyperweave-banner.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/docs/assets/hyperweave-navbar-logo.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/docs/assets/og-image.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/docs/explanation/architecture.mdx +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/docs/explanation/camo-compatibility.mdx +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/docs/explanation/cim-compliance.mdx +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/docs/explanation/genome-profile-system.mdx +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/docs/explanation/metadata-tiers.mdx +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/docs/how-to/add-motion-to-badges.mdx +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/docs/how-to/create-session-receipts.mdx +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/docs/how-to/set-up-claude-code-hooks.mdx +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/docs/how-to/use-live-data-badges.mdx +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/docs/introduction.mdx +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/docs/mint.json +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/docs/quickstart.mdx +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/docs/reference/cli.mdx +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/docs/reference/compose-spec.mdx +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/docs/reference/genomes.mdx +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/docs/reference/http-api.mdx +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/docs/reference/mcp-tools.mdx +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/docs/reference/motions.mdx +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/docs/reference/telemetry-contract.mdx +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/docs/spec/hyperweave-protocol.mdx +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/docs/tutorials/build-an-artifact-kit.mdx +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/docs/tutorials/compose-your-first-badge.mdx +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/docs/tutorials/install-session-telemetry.mdx +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/fly.toml +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/hooks/install.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/hooks/session_end.sh +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/justfile +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/pyproject.toml +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/scripts/extract_font_metrics.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/scripts/extract_glyphs.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/scripts/generate_proofset.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/scripts/probe_live_stats.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/scripts/probe_star_history.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/scripts/stress_test.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/__init__.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/__main__.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/compose/__init__.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/compose/assembler.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/compose/bar_chart.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/compose/context.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/compose/engine.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/compose/lanes.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/compose/layout.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/compose/palette.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/compose/reasoning.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/compose/resolver.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/compose/resolvers/__init__.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/compose/resolvers/chart.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/compose/resolvers/stats.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/compose/rhythm.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/compose/rhythm_strip.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/compose/treemap.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/compose/validate_paradigms.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/config/__init__.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/config/genome_validator.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/config/loader.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/config/registry.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/config/settings.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/connectors/__init__.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/connectors/arxiv.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/connectors/base.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/connectors/cache.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/connectors/github.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/connectors/rest.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/core/__init__.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/core/cell_layout.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/core/color.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/core/contracts.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/core/enums.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/core/font_metrics.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/core/models.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/core/paradigm.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/core/schema.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/core/state.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/core/text.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/core/thresholds.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/badge_modes.yaml +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/css/accessibility.css +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/css/bridge.css +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/css/expression.css +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/css/status.css +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/font-metrics/chakra-petch.json +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/font-metrics/inter.json +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/font-metrics/jetbrains-mono.json +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/font-metrics/orbitron.json +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/fonts/barlow-condensed-700.b64 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/fonts/barlow-condensed-700.meta.json +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/fonts/barlow-condensed-900.b64 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/fonts/barlow-condensed-900.meta.json +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/fonts/chakra-petch.b64 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/fonts/chakra-petch.meta.json +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/fonts/jetbrains-mono.b64 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/fonts/jetbrains-mono.meta.json +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/fonts/orbitron.b64 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/fonts/orbitron.meta.json +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/genomes/automata.json +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/genomes/brutalist.json +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/genomes/chrome.json +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/genomes/telemetry-claude-code.json +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/genomes/telemetry-codex.json +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/genomes/telemetry-cream.json +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/genomes/telemetry-voltage.json +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/glyphs.json +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/motions/border/chromatic-pulse.yaml +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/motions/border/corner-trace.yaml +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/motions/border/dual-orbit.yaml +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/motions/border/entanglement.yaml +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/motions/border/rimrun.yaml +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/motions/static.yaml +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/paradigms/brutalist.yaml +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/paradigms/cellular.yaml +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/paradigms/chrome.yaml +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/paradigms/default.yaml +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/policies/normal.json +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/policies/permissive.json +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/policies/ungoverned.json +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/profiles/brutalist.contract.json +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/profiles/brutalist.yaml +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/profiles/chrome.contract.json +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/profiles/chrome.yaml +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/reasoning/__init__.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/reasoning/brutalist.yaml +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/specimens.yaml +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/telemetry/model-pricing.yaml +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/telemetry/runtimes/claude-code.yaml +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/telemetry/runtimes/codex.yaml +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/telemetry/stage-config.yaml +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/telemetry/stage-labels.yaml +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/telemetry/tool-colors.yaml +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/terminals/arrow.json +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/terminals/aurora.json +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/terminals/beacon.json +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/terminals/bracket3d.json +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/terminals/chevron.json +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/terminals/crosshair.json +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/terminals/diamond.json +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/terminals/rocket.json +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/terminals/rules/bar.json +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/terminals/rules/dashed.json +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/terminals/rules/five-wave.json +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/terminals/rules/spectral.json +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/terminals/rules/straight.json +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/terminals/rules/wave.json +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/data/terminals/stijl.json +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/kit.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/mcp/__init__.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/mcp/__main__.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/mcp/server.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/py.typed +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/render/__init__.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/render/chart_engine.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/render/fonts.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/render/glyphs.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/render/motion.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/render/templates.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/serve/__init__.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/serve/app.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/serve/data_tokens.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/telemetry/__init__.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/telemetry/capture.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/telemetry/codex_parser.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/telemetry/contract.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/telemetry/corrections.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/telemetry/cost.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/telemetry/models.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/telemetry/parser.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/telemetry/receipt_paths.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/telemetry/runtimes.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/telemetry/stages.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/components/chart-area.svg.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/components/chart-axes.svg.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/components/chart-empty-state.svg.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/components/chart-gridlines.svg.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/components/chart-markers/circle.svg.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/components/chart-markers/diamond.svg.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/components/chart-markers/endpoint-diamond.svg.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/components/chart-markers/endpoint-rect.svg.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/components/chart-markers/rect.svg.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/components/chart-milestone-brutalist.svg.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/components/chart-milestone.svg.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/components/chart-polyline.svg.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/components/filter.svg.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/components/glyph-inline.svg.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/components/glyph.svg.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/components/gradient.svg.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/components/metadata.svg.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/components/metric.svg.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/components/phase-segment.svg.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/components/rule.svg.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/components/status.svg.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/components/terminal.svg.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/document.svg.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/error-badge.svg.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/badge/brutalist-content.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/badge/brutalist-dark-content.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/badge/brutalist-defs.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/badge/brutalist-light-content.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/badge/cellular-content.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/badge/cellular-defs.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/badge/chrome-content.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/badge/chrome-defs.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/badge/default-content.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/badge/default-defs.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/badge.svg.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/catalog.svg.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/chart/brutalist-content.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/chart/brutalist-dark-content.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/chart/brutalist-defs.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/chart/brutalist-light-content.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/chart/cellular-content.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/chart/cellular-defs.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/chart/chrome-content.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/chart/chrome-defs.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/chart.svg.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/divider/brutalist-seam.svg.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/divider/chrome-band.svg.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/divider.svg.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/icon/brutalist-content.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/icon/brutalist-defs.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/icon/cellular-content.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/icon/cellular-defs.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/icon/chrome-content.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/icon/chrome-defs.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/icon/default-content.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/icon/default-defs.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/icon.svg.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/marquee-horizontal/brutalist-content.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/marquee-horizontal/brutalist-defs.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/marquee-horizontal/brutalist-overlay.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/marquee-horizontal/cellular-content.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/marquee-horizontal/cellular-defs.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/marquee-horizontal/cellular-overlay.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/marquee-horizontal/chrome-content.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/marquee-horizontal/chrome-defs.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/marquee-horizontal/chrome-overlay.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/marquee-horizontal/default-content.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/marquee-horizontal/default-defs.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/marquee-horizontal.svg.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/master-card.svg.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/receipt.svg.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/rhythm-strip.svg.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/stats/brutalist-content.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/stats/brutalist-dark-content.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/stats/brutalist-defs.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/stats/brutalist-light-content.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/stats/cellular-content.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/stats/cellular-defs.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/stats/chrome-content.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/stats/chrome-defs.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/stats.svg.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/strip/brutalist-content.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/strip/brutalist-dark-content.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/strip/brutalist-defs.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/strip/brutalist-light-content.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/strip/brutalist-status.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/strip/cellular-content.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/strip/cellular-defs.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/strip/cellular-status.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/strip/chrome-content.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/strip/chrome-defs.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/strip/chrome-status.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/strip/default-content.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/strip/default-defs.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/strip/default-status.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/frames/strip.svg.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/motions/border/chromatic-pulse.svg.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/motions/border/corner-trace.svg.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/motions/border/dual-orbit.svg.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/motions/border/entanglement.svg.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/motions/border/rimrun.svg.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/partials/provider-glyphs.svg.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/src/hyperweave/templates/partials/state-signal-cascade.j2 +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/__init__.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/conftest.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/fixtures/codex_session.jsonl +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/fixtures/codex_session_patches.jsonl +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/fixtures/github_contributions/synthetic.html +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/fixtures/session.json +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/fixtures/session.jsonl +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/fixtures/synthetic_session.jsonl +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/helpers.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/snapshots/url_stability/divider_band_chrome_static.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/snapshots/url_stability/icon_github_chrome_static.svg +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_assembler.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_badge_brutalist_dark.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_badge_cellular.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_badge_layout.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_badge_mode.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_chart_engine.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_chart_frame.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_chromatic_coverage_validator.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_chrome_variants.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_codex_parser.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_compose_bar_chart.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_compose_rhythm_strip.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_compose_treemap.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_compose_variant_field.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_connectors.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_core.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_data_tokens.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_divider_cellular.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_divider_genome_specific.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_font_gating.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_font_metrics_chakra.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_genome_automata.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_github_scrape.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_kit.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_marquee_v0_2_16.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_mcp.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_paradigm_cellular.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_paradigm_dispatch.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_paradigm_extensibility.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_parse_transcript_auto.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_proofset.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_receipt_paths.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_receipt_token_compliance.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_render.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_resolver_rhythm.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_runtime_registries.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_serve.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_serve_live_state.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_slot_metric_state.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_state_inference.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_stats_brutalist.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_stats_card.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_strip_brutalist_grammar.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_strip_cellular.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_strip_status_toggle.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_telemetry.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_telemetry_contract_per_stage.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_telemetry_skin_dispatch.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_tool_class_completeness.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_url_stability.py +0 -0
- {hyperweave-0.3.3 → hyperweave-0.3.4}/tests/test_variant_default_resolution.py +0 -0
- {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
|
+
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.
|
|
22
|
-
__version_tuple__ = version_tuple = (0, 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
|
|
367
|
-
#
|
|
368
|
-
#
|
|
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
|
|
397
|
+
filename_hint = str(output)
|
|
394
398
|
elif action == "receipt" and output:
|
|
395
|
-
# Explicit --output:
|
|
396
|
-
filename_hint = output
|
|
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 (
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
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 —
|
|
632
|
-
"
|
|
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.
|
|
666
|
-
"
|
|
667
|
-
"
|
|
668
|
-
"
|
|
669
|
-
"
|
|
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
|
-
] = "
|
|
709
|
+
] = "",
|
|
673
710
|
) -> None:
|
|
674
|
-
"""Install
|
|
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
|
-
|
|
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
|
|
685
|
-
# the receipt CLI which silently falls through) because pinning
|
|
686
|
-
# would produce silent surprises every session-end until
|
|
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
|
-
|
|
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
|