voodoo-framework 2.8.0__tar.gz → 2.8.2__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.
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/PKG-INFO +1 -1
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/__init__.py +1 -1
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/core/app.py +8 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/ui/__init__.py +1 -1
- voodoo_framework-2.8.2/src/voodoo/ui/brand.py +137 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/ui/rendering.py +4 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo_framework.egg-info/PKG-INFO +1 -1
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo_framework.egg-info/SOURCES.txt +3 -0
- voodoo_framework-2.8.2/tests/test_brand.py +61 -0
- voodoo_framework-2.8.2/tests/test_public_assets.py +48 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/LICENSE +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/README.md +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/pyproject.toml +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/setup.cfg +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/adapters/__init__.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/adapters/capabilities.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/adapters/registry.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/adapters/tailwind.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/adapters/voodoo_css.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/agent.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/agents/__init__.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/agents/models.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/agents/registry.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/ai/__init__.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/ai/agent.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/ai/agent_legacy.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/ai/agent_runtime_truth.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/ai/providers/__init__.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/ai/providers/anthropic.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/ai/providers/gemini.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/ai/providers/mock.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/ai/providers/ollama.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/ai/providers/openai.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/ai/tools/__init__.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/ai/tools/registry.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/api.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/auth/__init__.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/auth/cookies.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/auth/guards.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/auth/jwt.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/auth/middleware.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/auth/passwords.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/auth/user.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/cli/__init__.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/cli/__main__.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/cli/agents.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/cli/ai.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/cli/approvals.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/cli/auth.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/cli/create.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/cli/dev.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/cli/doctor.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/cli/executions.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/cli/fabric.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/cli/generate.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/cli/inspect.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/cli/new.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/cli/objects.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/cli/protocol.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/cli/recover.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/cli/routes.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/cli/scaffolding.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/cli/schedules.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/cli/status.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/cli/tasks.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/cli/terminal.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/cli/theme.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/cli/version.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/cli/workers_cmd.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/components.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/config.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/core/__init__.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/core/errors.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/core/events.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/core/render.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/core/routing.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/core/sitemap.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/core/state.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/data/__init__.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/data/base.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/data/model.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/data/store_backend.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/data/store_facade.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/data/store_model.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/edge/__init__.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/edge/auth.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/edge/errors.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/edge/gateway.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/edge/http.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/edge/models.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/edge/mqtt.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/edge/protocol.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/edge/simulator.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/edge/store.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/edge/store_voodoo.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/edge/world.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/i18n.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/mcp/__init__.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/mcp/client.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/memory/__init__.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/memory/interfaces.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/memory/sqlite.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/mesh/__init__.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/mesh/auth.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/mesh/client.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/mesh/event_bus.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/mesh/remote.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/mesh/replay.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/primitives/__init__.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/primitives/capability.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/primitives/compute.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/primitives/constraint.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/primitives/effect.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/primitives/intent.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/primitives/resource.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/primitives/state.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/primitives/time.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/protocol/__init__.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/protocol/export.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/protocol/fabric.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/protocol/operational.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/protocol/schemas.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/py.typed +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/queue.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/routing/api.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/routing/pages.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/runtime/__init__.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/runtime/adaptive.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/runtime/capability.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/runtime/constraint.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/runtime/context.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/runtime/dashboard.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/runtime/engine.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/runtime/errors.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/runtime/execution.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/runtime/fabric.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/runtime/goal.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/runtime/goal_store.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/runtime/graph.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/runtime/human.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/runtime/identity.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/runtime/identity_store.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/runtime/membership.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/runtime/operations.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/runtime/persistence.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/runtime/planner.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/runtime/policy.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/runtime/scheduler.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/runtime/store.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/runtime/task.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/runtime/transaction.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/runtime/workflow.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/runtime/workflow_store.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/runtime/world_execution.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/schedule.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/security/__init__.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/security/cors.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/security/csrf.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/security/headers.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/security/passwords.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/security/rate_limit.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/security/redaction.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/security/secrets.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/seo.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/static/client.js +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/status.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/__init__.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/cache/__init__.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/cache/interfaces.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/cache/memory.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/cache/redis.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/database/__init__.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/database/interfaces.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/database/postgres.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/database/sqlite.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/events/__init__.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/events/interfaces.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/events/local.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/events/postgres.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/events/sqlite.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/events/store.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/execution/__init__.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/execution/migrations.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/execution/postgres.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/execution/sqlite.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/execution/store.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/manager.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/objects/__init__.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/objects/interfaces.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/objects/local.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/objects/s3.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/objects/store.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/queue/__init__.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/queue/interfaces.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/queue/memory.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/queue/postgres.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/queue/redis.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/queue/sqlite.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/queue/store.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/scheduler/__init__.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/scheduler/sqlite.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/scheduler/store.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/telemetry/__init__.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/telemetry/api.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/telemetry/middleware.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/telemetry/otlp.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/telemetry/store.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/theme.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/tools/__init__.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/tools/registry.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/ui/component.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/ui/events.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/ui/interactive.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/ui/layout.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/ui/library.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/ui/markdown.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/ui/primitives.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/ui/product.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/ui/state.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/ui/styles/__init__.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/ui/styles/presets.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/ui/styles/product.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/ui/styles/system.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/ui/styles/theme.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/ui/styles/theme_contract.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/ui/styles/voodoo_system.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/ui/voodoo_system.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/workers/__init__.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/workers/queue.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/world/__init__.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/world/model.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/world/models.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/world/sqlite.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/world/store.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo_framework.egg-info/dependency_links.txt +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo_framework.egg-info/entry_points.txt +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo_framework.egg-info/requires.txt +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo_framework.egg-info/top_level.txt +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_adaptive_agency_correctness.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_agency_runtime_truth.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_agent.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_agent_registry.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_agent_runtime.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_app.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_auth.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_capability_security.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_checkpoint_resume.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_chrome.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_cli.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_cli_fabric.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_cli_inspect.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_components.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_config.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_contract_api.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_create.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_create_store_smoke.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_data.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_design_system.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_design_system2.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_design_system_premium.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_design_system_theme_contract.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_durable_goal_runtime.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_durable_hitl.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_durable_workflow_runtime.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_edge_device.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_edge_e2e.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_edge_gateway.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_edge_http.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_edge_protocol.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_edge_security.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_edge_voodoo_store.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_edge_world.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_events.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_execution_sqlite_store.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_goal_runtime.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_hitl_persistence_correctness.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_http_runtime.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_human.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_i18n.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_identity_execution.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_identity_foundation.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_integration.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_mcp.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_mcp_runtime.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_memory.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_mesh.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_mesh_event_bus.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_mesh_remote_auth.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_mesh_remote_authority.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_mesh_remote_execution.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_mesh_remote_outcomes.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_mesh_remote_replay.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_mesh_two_node_acceptance.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_model.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_node_membership.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_object_store.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_observability.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_operational_policy.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_operational_runtime_ui.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_persistence.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_planner_adaptive.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_primitives.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_product_components.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_protocol.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_protocol_fabric.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_protocol_operational.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_provider_switching.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_providers.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_public_api_3.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_queue.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_reactive.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_runtime.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_runtime_correctness.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_runtime_fabric.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_runtime_store_app_lifecycle.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_runtime_store_lifecycle.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_runtime_store_provider.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_runtime_transaction.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_scheduler.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_security.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_seo.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_sprint27_convergence.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_sprint28_acceptance.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_state.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_store_first_user_journey.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_store_model_backend.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_store_only_core_import.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_theme.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_theme_presets.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_tools.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_ui.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_ui_magic.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_ui_magic_acceptance.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_voodoo_store_events.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_voodoo_store_execution.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_voodoo_store_hitl_restart.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_voodoo_store_queue.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_voodoo_store_scheduler.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_voodoo_system_components.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_websocket.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_worker_retry_semantics.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_workers.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_world_aware_execution.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_world_model.py +0 -0
- {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_world_sqlite.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: voodoo-framework
|
|
3
|
-
Version: 2.8.
|
|
3
|
+
Version: 2.8.2
|
|
4
4
|
Summary: The programmable runtime for adaptive applications and operational systems — web, APIs, agents, workers, human workflows, distributed systems, and physical systems in one runtime.
|
|
5
5
|
Author-email: Helder Perez <contact@helderperez.com>
|
|
6
6
|
Maintainer-email: Helder Perez <contact@helderperez.com>
|
|
@@ -355,6 +355,14 @@ def create_app(app_dir: str = "app") -> Starlette: # noqa: C901
|
|
|
355
355
|
Middleware(AuthMiddleware),
|
|
356
356
|
]
|
|
357
357
|
|
|
358
|
+
# ``public/`` is the filesystem root for static assets, not part of their
|
|
359
|
+
# public URL. Keep the explicit ``/public`` mount above for 2.x compatibility,
|
|
360
|
+
# then add a root mount last so application/runtime routes always win.
|
|
361
|
+
if os.path.isdir(public_dir):
|
|
362
|
+
routes.append(
|
|
363
|
+
Mount("/", app=StaticFiles(directory=public_dir), name="public-root")
|
|
364
|
+
)
|
|
365
|
+
|
|
358
366
|
app = Starlette(
|
|
359
367
|
debug=config.debug,
|
|
360
368
|
routes=routes,
|
|
@@ -12,6 +12,7 @@ Voodoo::
|
|
|
12
12
|
Button("Save", on_click=save)
|
|
13
13
|
"""
|
|
14
14
|
|
|
15
|
+
from voodoo.ui.brand import Brand
|
|
15
16
|
from voodoo.ui.component import Component, Html, escape, tone_to_color_var
|
|
16
17
|
from voodoo.ui.events import UIEvent
|
|
17
18
|
from voodoo.ui.interactive import (
|
|
@@ -36,7 +37,6 @@ from voodoo.ui.library import (
|
|
|
36
37
|
BackLink,
|
|
37
38
|
Badge,
|
|
38
39
|
Box,
|
|
39
|
-
Brand,
|
|
40
40
|
Card,
|
|
41
41
|
ChatBox,
|
|
42
42
|
ChatMessage,
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"""Branding primitives for logos and wordmarks.
|
|
2
|
+
|
|
3
|
+
``Brand`` preserves the existing child-based API while adding a first-class
|
|
4
|
+
image mode that can switch logo assets with the active light/dark theme.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
from voodoo.ui.component import Component
|
|
12
|
+
|
|
13
|
+
BRAND_CSS = """
|
|
14
|
+
/* Brand image contract */
|
|
15
|
+
.vd-brand-logo {
|
|
16
|
+
display: block;
|
|
17
|
+
max-width: 100%;
|
|
18
|
+
height: auto;
|
|
19
|
+
border-radius: 0 !important;
|
|
20
|
+
}
|
|
21
|
+
.vd-brand-logo--light { display: block; }
|
|
22
|
+
.vd-brand-logo--dark { display: none; }
|
|
23
|
+
.dark .vd-brand-logo--light { display: none; }
|
|
24
|
+
.dark .vd-brand-logo--dark { display: block; }
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class _BrandLogo(Component):
|
|
29
|
+
"""Internal logo image with no generic ``Img`` presentation styles."""
|
|
30
|
+
|
|
31
|
+
tag = "img"
|
|
32
|
+
auto_id = False
|
|
33
|
+
|
|
34
|
+
def __init__(
|
|
35
|
+
self,
|
|
36
|
+
*,
|
|
37
|
+
src: str,
|
|
38
|
+
alt: str,
|
|
39
|
+
variant: str | None = None,
|
|
40
|
+
width: str | int | None = None,
|
|
41
|
+
height: str | int | None = None,
|
|
42
|
+
) -> None:
|
|
43
|
+
classes = "vd-brand-logo"
|
|
44
|
+
if variant:
|
|
45
|
+
classes += f" vd-brand-logo--{variant}"
|
|
46
|
+
super().__init__(class_=classes)
|
|
47
|
+
self.attrs["src"] = src
|
|
48
|
+
self.attrs["alt"] = alt
|
|
49
|
+
if width is not None:
|
|
50
|
+
self.attrs["width"] = width
|
|
51
|
+
if height is not None:
|
|
52
|
+
self.attrs["height"] = height
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class Brand(Component):
|
|
56
|
+
"""Brand link supporting either child content or theme-aware logo assets.
|
|
57
|
+
|
|
58
|
+
Existing usage remains valid::
|
|
59
|
+
|
|
60
|
+
Brand("Acme", href="/")
|
|
61
|
+
Brand(Img(src="/logo.png", alt="Acme"), href="/")
|
|
62
|
+
|
|
63
|
+
Image mode keeps branding free of generic image presentation styles and
|
|
64
|
+
automatically selects the correct asset for the active theme::
|
|
65
|
+
|
|
66
|
+
Brand(
|
|
67
|
+
light="/logo-black.png",
|
|
68
|
+
dark="/logo-white.png",
|
|
69
|
+
alt="Acme",
|
|
70
|
+
width=160,
|
|
71
|
+
href="/",
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
When only ``light`` or ``dark`` is supplied, that asset is used for both
|
|
75
|
+
themes. Image mode and explicit children are intentionally mutually
|
|
76
|
+
exclusive so the rendered brand stays unambiguous.
|
|
77
|
+
"""
|
|
78
|
+
|
|
79
|
+
tag = "a"
|
|
80
|
+
style = "brand"
|
|
81
|
+
|
|
82
|
+
def __init__(
|
|
83
|
+
self,
|
|
84
|
+
*children: Any,
|
|
85
|
+
href: str = "/",
|
|
86
|
+
light: str | None = None,
|
|
87
|
+
dark: str | None = None,
|
|
88
|
+
alt: str = "",
|
|
89
|
+
width: str | int | None = None,
|
|
90
|
+
height: str | int | None = None,
|
|
91
|
+
**kwargs: Any,
|
|
92
|
+
) -> None:
|
|
93
|
+
image_mode = light is not None or dark is not None
|
|
94
|
+
if image_mode and children:
|
|
95
|
+
raise ValueError(
|
|
96
|
+
"Brand image mode cannot be combined with child content. "
|
|
97
|
+
"Use either Brand(...children) or Brand(light=..., dark=...)."
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
super().__init__(*children, **kwargs)
|
|
101
|
+
self.attrs["href"] = href
|
|
102
|
+
|
|
103
|
+
if not image_mode:
|
|
104
|
+
return
|
|
105
|
+
|
|
106
|
+
light_src = light or dark
|
|
107
|
+
dark_src = dark or light
|
|
108
|
+
assert light_src is not None
|
|
109
|
+
assert dark_src is not None
|
|
110
|
+
|
|
111
|
+
if light_src == dark_src:
|
|
112
|
+
self.children = (
|
|
113
|
+
_BrandLogo(
|
|
114
|
+
src=light_src,
|
|
115
|
+
alt=alt,
|
|
116
|
+
width=width,
|
|
117
|
+
height=height,
|
|
118
|
+
),
|
|
119
|
+
)
|
|
120
|
+
return
|
|
121
|
+
|
|
122
|
+
self.children = (
|
|
123
|
+
_BrandLogo(
|
|
124
|
+
src=light_src,
|
|
125
|
+
alt=alt,
|
|
126
|
+
variant="light",
|
|
127
|
+
width=width,
|
|
128
|
+
height=height,
|
|
129
|
+
),
|
|
130
|
+
_BrandLogo(
|
|
131
|
+
src=dark_src,
|
|
132
|
+
alt=alt,
|
|
133
|
+
variant="dark",
|
|
134
|
+
width=width,
|
|
135
|
+
height=height,
|
|
136
|
+
),
|
|
137
|
+
)
|
|
@@ -40,6 +40,7 @@ def render_page(component: Any, seo: Any = None) -> str:
|
|
|
40
40
|
"""Render a complete HTML document for a Voodoo component tree."""
|
|
41
41
|
from voodoo.config import config
|
|
42
42
|
from voodoo.seo import SEO
|
|
43
|
+
from voodoo.ui.brand import BRAND_CSS
|
|
43
44
|
from voodoo.ui.component import Component
|
|
44
45
|
from voodoo.ui.styles.theme import default_theme
|
|
45
46
|
|
|
@@ -162,6 +163,9 @@ def render_page(component: Any, seo: Any = None) -> str:
|
|
|
162
163
|
/* Stable primitive component layer */
|
|
163
164
|
{component_css}
|
|
164
165
|
|
|
166
|
+
/* Brand asset switching */
|
|
167
|
+
{BRAND_CSS}
|
|
168
|
+
|
|
165
169
|
/* Voodoo Design System 3 */
|
|
166
170
|
{design_system_css}
|
|
167
171
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: voodoo-framework
|
|
3
|
-
Version: 2.8.
|
|
3
|
+
Version: 2.8.2
|
|
4
4
|
Summary: The programmable runtime for adaptive applications and operational systems — web, APIs, agents, workers, human workflows, distributed systems, and physical systems in one runtime.
|
|
5
5
|
Author-email: Helder Perez <contact@helderperez.com>
|
|
6
6
|
Maintainer-email: Helder Perez <contact@helderperez.com>
|
|
@@ -200,6 +200,7 @@ src/voodoo/telemetry/store.py
|
|
|
200
200
|
src/voodoo/tools/__init__.py
|
|
201
201
|
src/voodoo/tools/registry.py
|
|
202
202
|
src/voodoo/ui/__init__.py
|
|
203
|
+
src/voodoo/ui/brand.py
|
|
203
204
|
src/voodoo/ui/component.py
|
|
204
205
|
src/voodoo/ui/events.py
|
|
205
206
|
src/voodoo/ui/interactive.py
|
|
@@ -238,6 +239,7 @@ tests/test_agent_registry.py
|
|
|
238
239
|
tests/test_agent_runtime.py
|
|
239
240
|
tests/test_app.py
|
|
240
241
|
tests/test_auth.py
|
|
242
|
+
tests/test_brand.py
|
|
241
243
|
tests/test_capability_security.py
|
|
242
244
|
tests/test_checkpoint_resume.py
|
|
243
245
|
tests/test_chrome.py
|
|
@@ -302,6 +304,7 @@ tests/test_protocol_operational.py
|
|
|
302
304
|
tests/test_provider_switching.py
|
|
303
305
|
tests/test_providers.py
|
|
304
306
|
tests/test_public_api_3.py
|
|
307
|
+
tests/test_public_assets.py
|
|
305
308
|
tests/test_queue.py
|
|
306
309
|
tests/test_reactive.py
|
|
307
310
|
tests/test_runtime.py
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"""Tests for the theme-aware Brand component."""
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from voodoo.ui import Brand
|
|
6
|
+
from voodoo.ui.brand import BRAND_CSS
|
|
7
|
+
from voodoo.ui.rendering import render_page
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def test_brand_preserves_child_based_api():
|
|
11
|
+
html = Brand("Voodoo", href="/home").render()
|
|
12
|
+
|
|
13
|
+
assert 'href="/home"' in html
|
|
14
|
+
assert ">Voodoo</a>" in html
|
|
15
|
+
assert "vd-brand-logo" not in html
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def test_brand_renders_theme_specific_assets_without_generic_img_style():
|
|
19
|
+
html = Brand(
|
|
20
|
+
light="/logo-black.png",
|
|
21
|
+
dark="/logo-white.png",
|
|
22
|
+
alt="Voodoo",
|
|
23
|
+
width=160,
|
|
24
|
+
href="/",
|
|
25
|
+
).render()
|
|
26
|
+
|
|
27
|
+
assert 'src="/logo-black.png"' in html
|
|
28
|
+
assert 'src="/logo-white.png"' in html
|
|
29
|
+
assert 'alt="Voodoo"' in html
|
|
30
|
+
assert 'width="160"' in html
|
|
31
|
+
assert "vd-brand-logo--light" in html
|
|
32
|
+
assert "vd-brand-logo--dark" in html
|
|
33
|
+
assert "vd-img" not in html
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def test_brand_single_asset_is_shared_by_both_themes():
|
|
37
|
+
html = Brand(light="/logo.svg", alt="Acme").render()
|
|
38
|
+
|
|
39
|
+
assert html.count("<img") == 1
|
|
40
|
+
assert 'src="/logo.svg"' in html
|
|
41
|
+
assert "vd-brand-logo--light" not in html
|
|
42
|
+
assert "vd-brand-logo--dark" not in html
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def test_brand_rejects_children_in_image_mode():
|
|
46
|
+
with pytest.raises(ValueError, match="cannot be combined"):
|
|
47
|
+
Brand("Voodoo", light="/logo.svg")
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def test_brand_css_switches_assets_and_removes_radius():
|
|
51
|
+
assert "border-radius: 0 !important" in BRAND_CSS
|
|
52
|
+
assert ".dark .vd-brand-logo--light { display: none; }" in BRAND_CSS
|
|
53
|
+
assert ".dark .vd-brand-logo--dark { display: block; }" in BRAND_CSS
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def test_render_page_includes_brand_css():
|
|
57
|
+
html = render_page(Brand(light="/logo-black.png", dark="/logo-white.png"))
|
|
58
|
+
|
|
59
|
+
assert "/* Brand asset switching */" in html
|
|
60
|
+
assert ".vd-brand-logo--light" in html
|
|
61
|
+
assert ".dark .vd-brand-logo--dark" in html
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"""Acceptance tests for the public asset URL contract."""
|
|
2
|
+
|
|
3
|
+
from starlette.testclient import TestClient
|
|
4
|
+
|
|
5
|
+
from voodoo import App
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def test_public_assets_are_served_from_root_without_shadowing_pages(
|
|
9
|
+
tmp_path, monkeypatch
|
|
10
|
+
):
|
|
11
|
+
monkeypatch.chdir(tmp_path)
|
|
12
|
+
|
|
13
|
+
app_dir = tmp_path / "app"
|
|
14
|
+
app_dir.mkdir()
|
|
15
|
+
(app_dir / "page.py").write_text(
|
|
16
|
+
"from voodoo.ui import Text\n\n"
|
|
17
|
+
"def page(request):\n"
|
|
18
|
+
" return Text('Application page wins')\n"
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
public_dir = tmp_path / "public"
|
|
22
|
+
(public_dir / "assets").mkdir(parents=True)
|
|
23
|
+
(public_dir / "logo.txt").write_text("voodoo-logo")
|
|
24
|
+
(public_dir / "assets" / "icon.txt").write_text("voodoo-icon")
|
|
25
|
+
# A static index must never shadow the application root route.
|
|
26
|
+
(public_dir / "index.html").write_text("STATIC INDEX")
|
|
27
|
+
|
|
28
|
+
with TestClient(App(app_dir=str(app_dir))) as client:
|
|
29
|
+
root = client.get("/")
|
|
30
|
+
logo = client.get("/logo.txt")
|
|
31
|
+
nested = client.get("/assets/icon.txt")
|
|
32
|
+
legacy = client.get("/public/logo.txt")
|
|
33
|
+
missing = client.get("/does-not-exist.txt")
|
|
34
|
+
|
|
35
|
+
assert root.status_code == 200
|
|
36
|
+
assert "Application page wins" in root.text
|
|
37
|
+
assert "STATIC INDEX" not in root.text
|
|
38
|
+
|
|
39
|
+
assert logo.status_code == 200
|
|
40
|
+
assert logo.text == "voodoo-logo"
|
|
41
|
+
assert nested.status_code == 200
|
|
42
|
+
assert nested.text == "voodoo-icon"
|
|
43
|
+
|
|
44
|
+
# Preserve the 2.x URL as a compatibility alias while root URLs become canonical.
|
|
45
|
+
assert legacy.status_code == 200
|
|
46
|
+
assert legacy.text == "voodoo-logo"
|
|
47
|
+
|
|
48
|
+
assert missing.status_code == 404
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|