voodoo-framework 2.4.0__tar.gz → 2.5.0__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.4.0/src/voodoo_framework.egg-info → voodoo_framework-2.5.0}/PKG-INFO +6 -4
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/README.md +5 -3
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/__init__.py +1 -1
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/cli/__init__.py +2 -0
- voodoo_framework-2.5.0/src/voodoo/cli/create.py +361 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/cli/dev.py +54 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0/src/voodoo_framework.egg-info}/PKG-INFO +6 -4
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo_framework.egg-info/SOURCES.txt +2 -0
- voodoo_framework-2.5.0/tests/test_create.py +150 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/LICENSE +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/pyproject.toml +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/setup.cfg +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/adapters/__init__.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/adapters/capabilities.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/adapters/registry.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/adapters/tailwind.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/adapters/voodoo_css.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/agent.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/agents/__init__.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/agents/models.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/agents/registry.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/ai/__init__.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/ai/agent.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/ai/providers/__init__.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/ai/providers/anthropic.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/ai/providers/gemini.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/ai/providers/mock.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/ai/providers/ollama.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/ai/providers/openai.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/ai/tools/__init__.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/ai/tools/registry.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/api.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/auth/__init__.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/auth/cookies.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/auth/guards.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/auth/jwt.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/auth/middleware.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/auth/passwords.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/auth/user.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/cli/__main__.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/cli/agents.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/cli/ai.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/cli/approvals.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/cli/auth.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/cli/doctor.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/cli/executions.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/cli/generate.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/cli/inspect.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/cli/new.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/cli/objects.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/cli/protocol.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/cli/recover.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/cli/routes.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/cli/scaffolding.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/cli/schedules.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/cli/status.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/cli/tasks.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/cli/terminal.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/cli/theme.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/cli/version.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/cli/workers_cmd.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/components.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/config.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/core/__init__.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/core/app.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/core/errors.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/core/events.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/core/render.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/core/routing.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/core/sitemap.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/core/state.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/data/__init__.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/data/base.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/data/model.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/i18n.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/mcp/__init__.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/mcp/client.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/memory/__init__.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/memory/interfaces.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/memory/sqlite.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/mesh/__init__.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/mesh/client.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/mesh/event_bus.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/primitives/__init__.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/primitives/capability.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/primitives/compute.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/primitives/constraint.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/primitives/effect.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/primitives/intent.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/primitives/resource.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/primitives/state.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/primitives/time.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/protocol/__init__.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/protocol/export.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/protocol/schemas.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/py.typed +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/queue.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/routing/api.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/routing/pages.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/runtime/__init__.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/runtime/adaptive.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/runtime/capability.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/runtime/constraint.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/runtime/context.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/runtime/engine.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/runtime/errors.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/runtime/execution.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/runtime/graph.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/runtime/human.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/runtime/persistence.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/runtime/planner.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/runtime/scheduler.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/runtime/task.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/runtime/workflow.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/schedule.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/security/__init__.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/security/cors.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/security/csrf.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/security/headers.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/security/passwords.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/security/rate_limit.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/security/redaction.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/security/secrets.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/seo.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/static/client.js +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/status.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/storage/__init__.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/storage/cache/__init__.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/storage/cache/interfaces.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/storage/cache/memory.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/storage/cache/redis.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/storage/database/__init__.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/storage/database/interfaces.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/storage/database/postgres.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/storage/database/sqlite.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/storage/events/__init__.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/storage/events/interfaces.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/storage/events/local.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/storage/events/postgres.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/storage/events/sqlite.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/storage/execution/__init__.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/storage/execution/migrations.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/storage/execution/postgres.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/storage/execution/sqlite.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/storage/manager.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/storage/objects/__init__.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/storage/objects/interfaces.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/storage/objects/local.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/storage/objects/s3.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/storage/queue/__init__.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/storage/queue/interfaces.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/storage/queue/memory.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/storage/queue/postgres.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/storage/queue/redis.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/storage/queue/sqlite.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/storage/scheduler/__init__.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/storage/scheduler/sqlite.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/telemetry/__init__.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/telemetry/api.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/telemetry/middleware.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/telemetry/otlp.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/telemetry/store.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/theme.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/tools/__init__.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/tools/registry.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/ui/__init__.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/ui/component.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/ui/events.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/ui/library.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/ui/markdown.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/ui/rendering.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/ui/state.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/ui/styles/__init__.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/ui/styles/presets.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/ui/styles/theme.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/workers/__init__.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo/workers/queue.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo_framework.egg-info/dependency_links.txt +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo_framework.egg-info/entry_points.txt +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo_framework.egg-info/requires.txt +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/src/voodoo_framework.egg-info/top_level.txt +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/tests/test_agent.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/tests/test_agent_registry.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/tests/test_agent_runtime.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/tests/test_app.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/tests/test_auth.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/tests/test_capability_security.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/tests/test_checkpoint_resume.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/tests/test_chrome.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/tests/test_cli.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/tests/test_cli_inspect.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/tests/test_components.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/tests/test_config.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/tests/test_contract_api.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/tests/test_data.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/tests/test_design_system.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/tests/test_durable_hitl.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/tests/test_events.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/tests/test_execution_sqlite_store.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/tests/test_http_runtime.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/tests/test_human.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/tests/test_i18n.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/tests/test_integration.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/tests/test_mcp.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/tests/test_mcp_runtime.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/tests/test_memory.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/tests/test_mesh.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/tests/test_mesh_event_bus.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/tests/test_model.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/tests/test_object_store.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/tests/test_observability.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/tests/test_persistence.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/tests/test_planner_adaptive.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/tests/test_primitives.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/tests/test_protocol.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/tests/test_provider_switching.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/tests/test_providers.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/tests/test_queue.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/tests/test_reactive.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/tests/test_runtime.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/tests/test_scheduler.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/tests/test_security.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/tests/test_seo.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/tests/test_state.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/tests/test_theme.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/tests/test_theme_presets.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/tests/test_tools.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/tests/test_ui.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/tests/test_websocket.py +0 -0
- {voodoo_framework-2.4.0 → voodoo_framework-2.5.0}/tests/test_workers.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: voodoo-framework
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.5.0
|
|
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>
|
|
@@ -119,14 +119,16 @@ Voodoo is **not** a wrapper around other frameworks. It's a unified runtime wher
|
|
|
119
119
|
|
|
120
120
|
```bash
|
|
121
121
|
pip install voodoo-framework
|
|
122
|
-
voodoo
|
|
122
|
+
voodoo create my_app
|
|
123
123
|
cd my_app
|
|
124
124
|
voodoo dev
|
|
125
125
|
```
|
|
126
126
|
|
|
127
127
|
Open `http://localhost:8000` — that's it. No npm, no bundler, no config files.
|
|
128
128
|
|
|
129
|
-
|
|
129
|
+
`voodoo create` scaffolds a full local runtime app with durable tasks, scheduler, events, and agent runtime — all on zero infrastructure. The generated app includes a crash/restart demo proving durability.
|
|
130
|
+
|
|
131
|
+
> **Want a minimal scaffold?** Use `voodoo new` instead for a bare-bones app with just UI routing.
|
|
130
132
|
|
|
131
133
|
> **Want AI features?** Install with `pip install "voodoo-framework[ai]"` to add OpenAI, Anthropic, Gemini, and Ollama SDKs.
|
|
132
134
|
|
|
@@ -232,7 +234,7 @@ if __name__ == "__main__":
|
|
|
232
234
|
| **Human-in-the-Loop** | `ask_human()` + `approve()`/`deny()` — humans as compute participants, not afterthoughts |
|
|
233
235
|
| **Adaptive execution** | Planner resolves capabilities to compute participants; supervisor steers with retry, fallback, budget control |
|
|
234
236
|
| **Durable by default** | Tasks, executions, schedules, and events survive process restarts — backed by SQLite out of the box |
|
|
235
|
-
| **Zero-config runtime** | `voodoo
|
|
237
|
+
| **Zero-config runtime** | `voodoo create` → `voodoo dev` → working app. No build step. Add `voodoo.toml` when you need configuration |
|
|
236
238
|
| **Local-first, cloud-capable** | SQLite by default; PostgreSQL, Redis, and S3/R2 are optional adapters behind the same contracts |
|
|
237
239
|
|
|
238
240
|
## The Computational Model
|
|
@@ -52,14 +52,16 @@ Voodoo is **not** a wrapper around other frameworks. It's a unified runtime wher
|
|
|
52
52
|
|
|
53
53
|
```bash
|
|
54
54
|
pip install voodoo-framework
|
|
55
|
-
voodoo
|
|
55
|
+
voodoo create my_app
|
|
56
56
|
cd my_app
|
|
57
57
|
voodoo dev
|
|
58
58
|
```
|
|
59
59
|
|
|
60
60
|
Open `http://localhost:8000` — that's it. No npm, no bundler, no config files.
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
`voodoo create` scaffolds a full local runtime app with durable tasks, scheduler, events, and agent runtime — all on zero infrastructure. The generated app includes a crash/restart demo proving durability.
|
|
63
|
+
|
|
64
|
+
> **Want a minimal scaffold?** Use `voodoo new` instead for a bare-bones app with just UI routing.
|
|
63
65
|
|
|
64
66
|
> **Want AI features?** Install with `pip install "voodoo-framework[ai]"` to add OpenAI, Anthropic, Gemini, and Ollama SDKs.
|
|
65
67
|
|
|
@@ -165,7 +167,7 @@ if __name__ == "__main__":
|
|
|
165
167
|
| **Human-in-the-Loop** | `ask_human()` + `approve()`/`deny()` — humans as compute participants, not afterthoughts |
|
|
166
168
|
| **Adaptive execution** | Planner resolves capabilities to compute participants; supervisor steers with retry, fallback, budget control |
|
|
167
169
|
| **Durable by default** | Tasks, executions, schedules, and events survive process restarts — backed by SQLite out of the box |
|
|
168
|
-
| **Zero-config runtime** | `voodoo
|
|
170
|
+
| **Zero-config runtime** | `voodoo create` → `voodoo dev` → working app. No build step. Add `voodoo.toml` when you need configuration |
|
|
169
171
|
| **Local-first, cloud-capable** | SQLite by default; PostgreSQL, Redis, and S3/R2 are optional adapters behind the same contracts |
|
|
170
172
|
|
|
171
173
|
## The Computational Model
|
|
@@ -4,6 +4,7 @@ from voodoo.cli import (
|
|
|
4
4
|
agents,
|
|
5
5
|
ai,
|
|
6
6
|
approvals,
|
|
7
|
+
create,
|
|
7
8
|
dev,
|
|
8
9
|
doctor,
|
|
9
10
|
executions,
|
|
@@ -32,6 +33,7 @@ app = typer.Typer(
|
|
|
32
33
|
)
|
|
33
34
|
|
|
34
35
|
app.command()(new.new)
|
|
36
|
+
app.command()(create.create)
|
|
35
37
|
app.command()(dev.dev)
|
|
36
38
|
app.command()(generate.generate)
|
|
37
39
|
app.add_typer(auth_app, name="auth")
|
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
"""CLI: ``voodoo create <app>`` — scaffold a full local runtime app.
|
|
2
|
+
|
|
3
|
+
Sprint 22: Local runtime DX. Evolves ``voodoo new`` to wire up the full
|
|
4
|
+
local runtime (durable tasks, scheduler, events, object store, agent runtime)
|
|
5
|
+
with a crash/restart demo proving durability.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import subprocess
|
|
11
|
+
import sys
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
|
|
14
|
+
import typer
|
|
15
|
+
|
|
16
|
+
from voodoo.cli import terminal
|
|
17
|
+
|
|
18
|
+
__all__ = ["create"]
|
|
19
|
+
|
|
20
|
+
# ---------------------------------------------------------------------------
|
|
21
|
+
# Template: main.py — full local runtime
|
|
22
|
+
# ---------------------------------------------------------------------------
|
|
23
|
+
|
|
24
|
+
_MAIN_PY = '''"""{name} — a Voodoo autonomous app.
|
|
25
|
+
|
|
26
|
+
This app demonstrates the full local runtime:
|
|
27
|
+
- Durable tasks (queue + workers) that survive restarts
|
|
28
|
+
- Scheduler for recurring jobs
|
|
29
|
+
- Mesh events for real-time communication
|
|
30
|
+
- Agent runtime with mock provider (no network needed)
|
|
31
|
+
|
|
32
|
+
Run: python main.py or voodoo dev
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
from voodoo import (
|
|
36
|
+
Agent,
|
|
37
|
+
App,
|
|
38
|
+
Button,
|
|
39
|
+
Card,
|
|
40
|
+
Container,
|
|
41
|
+
Heading,
|
|
42
|
+
Stack,
|
|
43
|
+
Text,
|
|
44
|
+
event,
|
|
45
|
+
page,
|
|
46
|
+
state,
|
|
47
|
+
tool,
|
|
48
|
+
)
|
|
49
|
+
from voodoo.workers.queue import enqueue, queue
|
|
50
|
+
|
|
51
|
+
app = App()
|
|
52
|
+
|
|
53
|
+
# ---------------------------------------------------------------------------
|
|
54
|
+
# State
|
|
55
|
+
# ---------------------------------------------------------------------------
|
|
56
|
+
|
|
57
|
+
counter = state("counter", 0)
|
|
58
|
+
log_lines = state("log_lines", [])
|
|
59
|
+
agent_result = state("agent_result", "Click to run the agent")
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _log(msg: str) -> None:
|
|
63
|
+
"""Append a timestamped line to the on-screen log."""
|
|
64
|
+
from datetime import datetime
|
|
65
|
+
|
|
66
|
+
ts = datetime.now().strftime("%H:%M:%S")
|
|
67
|
+
lines = log_lines.get()
|
|
68
|
+
lines.append(f"[{{ts}}] {{msg}}")
|
|
69
|
+
# Keep last 20 lines
|
|
70
|
+
log_lines.set(lines[-20:])
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
# ---------------------------------------------------------------------------
|
|
74
|
+
# Durable task — survives restarts
|
|
75
|
+
# ---------------------------------------------------------------------------
|
|
76
|
+
|
|
77
|
+
@queue("increment")
|
|
78
|
+
async def increment_worker(payload: dict) -> None:
|
|
79
|
+
"""Durable worker: increments the counter and logs the result."""
|
|
80
|
+
n = counter.get() + 1
|
|
81
|
+
counter.set(n)
|
|
82
|
+
_log(f"increment task done → counter = {{n}}")
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
# ---------------------------------------------------------------------------
|
|
86
|
+
# Agent (mock provider — no network needed)
|
|
87
|
+
# ---------------------------------------------------------------------------
|
|
88
|
+
|
|
89
|
+
@tool
|
|
90
|
+
async def get_counter() -> str:
|
|
91
|
+
"""Return the current counter value."""
|
|
92
|
+
return str(counter.get())
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
agent = Agent(
|
|
96
|
+
model="mock:test",
|
|
97
|
+
tools=["get_counter"],
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
# ---------------------------------------------------------------------------
|
|
102
|
+
# Routes
|
|
103
|
+
# ---------------------------------------------------------------------------
|
|
104
|
+
|
|
105
|
+
@page("/")
|
|
106
|
+
def home():
|
|
107
|
+
return Container(
|
|
108
|
+
Stack(
|
|
109
|
+
Heading("{name}", level=1),
|
|
110
|
+
Text(
|
|
111
|
+
"A Voodoo autonomous app — durable tasks, scheduler, "
|
|
112
|
+
"events, and agents, all running on zero infrastructure.",
|
|
113
|
+
tone="muted",
|
|
114
|
+
),
|
|
115
|
+
_status_card(),
|
|
116
|
+
_task_card(),
|
|
117
|
+
_agent_card(),
|
|
118
|
+
_log_card(),
|
|
119
|
+
gap="lg",
|
|
120
|
+
)
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def _status_card():
|
|
125
|
+
return Card(
|
|
126
|
+
Stack(
|
|
127
|
+
Heading("Runtime", level=2),
|
|
128
|
+
Text(f"Counter: {{counter.get()}}"),
|
|
129
|
+
Text(f"Log entries: {{len(log_lines.get())}}"),
|
|
130
|
+
gap="sm",
|
|
131
|
+
)
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def _task_card():
|
|
136
|
+
return Card(
|
|
137
|
+
Stack(
|
|
138
|
+
Heading("Durable Tasks", level=2),
|
|
139
|
+
Text(
|
|
140
|
+
"Enqueue a durable task. It survives restarts — "
|
|
141
|
+
"stop the server, start it again, and watch the counter increment.",
|
|
142
|
+
tone="muted",
|
|
143
|
+
),
|
|
144
|
+
Button(
|
|
145
|
+
"Enqueue increment",
|
|
146
|
+
onclick="vd.event('enqueue_task')",
|
|
147
|
+
variant="primary",
|
|
148
|
+
),
|
|
149
|
+
gap="sm",
|
|
150
|
+
)
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def _agent_card():
|
|
155
|
+
return Card(
|
|
156
|
+
Stack(
|
|
157
|
+
Heading("Agent", level=2),
|
|
158
|
+
Text(f"Result: {{agent_result.get()}}"),
|
|
159
|
+
Button(
|
|
160
|
+
"Run agent",
|
|
161
|
+
onclick="vd.event('run_agent')",
|
|
162
|
+
variant="secondary",
|
|
163
|
+
),
|
|
164
|
+
gap="sm",
|
|
165
|
+
)
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def _log_card():
|
|
170
|
+
return Card(
|
|
171
|
+
Stack(
|
|
172
|
+
Heading("Event Log", level=2),
|
|
173
|
+
*[Text(line, tone="muted") for line in log_lines.get()],
|
|
174
|
+
gap="xs",
|
|
175
|
+
)
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
# ---------------------------------------------------------------------------
|
|
180
|
+
# Events
|
|
181
|
+
# ---------------------------------------------------------------------------
|
|
182
|
+
|
|
183
|
+
@event
|
|
184
|
+
async def enqueue_task(element_id, value):
|
|
185
|
+
"""Enqueue a durable increment task."""
|
|
186
|
+
await enqueue("increment", {{"source": "ui"}})
|
|
187
|
+
_log("enqueued increment task")
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
@event
|
|
191
|
+
async def run_agent(element_id, value):
|
|
192
|
+
"""Run the agent and display the result."""
|
|
193
|
+
_log("running agent...")
|
|
194
|
+
run = await agent.run("What is the current counter value?")
|
|
195
|
+
agent_result.set(run.output)
|
|
196
|
+
_log(f"agent done: {{run.output}}")
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
# ---------------------------------------------------------------------------
|
|
200
|
+
# Startup — enqueue a demo task on first boot
|
|
201
|
+
# ---------------------------------------------------------------------------
|
|
202
|
+
|
|
203
|
+
@app.on_startup
|
|
204
|
+
async def on_startup():
|
|
205
|
+
"""On first boot, enqueue a demo task to prove durability."""
|
|
206
|
+
import os
|
|
207
|
+
|
|
208
|
+
marker = ".voodoo/state/.booted"
|
|
209
|
+
if not os.path.exists(marker):
|
|
210
|
+
os.makedirs(os.path.dirname(marker), exist_ok=True)
|
|
211
|
+
with open(marker, "w") as f:
|
|
212
|
+
f.write("booted")
|
|
213
|
+
await enqueue("increment", {{"source": "startup"}})
|
|
214
|
+
_log("first boot — enqueued demo task")
|
|
215
|
+
else:
|
|
216
|
+
_log("restart detected — pending tasks will be recovered")
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
if __name__ == "__main__":
|
|
220
|
+
app.run()
|
|
221
|
+
'''
|
|
222
|
+
|
|
223
|
+
# ---------------------------------------------------------------------------
|
|
224
|
+
# Template: voodoo.toml
|
|
225
|
+
# ---------------------------------------------------------------------------
|
|
226
|
+
|
|
227
|
+
_VOODOO_TOML = """[app]
|
|
228
|
+
name = "{name}"
|
|
229
|
+
|
|
230
|
+
# Local-first defaults — zero infrastructure required.
|
|
231
|
+
# The runtime uses SQLite, local filesystem, and in-memory queues by default.
|
|
232
|
+
# Override with env vars or this config for production:
|
|
233
|
+
# VOODOO_DATABASE_URL=postgresql://...
|
|
234
|
+
# VOODOO_QUEUE_PROVIDER=redis
|
|
235
|
+
# VOODOO_OBJECT_STORE_PROVIDER=s3
|
|
236
|
+
"""
|
|
237
|
+
|
|
238
|
+
# ---------------------------------------------------------------------------
|
|
239
|
+
# Template: pyproject.toml
|
|
240
|
+
# ---------------------------------------------------------------------------
|
|
241
|
+
|
|
242
|
+
_PYPROJECT_TOML = """[project]
|
|
243
|
+
name = "{name}"
|
|
244
|
+
version = "0.1.0"
|
|
245
|
+
requires-python = ">=3.12"
|
|
246
|
+
dependencies = [
|
|
247
|
+
"voodoo-framework",
|
|
248
|
+
]
|
|
249
|
+
"""
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
# ---------------------------------------------------------------------------
|
|
253
|
+
# Command
|
|
254
|
+
# ---------------------------------------------------------------------------
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
def create(
|
|
258
|
+
project_name: str = typer.Argument(..., help="Name of the project to create"),
|
|
259
|
+
) -> None:
|
|
260
|
+
"""Scaffold a full local runtime app with durable tasks, scheduler, events, and agents.
|
|
261
|
+
|
|
262
|
+
The generated app runs on zero infrastructure (SQLite + local filesystem)
|
|
263
|
+
and includes a crash/restart demo proving durability.
|
|
264
|
+
"""
|
|
265
|
+
project_dir = Path(project_name)
|
|
266
|
+
if project_dir.exists():
|
|
267
|
+
terminal.error(f"Directory '{project_name}' already exists")
|
|
268
|
+
raise typer.Exit(1)
|
|
269
|
+
|
|
270
|
+
terminal.wordmark()
|
|
271
|
+
terminal.blank()
|
|
272
|
+
terminal.status("creating", project_name)
|
|
273
|
+
terminal.blank()
|
|
274
|
+
|
|
275
|
+
# Create directory structure
|
|
276
|
+
project_dir.mkdir(parents=True)
|
|
277
|
+
(project_dir / "app").mkdir()
|
|
278
|
+
(project_dir / ".voodoo" / "state").mkdir(parents=True)
|
|
279
|
+
|
|
280
|
+
# Write files
|
|
281
|
+
(project_dir / "main.py").write_text(_MAIN_PY.format(name=project_name))
|
|
282
|
+
(project_dir / "voodoo.toml").write_text(_VOODOO_TOML.format(name=project_name))
|
|
283
|
+
(project_dir / "pyproject.toml").write_text(
|
|
284
|
+
_PYPROJECT_TOML.format(name=project_name)
|
|
285
|
+
)
|
|
286
|
+
|
|
287
|
+
terminal.label_value("created", f"{project_name}/")
|
|
288
|
+
terminal.tree(
|
|
289
|
+
[
|
|
290
|
+
"main.py # App entry point — full runtime demo",
|
|
291
|
+
"voodoo.toml # Runtime configuration",
|
|
292
|
+
"pyproject.toml # Python project metadata",
|
|
293
|
+
"app/ # Folder-based routes (add page.py files here)",
|
|
294
|
+
".voodoo/state/ # Local state (SQLite, queue, schedules)",
|
|
295
|
+
]
|
|
296
|
+
)
|
|
297
|
+
terminal.blank()
|
|
298
|
+
|
|
299
|
+
# Install dependencies
|
|
300
|
+
terminal.status("installing", "dependencies")
|
|
301
|
+
terminal.blank()
|
|
302
|
+
|
|
303
|
+
local_venv = project_dir / ".venv"
|
|
304
|
+
try:
|
|
305
|
+
subprocess.run(
|
|
306
|
+
[sys.executable, "-m", "uv", "venv", str(local_venv)],
|
|
307
|
+
check=True,
|
|
308
|
+
capture_output=True,
|
|
309
|
+
)
|
|
310
|
+
subprocess.run(
|
|
311
|
+
[
|
|
312
|
+
str(local_venv / "bin" / "python"),
|
|
313
|
+
"-m",
|
|
314
|
+
"uv",
|
|
315
|
+
"pip",
|
|
316
|
+
"install",
|
|
317
|
+
"-e",
|
|
318
|
+
".",
|
|
319
|
+
],
|
|
320
|
+
cwd=str(project_dir),
|
|
321
|
+
check=True,
|
|
322
|
+
capture_output=True,
|
|
323
|
+
)
|
|
324
|
+
terminal.muted("installed via uv")
|
|
325
|
+
except (subprocess.CalledProcessError, FileNotFoundError):
|
|
326
|
+
# Fallback to plain venv + pip
|
|
327
|
+
try:
|
|
328
|
+
subprocess.run(
|
|
329
|
+
[sys.executable, "-m", "venv", str(local_venv)],
|
|
330
|
+
check=True,
|
|
331
|
+
capture_output=True,
|
|
332
|
+
)
|
|
333
|
+
subprocess.run(
|
|
334
|
+
[
|
|
335
|
+
str(local_venv / "bin" / "pip"),
|
|
336
|
+
"install",
|
|
337
|
+
"-e",
|
|
338
|
+
".",
|
|
339
|
+
],
|
|
340
|
+
cwd=str(project_dir),
|
|
341
|
+
check=True,
|
|
342
|
+
capture_output=True,
|
|
343
|
+
)
|
|
344
|
+
terminal.muted("installed via pip")
|
|
345
|
+
except subprocess.CalledProcessError as exc:
|
|
346
|
+
terminal.warning(f"dependency install failed: {exc}")
|
|
347
|
+
terminal.muted("run 'cd {project_name} && pip install -e .' manually")
|
|
348
|
+
|
|
349
|
+
terminal.blank()
|
|
350
|
+
terminal.success("ready")
|
|
351
|
+
terminal.blank()
|
|
352
|
+
terminal.next_steps(
|
|
353
|
+
[
|
|
354
|
+
f"cd {project_name}",
|
|
355
|
+
"voodoo dev",
|
|
356
|
+
"",
|
|
357
|
+
"Then open http://localhost:8000 and click 'Enqueue increment'.",
|
|
358
|
+
"Stop the server (Ctrl+C), run 'voodoo dev' again — the counter",
|
|
359
|
+
"increments because the task is durable.",
|
|
360
|
+
]
|
|
361
|
+
)
|
|
@@ -70,6 +70,9 @@ def dev(
|
|
|
70
70
|
terminal.label_value("docs", f"{local_url}/docs")
|
|
71
71
|
terminal.blank()
|
|
72
72
|
|
|
73
|
+
# Sprint 22: runtime banner — show providers and runtime state
|
|
74
|
+
_print_runtime_banner()
|
|
75
|
+
|
|
73
76
|
local_venv_python = (
|
|
74
77
|
Path(".venv/bin/python")
|
|
75
78
|
if os.name != "nt"
|
|
@@ -117,3 +120,54 @@ def dev(
|
|
|
117
120
|
except KeyboardInterrupt:
|
|
118
121
|
terminal.blank()
|
|
119
122
|
terminal.status("runtime", "stopped")
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def _print_runtime_banner() -> None:
|
|
126
|
+
"""Print runtime providers and state (Sprint 22)."""
|
|
127
|
+
from voodoo.config import get_config
|
|
128
|
+
|
|
129
|
+
cfg = get_config()
|
|
130
|
+
|
|
131
|
+
# Providers
|
|
132
|
+
terminal.heading("providers")
|
|
133
|
+
db_provider = cfg.database.provider.lower()
|
|
134
|
+
terminal.status("database", db_provider)
|
|
135
|
+
|
|
136
|
+
queue_provider = cfg.queue.provider.lower()
|
|
137
|
+
terminal.status("queue", queue_provider)
|
|
138
|
+
|
|
139
|
+
# Object store
|
|
140
|
+
terminal.status("objects", cfg.objects.provider.lower())
|
|
141
|
+
|
|
142
|
+
# Agent runtime
|
|
143
|
+
try:
|
|
144
|
+
from voodoo.ai.providers import _PROVIDER_CLASSES
|
|
145
|
+
|
|
146
|
+
providers = list(_PROVIDER_CLASSES.keys())
|
|
147
|
+
terminal.status("agents", ", ".join(providers) if providers else "none")
|
|
148
|
+
except Exception:
|
|
149
|
+
terminal.status("agents", "mock")
|
|
150
|
+
|
|
151
|
+
# MCP endpoint
|
|
152
|
+
terminal.label_value("mcp", "/mcp")
|
|
153
|
+
|
|
154
|
+
# Registered workers
|
|
155
|
+
try:
|
|
156
|
+
from voodoo.workers.queue import _workers
|
|
157
|
+
|
|
158
|
+
worker_names = list(_workers.keys())
|
|
159
|
+
if worker_names:
|
|
160
|
+
terminal.label_value("workers", ", ".join(worker_names))
|
|
161
|
+
else:
|
|
162
|
+
terminal.label_value("workers", "none")
|
|
163
|
+
except Exception:
|
|
164
|
+
terminal.label_value("workers", "none")
|
|
165
|
+
|
|
166
|
+
# Schedules DB
|
|
167
|
+
schedule_path = Path(".voodoo/state/schedules.db")
|
|
168
|
+
if schedule_path.exists():
|
|
169
|
+
terminal.status("scheduler", "ready")
|
|
170
|
+
else:
|
|
171
|
+
terminal.status("scheduler", "will be created")
|
|
172
|
+
|
|
173
|
+
terminal.blank()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: voodoo-framework
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.5.0
|
|
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>
|
|
@@ -119,14 +119,16 @@ Voodoo is **not** a wrapper around other frameworks. It's a unified runtime wher
|
|
|
119
119
|
|
|
120
120
|
```bash
|
|
121
121
|
pip install voodoo-framework
|
|
122
|
-
voodoo
|
|
122
|
+
voodoo create my_app
|
|
123
123
|
cd my_app
|
|
124
124
|
voodoo dev
|
|
125
125
|
```
|
|
126
126
|
|
|
127
127
|
Open `http://localhost:8000` — that's it. No npm, no bundler, no config files.
|
|
128
128
|
|
|
129
|
-
|
|
129
|
+
`voodoo create` scaffolds a full local runtime app with durable tasks, scheduler, events, and agent runtime — all on zero infrastructure. The generated app includes a crash/restart demo proving durability.
|
|
130
|
+
|
|
131
|
+
> **Want a minimal scaffold?** Use `voodoo new` instead for a bare-bones app with just UI routing.
|
|
130
132
|
|
|
131
133
|
> **Want AI features?** Install with `pip install "voodoo-framework[ai]"` to add OpenAI, Anthropic, Gemini, and Ollama SDKs.
|
|
132
134
|
|
|
@@ -232,7 +234,7 @@ if __name__ == "__main__":
|
|
|
232
234
|
| **Human-in-the-Loop** | `ask_human()` + `approve()`/`deny()` — humans as compute participants, not afterthoughts |
|
|
233
235
|
| **Adaptive execution** | Planner resolves capabilities to compute participants; supervisor steers with retry, fallback, budget control |
|
|
234
236
|
| **Durable by default** | Tasks, executions, schedules, and events survive process restarts — backed by SQLite out of the box |
|
|
235
|
-
| **Zero-config runtime** | `voodoo
|
|
237
|
+
| **Zero-config runtime** | `voodoo create` → `voodoo dev` → working app. No build step. Add `voodoo.toml` when you need configuration |
|
|
236
238
|
| **Local-first, cloud-capable** | SQLite by default; PostgreSQL, Redis, and S3/R2 are optional adapters behind the same contracts |
|
|
237
239
|
|
|
238
240
|
## The Computational Model
|
|
@@ -44,6 +44,7 @@ src/voodoo/cli/agents.py
|
|
|
44
44
|
src/voodoo/cli/ai.py
|
|
45
45
|
src/voodoo/cli/approvals.py
|
|
46
46
|
src/voodoo/cli/auth.py
|
|
47
|
+
src/voodoo/cli/create.py
|
|
47
48
|
src/voodoo/cli/dev.py
|
|
48
49
|
src/voodoo/cli/doctor.py
|
|
49
50
|
src/voodoo/cli/executions.py
|
|
@@ -188,6 +189,7 @@ tests/test_cli_inspect.py
|
|
|
188
189
|
tests/test_components.py
|
|
189
190
|
tests/test_config.py
|
|
190
191
|
tests/test_contract_api.py
|
|
192
|
+
tests/test_create.py
|
|
191
193
|
tests/test_data.py
|
|
192
194
|
tests/test_design_system.py
|
|
193
195
|
tests/test_durable_hitl.py
|