voodoo-framework 2.8.1__tar.gz → 2.8.3__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.1 → voodoo_framework-2.8.3}/PKG-INFO +1 -1
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/__init__.py +1 -1
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/cli/__init__.py +2 -0
- voodoo_framework-2.8.3/src/voodoo/cli/start.py +55 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/ui/__init__.py +1 -1
- voodoo_framework-2.8.3/src/voodoo/ui/brand.py +137 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/ui/rendering.py +4 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo_framework.egg-info/PKG-INFO +1 -1
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo_framework.egg-info/SOURCES.txt +3 -0
- voodoo_framework-2.8.3/tests/test_brand.py +61 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_cli.py +94 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/LICENSE +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/README.md +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/pyproject.toml +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/setup.cfg +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/adapters/__init__.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/adapters/capabilities.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/adapters/registry.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/adapters/tailwind.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/adapters/voodoo_css.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/agent.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/agents/__init__.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/agents/models.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/agents/registry.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/ai/__init__.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/ai/agent.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/ai/agent_legacy.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/ai/agent_runtime_truth.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/ai/providers/__init__.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/ai/providers/anthropic.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/ai/providers/gemini.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/ai/providers/mock.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/ai/providers/ollama.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/ai/providers/openai.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/ai/tools/__init__.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/ai/tools/registry.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/api.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/auth/__init__.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/auth/cookies.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/auth/guards.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/auth/jwt.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/auth/middleware.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/auth/passwords.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/auth/user.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/cli/__main__.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/cli/agents.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/cli/ai.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/cli/approvals.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/cli/auth.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/cli/create.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/cli/dev.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/cli/doctor.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/cli/executions.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/cli/fabric.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/cli/generate.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/cli/inspect.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/cli/new.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/cli/objects.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/cli/protocol.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/cli/recover.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/cli/routes.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/cli/scaffolding.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/cli/schedules.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/cli/status.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/cli/tasks.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/cli/terminal.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/cli/theme.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/cli/version.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/cli/workers_cmd.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/components.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/config.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/core/__init__.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/core/app.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/core/errors.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/core/events.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/core/render.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/core/routing.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/core/sitemap.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/core/state.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/data/__init__.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/data/base.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/data/model.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/data/store_backend.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/data/store_facade.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/data/store_model.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/edge/__init__.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/edge/auth.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/edge/errors.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/edge/gateway.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/edge/http.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/edge/models.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/edge/mqtt.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/edge/protocol.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/edge/simulator.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/edge/store.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/edge/store_voodoo.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/edge/world.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/i18n.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/mcp/__init__.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/mcp/client.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/memory/__init__.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/memory/interfaces.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/memory/sqlite.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/mesh/__init__.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/mesh/auth.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/mesh/client.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/mesh/event_bus.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/mesh/remote.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/mesh/replay.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/primitives/__init__.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/primitives/capability.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/primitives/compute.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/primitives/constraint.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/primitives/effect.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/primitives/intent.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/primitives/resource.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/primitives/state.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/primitives/time.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/protocol/__init__.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/protocol/export.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/protocol/fabric.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/protocol/operational.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/protocol/schemas.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/py.typed +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/queue.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/routing/api.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/routing/pages.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/runtime/__init__.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/runtime/adaptive.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/runtime/capability.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/runtime/constraint.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/runtime/context.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/runtime/dashboard.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/runtime/engine.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/runtime/errors.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/runtime/execution.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/runtime/fabric.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/runtime/goal.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/runtime/goal_store.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/runtime/graph.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/runtime/human.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/runtime/identity.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/runtime/identity_store.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/runtime/membership.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/runtime/operations.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/runtime/persistence.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/runtime/planner.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/runtime/policy.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/runtime/scheduler.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/runtime/store.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/runtime/task.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/runtime/transaction.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/runtime/workflow.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/runtime/workflow_store.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/runtime/world_execution.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/schedule.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/security/__init__.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/security/cors.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/security/csrf.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/security/headers.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/security/passwords.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/security/rate_limit.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/security/redaction.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/security/secrets.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/seo.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/static/client.js +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/status.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/storage/__init__.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/storage/cache/__init__.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/storage/cache/interfaces.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/storage/cache/memory.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/storage/cache/redis.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/storage/database/__init__.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/storage/database/interfaces.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/storage/database/postgres.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/storage/database/sqlite.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/storage/events/__init__.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/storage/events/interfaces.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/storage/events/local.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/storage/events/postgres.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/storage/events/sqlite.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/storage/events/store.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/storage/execution/__init__.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/storage/execution/migrations.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/storage/execution/postgres.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/storage/execution/sqlite.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/storage/execution/store.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/storage/manager.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/storage/objects/__init__.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/storage/objects/interfaces.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/storage/objects/local.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/storage/objects/s3.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/storage/objects/store.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/storage/queue/__init__.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/storage/queue/interfaces.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/storage/queue/memory.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/storage/queue/postgres.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/storage/queue/redis.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/storage/queue/sqlite.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/storage/queue/store.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/storage/scheduler/__init__.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/storage/scheduler/sqlite.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/storage/scheduler/store.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/telemetry/__init__.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/telemetry/api.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/telemetry/middleware.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/telemetry/otlp.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/telemetry/store.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/theme.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/tools/__init__.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/tools/registry.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/ui/component.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/ui/events.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/ui/interactive.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/ui/layout.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/ui/library.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/ui/markdown.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/ui/primitives.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/ui/product.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/ui/state.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/ui/styles/__init__.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/ui/styles/presets.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/ui/styles/product.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/ui/styles/system.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/ui/styles/theme.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/ui/styles/theme_contract.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/ui/styles/voodoo_system.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/ui/voodoo_system.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/workers/__init__.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/workers/queue.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/world/__init__.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/world/model.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/world/models.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/world/sqlite.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo/world/store.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo_framework.egg-info/dependency_links.txt +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo_framework.egg-info/entry_points.txt +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo_framework.egg-info/requires.txt +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/src/voodoo_framework.egg-info/top_level.txt +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_adaptive_agency_correctness.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_agency_runtime_truth.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_agent.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_agent_registry.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_agent_runtime.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_app.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_auth.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_capability_security.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_checkpoint_resume.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_chrome.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_cli_fabric.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_cli_inspect.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_components.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_config.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_contract_api.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_create.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_create_store_smoke.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_data.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_design_system.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_design_system2.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_design_system_premium.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_design_system_theme_contract.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_durable_goal_runtime.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_durable_hitl.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_durable_workflow_runtime.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_edge_device.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_edge_e2e.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_edge_gateway.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_edge_http.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_edge_protocol.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_edge_security.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_edge_voodoo_store.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_edge_world.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_events.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_execution_sqlite_store.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_goal_runtime.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_hitl_persistence_correctness.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_http_runtime.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_human.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_i18n.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_identity_execution.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_identity_foundation.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_integration.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_mcp.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_mcp_runtime.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_memory.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_mesh.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_mesh_event_bus.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_mesh_remote_auth.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_mesh_remote_authority.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_mesh_remote_execution.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_mesh_remote_outcomes.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_mesh_remote_replay.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_mesh_two_node_acceptance.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_model.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_node_membership.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_object_store.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_observability.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_operational_policy.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_operational_runtime_ui.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_persistence.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_planner_adaptive.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_primitives.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_product_components.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_protocol.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_protocol_fabric.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_protocol_operational.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_provider_switching.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_providers.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_public_api_3.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_public_assets.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_queue.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_reactive.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_runtime.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_runtime_correctness.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_runtime_fabric.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_runtime_store_app_lifecycle.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_runtime_store_lifecycle.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_runtime_store_provider.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_runtime_transaction.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_scheduler.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_security.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_seo.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_sprint27_convergence.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_sprint28_acceptance.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_state.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_store_first_user_journey.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_store_model_backend.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_store_only_core_import.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_theme.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_theme_presets.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_tools.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_ui.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_ui_magic.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_ui_magic_acceptance.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_voodoo_store_events.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_voodoo_store_execution.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_voodoo_store_hitl_restart.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_voodoo_store_queue.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_voodoo_store_scheduler.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_voodoo_system_components.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_websocket.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_worker_retry_semantics.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_workers.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_world_aware_execution.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/tests/test_world_model.py +0 -0
- {voodoo_framework-2.8.1 → voodoo_framework-2.8.3}/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.3
|
|
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>
|
|
@@ -16,6 +16,7 @@ from voodoo.cli import (
|
|
|
16
16
|
recover,
|
|
17
17
|
routes,
|
|
18
18
|
schedules,
|
|
19
|
+
start,
|
|
19
20
|
status,
|
|
20
21
|
tasks,
|
|
21
22
|
theme,
|
|
@@ -36,6 +37,7 @@ app = typer.Typer(
|
|
|
36
37
|
app.command()(new.new)
|
|
37
38
|
app.command()(create.create)
|
|
38
39
|
app.command()(dev.dev)
|
|
40
|
+
app.command()(start.start)
|
|
39
41
|
app.command()(generate.generate)
|
|
40
42
|
app.add_typer(auth_app, name="auth")
|
|
41
43
|
app.add_typer(ai.ai_app, name="ai")
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"""Production server command for Voodoo applications."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
import typer
|
|
9
|
+
|
|
10
|
+
__all__ = ["start"]
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def start(
|
|
14
|
+
app_str: str | None = typer.Argument(
|
|
15
|
+
None,
|
|
16
|
+
help="App instance to run. Defaults to main:app or voodoo.core:app.",
|
|
17
|
+
),
|
|
18
|
+
host: str | None = typer.Option(
|
|
19
|
+
None,
|
|
20
|
+
help="Host to bind to. Defaults to VOODOO_HOST or 0.0.0.0.",
|
|
21
|
+
),
|
|
22
|
+
port: int | None = typer.Option(
|
|
23
|
+
None,
|
|
24
|
+
help="Port to bind to. Defaults to PORT, VOODOO_PORT, or 8000.",
|
|
25
|
+
),
|
|
26
|
+
) -> None:
|
|
27
|
+
"""Start a Voodoo application in production mode."""
|
|
28
|
+
if app_str is None:
|
|
29
|
+
app_str = "main:app" if Path("main.py").exists() else "voodoo.core:app"
|
|
30
|
+
|
|
31
|
+
resolved_host = host or os.getenv("VOODOO_HOST") or "0.0.0.0"
|
|
32
|
+
configured_port = os.getenv("PORT") or os.getenv("VOODOO_PORT") or "8000"
|
|
33
|
+
resolved_port = port if port is not None else int(configured_port)
|
|
34
|
+
|
|
35
|
+
# Production should be the safe default for this command while still
|
|
36
|
+
# allowing an explicitly configured environment to win.
|
|
37
|
+
os.environ.setdefault("VOODOO_ENV", "production")
|
|
38
|
+
os.environ.setdefault("WEBSOCKETS_MAX_LINE_LENGTH", "8388608")
|
|
39
|
+
os.environ.setdefault("WEBSOCKETS_MAX_NUM_HEADERS", "256")
|
|
40
|
+
|
|
41
|
+
import uvicorn
|
|
42
|
+
|
|
43
|
+
uvicorn.run(
|
|
44
|
+
app_str,
|
|
45
|
+
host=resolved_host,
|
|
46
|
+
port=resolved_port,
|
|
47
|
+
# One process owns one live local Store writer. Horizontal scaling uses
|
|
48
|
+
# separate Voodoo Nodes with node-local Stores.
|
|
49
|
+
workers=1,
|
|
50
|
+
proxy_headers=True,
|
|
51
|
+
forwarded_allow_ips=os.getenv("FORWARDED_ALLOW_IPS", "127.0.0.1"),
|
|
52
|
+
http="h11",
|
|
53
|
+
ws="websockets",
|
|
54
|
+
h11_max_incomplete_event_size=5_242_880,
|
|
55
|
+
)
|
|
@@ -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.3
|
|
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>
|
|
@@ -60,6 +60,7 @@ src/voodoo/cli/recover.py
|
|
|
60
60
|
src/voodoo/cli/routes.py
|
|
61
61
|
src/voodoo/cli/scaffolding.py
|
|
62
62
|
src/voodoo/cli/schedules.py
|
|
63
|
+
src/voodoo/cli/start.py
|
|
63
64
|
src/voodoo/cli/status.py
|
|
64
65
|
src/voodoo/cli/tasks.py
|
|
65
66
|
src/voodoo/cli/terminal.py
|
|
@@ -200,6 +201,7 @@ src/voodoo/telemetry/store.py
|
|
|
200
201
|
src/voodoo/tools/__init__.py
|
|
201
202
|
src/voodoo/tools/registry.py
|
|
202
203
|
src/voodoo/ui/__init__.py
|
|
204
|
+
src/voodoo/ui/brand.py
|
|
203
205
|
src/voodoo/ui/component.py
|
|
204
206
|
src/voodoo/ui/events.py
|
|
205
207
|
src/voodoo/ui/interactive.py
|
|
@@ -238,6 +240,7 @@ tests/test_agent_registry.py
|
|
|
238
240
|
tests/test_agent_runtime.py
|
|
239
241
|
tests/test_app.py
|
|
240
242
|
tests/test_auth.py
|
|
243
|
+
tests/test_brand.py
|
|
241
244
|
tests/test_capability_security.py
|
|
242
245
|
tests/test_checkpoint_resume.py
|
|
243
246
|
tests/test_chrome.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
|
|
@@ -335,3 +335,97 @@ def test_cli_dev_does_not_leak_pythonpath(tmp_path: Path, monkeypatch):
|
|
|
335
335
|
|
|
336
336
|
assert result.exit_code == 0
|
|
337
337
|
assert "PYTHONPATH" not in captured
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
def test_cli_start_uses_safe_production_defaults(
|
|
341
|
+
tmp_path: Path,
|
|
342
|
+
monkeypatch,
|
|
343
|
+
):
|
|
344
|
+
"""start should discover main.py and preserve Store-safe server defaults."""
|
|
345
|
+
monkeypatch.chdir(tmp_path)
|
|
346
|
+
(tmp_path / "main.py").write_text("app = object()\n")
|
|
347
|
+
for name in (
|
|
348
|
+
"VOODOO_ENV",
|
|
349
|
+
"VOODOO_HOST",
|
|
350
|
+
"VOODOO_PORT",
|
|
351
|
+
"PORT",
|
|
352
|
+
"FORWARDED_ALLOW_IPS",
|
|
353
|
+
"WEBSOCKETS_MAX_LINE_LENGTH",
|
|
354
|
+
"WEBSOCKETS_MAX_NUM_HEADERS",
|
|
355
|
+
):
|
|
356
|
+
monkeypatch.delenv(name, raising=False)
|
|
357
|
+
|
|
358
|
+
with patch("uvicorn.run") as run:
|
|
359
|
+
result = runner.invoke(app, ["start"])
|
|
360
|
+
|
|
361
|
+
assert result.exit_code == 0
|
|
362
|
+
run.assert_called_once_with(
|
|
363
|
+
"main:app",
|
|
364
|
+
host="0.0.0.0",
|
|
365
|
+
port=8000,
|
|
366
|
+
workers=1,
|
|
367
|
+
proxy_headers=True,
|
|
368
|
+
forwarded_allow_ips="127.0.0.1",
|
|
369
|
+
http="h11",
|
|
370
|
+
ws="websockets",
|
|
371
|
+
h11_max_incomplete_event_size=5_242_880,
|
|
372
|
+
)
|
|
373
|
+
assert os.environ["VOODOO_ENV"] == "production"
|
|
374
|
+
assert os.environ["WEBSOCKETS_MAX_LINE_LENGTH"] == "8388608"
|
|
375
|
+
assert os.environ["WEBSOCKETS_MAX_NUM_HEADERS"] == "256"
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
def test_cli_start_respects_explicit_configuration(
|
|
379
|
+
tmp_path: Path,
|
|
380
|
+
monkeypatch,
|
|
381
|
+
):
|
|
382
|
+
"""CLI arguments and explicit environment settings should remain authoritative."""
|
|
383
|
+
monkeypatch.chdir(tmp_path)
|
|
384
|
+
monkeypatch.setenv("VOODOO_ENV", "staging")
|
|
385
|
+
monkeypatch.setenv("VOODOO_HOST", "127.0.0.2")
|
|
386
|
+
monkeypatch.setenv("PORT", "9100")
|
|
387
|
+
monkeypatch.setenv("FORWARDED_ALLOW_IPS", "10.0.0.0/8")
|
|
388
|
+
|
|
389
|
+
with patch("uvicorn.run") as run:
|
|
390
|
+
result = runner.invoke(
|
|
391
|
+
app,
|
|
392
|
+
[
|
|
393
|
+
"start",
|
|
394
|
+
"custom.application:app",
|
|
395
|
+
"--host",
|
|
396
|
+
"127.0.0.3",
|
|
397
|
+
"--port",
|
|
398
|
+
"9200",
|
|
399
|
+
],
|
|
400
|
+
)
|
|
401
|
+
|
|
402
|
+
assert result.exit_code == 0
|
|
403
|
+
call = run.call_args
|
|
404
|
+
assert call.args == ("custom.application:app",)
|
|
405
|
+
assert call.kwargs["host"] == "127.0.0.3"
|
|
406
|
+
assert call.kwargs["port"] == 9200
|
|
407
|
+
assert call.kwargs["forwarded_allow_ips"] == "10.0.0.0/8"
|
|
408
|
+
assert call.kwargs["workers"] == 1
|
|
409
|
+
assert os.environ["VOODOO_ENV"] == "staging"
|
|
410
|
+
|
|
411
|
+
|
|
412
|
+
def test_cli_start_falls_back_to_folder_routing_app(
|
|
413
|
+
tmp_path: Path,
|
|
414
|
+
monkeypatch,
|
|
415
|
+
):
|
|
416
|
+
"""Projects without main.py should use the folder-routing application."""
|
|
417
|
+
monkeypatch.chdir(tmp_path)
|
|
418
|
+
|
|
419
|
+
with patch("uvicorn.run") as run:
|
|
420
|
+
result = runner.invoke(app, ["start"])
|
|
421
|
+
|
|
422
|
+
assert result.exit_code == 0
|
|
423
|
+
assert run.call_args.args == ("voodoo.core:app",)
|
|
424
|
+
|
|
425
|
+
|
|
426
|
+
def test_cli_start_does_not_offer_unsafe_multi_worker_mode():
|
|
427
|
+
"""One local Store writer means the production command has no workers option."""
|
|
428
|
+
result = runner.invoke(app, ["start", "--workers", "2"])
|
|
429
|
+
|
|
430
|
+
assert result.exit_code != 0
|
|
431
|
+
assert "No such option" in result.output
|
|
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
|