voodoo-framework 3.1.0__tar.gz → 3.2.1__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-3.1.0 → voodoo_framework-3.2.1}/PKG-INFO +4 -2
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/README.md +1 -1
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/pyproject.toml +3 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/__init__.py +1 -1
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/adapters/tailwind.py +28 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/adapters/voodoo_css.py +21 -4
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/agents/registry.py +122 -3
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/cli/__init__.py +1 -1
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/cli/agents.py +5 -12
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/cli/approvals.py +21 -15
- voodoo_framework-3.2.1/src/voodoo/cli/context.py +195 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/cli/dev.py +8 -11
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/cli/doctor.py +120 -14
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/cli/executions.py +8 -14
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/cli/inspect.py +4 -4
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/cli/new.py +22 -19
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/cli/objects.py +7 -7
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/cli/recover.py +15 -21
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/cli/scaffolding.py +34 -28
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/cli/schedules.py +6 -5
- voodoo_framework-3.2.1/src/voodoo/cli/status.py +107 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/static/client.js +200 -6
- voodoo_framework-3.2.1/src/voodoo/storage/objects/__init__.py +17 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/ui/data_extended.py +28 -3
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/ui/library.py +65 -58
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/ui/rendering.py +8 -8
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/ui/state.py +16 -3
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/ui/styles/system.py +279 -3
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/ui/styles/theme_contract.py +7 -7
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/ui/workspace.py +45 -11
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo_framework.egg-info/PKG-INFO +4 -2
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo_framework.egg-info/SOURCES.txt +1 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo_framework.egg-info/requires.txt +3 -0
- voodoo_framework-3.1.0/src/voodoo/cli/status.py +0 -73
- voodoo_framework-3.1.0/src/voodoo/storage/objects/__init__.py +0 -12
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/LICENSE +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/setup.cfg +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/adapters/__init__.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/adapters/capabilities.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/adapters/registry.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/agents/__init__.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/agents/models.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/ai/__init__.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/ai/agent.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/ai/agent_legacy.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/ai/agent_runtime_truth.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/ai/providers/__init__.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/ai/providers/anthropic.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/ai/providers/gemini.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/ai/providers/mock.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/ai/providers/ollama.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/ai/providers/openai.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/ai/tools/__init__.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/ai/tools/registry.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/auth/__init__.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/auth/cookies.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/auth/guards.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/auth/jwt.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/auth/middleware.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/auth/passwords.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/auth/user.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/cli/__main__.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/cli/ai.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/cli/auth.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/cli/create.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/cli/fabric.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/cli/generate.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/cli/graph.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/cli/protocol.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/cli/routes.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/cli/start.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/cli/tasks.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/cli/terminal.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/cli/theme.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/cli/version.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/cli/workers_cmd.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/components.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/config.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/core/__init__.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/core/app.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/core/errors.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/core/events.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/core/render.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/core/routing.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/core/sitemap.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/core/state.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/data/__init__.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/data/base.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/data/model.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/data/store_backend.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/data/store_facade.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/data/store_model.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/edge/__init__.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/edge/auth.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/edge/errors.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/edge/gateway.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/edge/http.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/edge/models.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/edge/mqtt.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/edge/protocol.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/edge/simulator.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/edge/store.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/edge/store_voodoo.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/edge/world.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/i18n.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/integrations/__init__.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/integrations/ai/__init__.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/integrations/ai/anthropic.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/integrations/ai/gemini.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/integrations/ai/ollama.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/integrations/ai/openai.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/integrations/mcp/__init__.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/integrations/mcp/client.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/integrations/otel.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/memory/__init__.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/memory/interfaces.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/memory/sqlite.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/mesh/__init__.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/mesh/client.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/mesh/event_bus.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/observability/__init__.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/observability/api.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/observability/middleware.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/observability/store.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/primitives/__init__.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/primitives/capability.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/primitives/compute.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/primitives/constraint.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/primitives/effect.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/primitives/intent.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/primitives/resource.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/primitives/state.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/primitives/time.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/protocol/__init__.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/protocol/export.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/protocol/fabric.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/protocol/operational.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/protocol/schemas.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/py.typed +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/routing/api.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/routing/pages.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/runtime/__init__.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/runtime/agency/__init__.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/runtime/agency/adaptive.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/runtime/agency/goal.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/runtime/agency/goal_store.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/runtime/application_graph.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/runtime/capability.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/runtime/constraint.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/runtime/context.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/runtime/conventions.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/runtime/dependency_graph.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/runtime/distributed/__init__.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/runtime/distributed/auth.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/runtime/distributed/fabric.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/runtime/distributed/membership.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/runtime/distributed/remote.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/runtime/distributed/replay.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/runtime/errors.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/runtime/execution/__init__.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/runtime/execution/engine.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/runtime/execution/model.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/runtime/execution/world.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/runtime/extension.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/runtime/graph.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/runtime/human.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/runtime/identity.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/runtime/identity_store.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/runtime/inspection/__init__.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/runtime/inspection/dashboard.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/runtime/inspection/lineage.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/runtime/operations.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/runtime/persistence.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/runtime/planner.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/runtime/policy.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/runtime/reconciliation/__init__.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/runtime/reconciliation/reconcile.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/runtime/runtime.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/runtime/scheduling/__init__.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/runtime/scheduling/dispatch.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/runtime/scheduling/handoff.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/runtime/scheduling/schedule_service.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/runtime/scheduling/tasks.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/runtime/scheduling/work.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/runtime/scheduling/workers.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/runtime/store.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/runtime/task.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/runtime/transaction.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/runtime/workflow.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/runtime/workflow_store.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/schedule.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/security/__init__.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/security/cors.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/security/csrf.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/security/headers.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/security/passwords.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/security/rate_limit.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/security/redaction.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/security/secrets.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/seo.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/status.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/storage/__init__.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/storage/cache/__init__.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/storage/cache/interfaces.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/storage/cache/memory.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/storage/cache/redis.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/storage/database/__init__.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/storage/database/interfaces.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/storage/database/postgres.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/storage/database/sqlite.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/storage/events/__init__.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/storage/events/interfaces.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/storage/events/local.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/storage/events/postgres.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/storage/events/sqlite.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/storage/events/store.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/storage/execution/__init__.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/storage/execution/migrations.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/storage/execution/postgres.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/storage/execution/sqlite.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/storage/execution/store.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/storage/manager.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/storage/objects/interfaces.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/storage/objects/local.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/storage/objects/s3.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/storage/objects/store.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/storage/queue/__init__.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/storage/queue/interfaces.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/storage/queue/memory.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/storage/queue/postgres.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/storage/queue/redis.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/storage/queue/sqlite.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/storage/queue/store.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/storage/scheduler/__init__.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/storage/scheduler/sqlite.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/storage/scheduler/store.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/ui/__init__.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/ui/brand.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/ui/component.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/ui/controls.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/ui/events.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/ui/forms_extended.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/ui/foundation.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/ui/interaction_kernel.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/ui/interactions.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/ui/interactive.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/ui/layout.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/ui/markdown.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/ui/navigation.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/ui/navigation_extended.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/ui/primitives.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/ui/product.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/ui/styles/__init__.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/ui/styles/extended.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/ui/styles/palette.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/ui/styles/presets.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/ui/styles/product.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/ui/styles/theme.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/ui/styles/voodoo_system.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/ui/voodoo_system.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/world/__init__.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/world/model.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/world/models.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/world/sqlite.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo/world/store.py +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo_framework.egg-info/dependency_links.txt +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo_framework.egg-info/entry_points.txt +0 -0
- {voodoo_framework-3.1.0 → voodoo_framework-3.2.1}/src/voodoo_framework.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: voodoo-framework
|
|
3
|
-
Version: 3.1
|
|
3
|
+
Version: 3.2.1
|
|
4
4
|
Summary: The programmable runtime for adaptive applications and operational systems — from web and AI to distributed and physical systems.
|
|
5
5
|
Author-email: Helder Perez <contact@helderperez.com>
|
|
6
6
|
Maintainer-email: Helder Perez <contact@helderperez.com>
|
|
@@ -45,6 +45,8 @@ Requires-Dist: anthropic; extra == "ai"
|
|
|
45
45
|
Requires-Dist: google-generativeai; extra == "ai"
|
|
46
46
|
Requires-Dist: ollama; extra == "ai"
|
|
47
47
|
Provides-Extra: mcp
|
|
48
|
+
Provides-Extra: browser
|
|
49
|
+
Requires-Dist: playwright; extra == "browser"
|
|
48
50
|
Provides-Extra: dev
|
|
49
51
|
Requires-Dist: pytest; extra == "dev"
|
|
50
52
|
Requires-Dist: pytest-asyncio; extra == "dev"
|
|
@@ -142,7 +144,7 @@ Voodoo requires Python 3.12+.
|
|
|
142
144
|
```bash
|
|
143
145
|
pip install voodoo-framework
|
|
144
146
|
|
|
145
|
-
voodoo
|
|
147
|
+
voodoo new my_app
|
|
146
148
|
cd my_app
|
|
147
149
|
voodoo dev
|
|
148
150
|
```
|
|
@@ -750,6 +750,34 @@ _STYLES: dict[str, Callable[[dict[str, Any], Theme], str]] = {
|
|
|
750
750
|
"avatar": _avatar,
|
|
751
751
|
"avatar.img": _avatar_img,
|
|
752
752
|
"avatar.fallback": _avatar_fallback,
|
|
753
|
+
"user-badge": lambda props, theme: (
|
|
754
|
+
"inline-flex items-center gap-2 rounded-full border "
|
|
755
|
+
"border-[var(--vd-color-border)] bg-[var(--vd-color-surface)] "
|
|
756
|
+
"px-2.5 py-1 text-sm text-[var(--vd-color-text)] shadow-sm"
|
|
757
|
+
),
|
|
758
|
+
"user-badge.avatar": lambda props, theme: (
|
|
759
|
+
"inline-flex size-7 shrink-0 items-center justify-center rounded-full "
|
|
760
|
+
"bg-[var(--vd-color-secondary)] text-xs font-semibold text-white"
|
|
761
|
+
),
|
|
762
|
+
"user-badge.copy": lambda props, theme: "grid min-w-0 gap-0.5 text-left",
|
|
763
|
+
"user-badge.name": lambda props, theme: (
|
|
764
|
+
"truncate text-sm font-medium leading-tight"
|
|
765
|
+
),
|
|
766
|
+
"user-badge.meta": lambda props, theme: (
|
|
767
|
+
"text-xs capitalize text-[var(--vd-color-text-muted)]"
|
|
768
|
+
),
|
|
769
|
+
"user-badge.action": lambda props, theme: (
|
|
770
|
+
"ml-1 text-xs text-[var(--vd-color-text-muted)] no-underline "
|
|
771
|
+
"hover:text-[var(--vd-color-danger)]"
|
|
772
|
+
),
|
|
773
|
+
"auth-guard": lambda props, theme: (
|
|
774
|
+
"p-3 text-center text-sm "
|
|
775
|
+
+ (
|
|
776
|
+
"font-medium text-[var(--vd-color-danger)]"
|
|
777
|
+
if props.get("variant") == "error"
|
|
778
|
+
else "text-[var(--vd-color-text-muted)]"
|
|
779
|
+
)
|
|
780
|
+
),
|
|
753
781
|
"divider": _divider,
|
|
754
782
|
"dialog": _dialog,
|
|
755
783
|
"modal": _modal,
|
|
@@ -605,9 +605,12 @@ button, input, select, textarea {{ font: inherit; color: inherit; }}
|
|
|
605
605
|
border: 1px solid var(--vd-color-border); background: var(--vd-color-surface);
|
|
606
606
|
border-radius: {r}xl); box-shadow: {sh}lg);
|
|
607
607
|
padding: {s}xl); width: 100%; max-width: 32rem;
|
|
608
|
-
margin: auto;
|
|
609
|
-
|
|
608
|
+
margin: auto; color: var(--vd-color-text);
|
|
609
|
+
}}
|
|
610
|
+
.vd-modal[open] {{
|
|
611
|
+
display: flex; flex-direction: column; gap: {s}md);
|
|
610
612
|
}}
|
|
613
|
+
.vd-modal:not([open]) {{ display: none; }}
|
|
611
614
|
.vd-modal::backdrop {{ background: rgb(0 0 0 / 0.6); }}
|
|
612
615
|
|
|
613
616
|
/* Link */
|
|
@@ -1187,8 +1190,22 @@ button, input, select, textarea {{ font: inherit; color: inherit; }}
|
|
|
1187
1190
|
font-size: {t}xs); font-weight: var(--vd-weight-semibold);
|
|
1188
1191
|
text-transform: uppercase;
|
|
1189
1192
|
}}
|
|
1190
|
-
.vd-user-badge-
|
|
1191
|
-
|
|
1193
|
+
.vd-user-badge-copy {{
|
|
1194
|
+
display: grid; gap: 0.125rem; min-width: 0; text-align: left;
|
|
1195
|
+
}}
|
|
1196
|
+
.vd-user-badge-name {{
|
|
1197
|
+
line-height: 1.1; font-size: {t}sm);
|
|
1198
|
+
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
|
1199
|
+
}}
|
|
1200
|
+
.vd-user-badge-meta {{
|
|
1201
|
+
font-size: {t}xs); color: var(--vd-color-text-muted);
|
|
1202
|
+
text-transform: capitalize;
|
|
1203
|
+
}}
|
|
1204
|
+
.vd-user-badge-action {{
|
|
1205
|
+
margin-left: {s}xs); color: var(--vd-color-text-muted);
|
|
1206
|
+
font-size: {t}xs); text-decoration: none;
|
|
1207
|
+
}}
|
|
1208
|
+
.vd-user-badge-action:hover {{ color: var(--vd-color-danger); }}
|
|
1192
1209
|
|
|
1193
1210
|
/* Auth guard */
|
|
1194
1211
|
.vd-auth-guard {{
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
"""Agent registry
|
|
1
|
+
"""Agent registry persistence.
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
Voodoo Store is the canonical durable backend. SQLite remains an explicit
|
|
4
|
+
compatibility adapter; the in-memory implementation is intended for tests.
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
from __future__ import annotations
|
|
@@ -16,6 +16,7 @@ from voodoo.agents.models import AgentEntity, AgentRunRecord
|
|
|
16
16
|
__all__ = [
|
|
17
17
|
"AgentRegistry",
|
|
18
18
|
"InMemoryAgentRegistry",
|
|
19
|
+
"VoodooStoreAgentRegistry",
|
|
19
20
|
"SQLiteAgentRegistry",
|
|
20
21
|
]
|
|
21
22
|
|
|
@@ -133,6 +134,124 @@ class InMemoryAgentRegistry:
|
|
|
133
134
|
return len(self._runs.get(agent_id, []))
|
|
134
135
|
|
|
135
136
|
|
|
137
|
+
# ---------------------------------------------------------------------------
|
|
138
|
+
# Voodoo Store implementation
|
|
139
|
+
# ---------------------------------------------------------------------------
|
|
140
|
+
|
|
141
|
+
_AGENT_PREFIX = b"runtime:agent:entity:"
|
|
142
|
+
_RUN_PREFIX = b"runtime:agent:run:"
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
class VoodooStoreAgentRegistry:
|
|
146
|
+
"""Durable agent registry backed by the active application RuntimeStore."""
|
|
147
|
+
|
|
148
|
+
def __init__(self) -> None:
|
|
149
|
+
from voodoo.core.errors import ConfigurationError
|
|
150
|
+
from voodoo.runtime.store import get_active_runtime_store
|
|
151
|
+
|
|
152
|
+
runtime_store = get_active_runtime_store()
|
|
153
|
+
if runtime_store is None:
|
|
154
|
+
raise ConfigurationError(
|
|
155
|
+
"Agent registry requires the active application RuntimeStore."
|
|
156
|
+
)
|
|
157
|
+
provider = runtime_store.provider or runtime_store.start()
|
|
158
|
+
native = None if provider is None else getattr(provider, "native", None)
|
|
159
|
+
if native is None:
|
|
160
|
+
raise ConfigurationError(
|
|
161
|
+
"The active Voodoo Store provider does not expose durable storage."
|
|
162
|
+
)
|
|
163
|
+
self._store = native
|
|
164
|
+
|
|
165
|
+
@staticmethod
|
|
166
|
+
def _agent_key(agent_id: str) -> bytes:
|
|
167
|
+
return _AGENT_PREFIX + agent_id.encode("utf-8")
|
|
168
|
+
|
|
169
|
+
@staticmethod
|
|
170
|
+
def _run_prefix(agent_id: str) -> bytes:
|
|
171
|
+
return _RUN_PREFIX + agent_id.encode("utf-8") + b":"
|
|
172
|
+
|
|
173
|
+
@classmethod
|
|
174
|
+
def _run_key(cls, record: AgentRunRecord) -> bytes:
|
|
175
|
+
return cls._run_prefix(record.agent_id) + (
|
|
176
|
+
f"{record.started_at:020.6f}:{record.run_id}".encode()
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
@staticmethod
|
|
180
|
+
def _encode(data: dict[str, Any]) -> bytes:
|
|
181
|
+
return json.dumps(data, separators=(",", ":"), default=str).encode("utf-8")
|
|
182
|
+
|
|
183
|
+
@staticmethod
|
|
184
|
+
def _decode(raw: bytes) -> dict[str, Any]:
|
|
185
|
+
return json.loads(bytes(raw).decode("utf-8"))
|
|
186
|
+
|
|
187
|
+
async def register(self, entity: AgentEntity) -> None:
|
|
188
|
+
self._store.put(
|
|
189
|
+
self._agent_key(entity.agent_id), self._encode(entity.to_dict())
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
async def get(self, agent_id: str) -> AgentEntity | None:
|
|
193
|
+
raw = self._store.get(self._agent_key(agent_id))
|
|
194
|
+
if raw is None:
|
|
195
|
+
return None
|
|
196
|
+
return AgentEntity.from_dict(self._decode(raw))
|
|
197
|
+
|
|
198
|
+
async def list_agents(
|
|
199
|
+
self,
|
|
200
|
+
state: str | None = None,
|
|
201
|
+
limit: int = 100,
|
|
202
|
+
) -> list[AgentEntity]:
|
|
203
|
+
agents = [
|
|
204
|
+
AgentEntity.from_dict(self._decode(raw))
|
|
205
|
+
for _key, raw in self._store.scan_prefix(_AGENT_PREFIX)
|
|
206
|
+
]
|
|
207
|
+
if state is not None:
|
|
208
|
+
agents = [agent for agent in agents if agent.state == state]
|
|
209
|
+
agents.sort(key=lambda agent: agent.updated_at, reverse=True)
|
|
210
|
+
return agents[:limit]
|
|
211
|
+
|
|
212
|
+
async def update(self, entity: AgentEntity) -> None:
|
|
213
|
+
if await self.get(entity.agent_id) is None:
|
|
214
|
+
raise KeyError(f"Agent '{entity.agent_id}' not found")
|
|
215
|
+
await self.register(entity)
|
|
216
|
+
|
|
217
|
+
async def delete(self, agent_id: str) -> bool:
|
|
218
|
+
if await self.get(agent_id) is None:
|
|
219
|
+
return False
|
|
220
|
+
tx = self._store.transaction()
|
|
221
|
+
tx.delete(self._agent_key(agent_id))
|
|
222
|
+
for key, _raw in tx.scan_prefix(self._run_prefix(agent_id)):
|
|
223
|
+
tx.delete(bytes(key))
|
|
224
|
+
tx.commit()
|
|
225
|
+
return True
|
|
226
|
+
|
|
227
|
+
async def record_run(self, record: AgentRunRecord) -> None:
|
|
228
|
+
self._store.put(self._run_key(record), self._encode(record.to_dict()))
|
|
229
|
+
|
|
230
|
+
async def get_runs(
|
|
231
|
+
self,
|
|
232
|
+
agent_id: str,
|
|
233
|
+
limit: int = 50,
|
|
234
|
+
) -> list[AgentRunRecord]:
|
|
235
|
+
runs = [
|
|
236
|
+
AgentRunRecord.from_dict(self._decode(raw))
|
|
237
|
+
for _key, raw in self._store.scan_prefix(self._run_prefix(agent_id))
|
|
238
|
+
]
|
|
239
|
+
runs.sort(key=lambda run: run.started_at, reverse=True)
|
|
240
|
+
return runs[:limit]
|
|
241
|
+
|
|
242
|
+
async def count_agents(self, state: str | None = None) -> int:
|
|
243
|
+
return len(await self.list_agents(state=state, limit=1_000_000))
|
|
244
|
+
|
|
245
|
+
async def count_runs(self, agent_id: str) -> int:
|
|
246
|
+
return sum(
|
|
247
|
+
1 for _key, _raw in self._store.scan_prefix(self._run_prefix(agent_id))
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
def close(self) -> None:
|
|
251
|
+
"""No-op: RuntimeStore owns the shared Store lifecycle."""
|
|
252
|
+
return None
|
|
253
|
+
|
|
254
|
+
|
|
136
255
|
# ---------------------------------------------------------------------------
|
|
137
256
|
# SQLite implementation
|
|
138
257
|
# ---------------------------------------------------------------------------
|
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
"""voodoo agents — list and inspect
|
|
2
|
-
|
|
3
|
-
Reads from the agent registry (SQLite by default). Falls back to
|
|
4
|
-
in-memory state when no durable store is available.
|
|
5
|
-
"""
|
|
1
|
+
"""voodoo agents — list and inspect agents from application persistence."""
|
|
6
2
|
|
|
7
3
|
from __future__ import annotations
|
|
8
4
|
|
|
@@ -19,15 +15,12 @@ agents_app = typer.Typer(
|
|
|
19
15
|
|
|
20
16
|
|
|
21
17
|
def _get_registry():
|
|
22
|
-
"""Return
|
|
23
|
-
from voodoo.
|
|
24
|
-
from voodoo.config import config
|
|
18
|
+
"""Return the application agent registry (Voodoo Store by default)."""
|
|
19
|
+
from voodoo.cli.context import acquire_agent_registry
|
|
25
20
|
|
|
26
|
-
db_path = config.db_path.replace(":memory:", ".voodoo/state/data.db").replace(
|
|
27
|
-
"data.db", "agents.db"
|
|
28
|
-
)
|
|
29
21
|
try:
|
|
30
|
-
|
|
22
|
+
registry, _store_path = acquire_agent_registry()
|
|
23
|
+
return registry
|
|
31
24
|
except Exception:
|
|
32
25
|
return None
|
|
33
26
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Sprint 18: human approval is an execution state that survives process
|
|
4
4
|
death. This CLI reads and decides approvals directly from the durable
|
|
5
|
-
execution store (
|
|
5
|
+
canonical execution store (Voodoo Store by default), so a decision can be made on any
|
|
6
6
|
machine — the waiting execution resumes on whichever worker picks it up.
|
|
7
7
|
|
|
8
8
|
voodoo approvals list [--pending] [--json]
|
|
@@ -34,19 +34,17 @@ approvals_app = typer.Typer(
|
|
|
34
34
|
|
|
35
35
|
|
|
36
36
|
def _resolve_store(store_path: str | None):
|
|
37
|
-
"""Return
|
|
38
|
-
from voodoo.
|
|
37
|
+
"""Return canonical execution storage unless a legacy path is explicit."""
|
|
38
|
+
from voodoo.cli.context import acquire_execution_store
|
|
39
39
|
from voodoo.runtime.persistence import JSONFileExecutionStore
|
|
40
40
|
from voodoo.storage.execution import SQLiteExecutionStore
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
return JSONFileExecutionStore(store_path), store_path
|
|
49
|
-
return SQLiteExecutionStore(store_path), store_path
|
|
42
|
+
explicit = store_path or os.environ.get("VOODOO_EXECUTION_STORE")
|
|
43
|
+
if explicit is None:
|
|
44
|
+
return acquire_execution_store()
|
|
45
|
+
if Path(explicit).suffix == ".jsonl":
|
|
46
|
+
return JSONFileExecutionStore(explicit), explicit
|
|
47
|
+
return SQLiteExecutionStore(explicit), explicit
|
|
50
48
|
|
|
51
49
|
|
|
52
50
|
def _load_app(app_str: str | None) -> None:
|
|
@@ -76,7 +74,9 @@ def list_approvals(
|
|
|
76
74
|
False, "--pending", help="Only show pending approvals"
|
|
77
75
|
),
|
|
78
76
|
store_path: str = typer.Option(
|
|
79
|
-
None,
|
|
77
|
+
None,
|
|
78
|
+
"--store",
|
|
79
|
+
help="Legacy execution-store path; default uses application.vstore",
|
|
80
80
|
),
|
|
81
81
|
app_str: str = typer.Option(
|
|
82
82
|
None, "--app", help="App instance (e.g. main:app) to import first"
|
|
@@ -120,7 +120,9 @@ def list_approvals(
|
|
|
120
120
|
def show_approval(
|
|
121
121
|
execution_id: str = typer.Argument(..., help="Execution id of the approval"),
|
|
122
122
|
store_path: str = typer.Option(
|
|
123
|
-
None,
|
|
123
|
+
None,
|
|
124
|
+
"--store",
|
|
125
|
+
help="Legacy execution-store path; default uses application.vstore",
|
|
124
126
|
),
|
|
125
127
|
json_mode: bool = typer.Option(
|
|
126
128
|
False, "--json", help="Machine-readable JSON output"
|
|
@@ -235,7 +237,9 @@ def approve_cmd(
|
|
|
235
237
|
by: str = typer.Option("human", "--by", help="Who is approving"),
|
|
236
238
|
note: str = typer.Option(None, "--note", help="Optional note"),
|
|
237
239
|
store_path: str = typer.Option(
|
|
238
|
-
None,
|
|
240
|
+
None,
|
|
241
|
+
"--store",
|
|
242
|
+
help="Legacy execution-store path; default uses application.vstore",
|
|
239
243
|
),
|
|
240
244
|
app_str: str = typer.Option(
|
|
241
245
|
None, "--app", help="App instance (e.g. main:app) to import first"
|
|
@@ -262,7 +266,9 @@ def deny_cmd(
|
|
|
262
266
|
by: str = typer.Option("human", "--by", help="Who is denying"),
|
|
263
267
|
reason: str = typer.Option(None, "--reason", help="Denial reason"),
|
|
264
268
|
store_path: str = typer.Option(
|
|
265
|
-
None,
|
|
269
|
+
None,
|
|
270
|
+
"--store",
|
|
271
|
+
help="Legacy execution-store path; default uses application.vstore",
|
|
266
272
|
),
|
|
267
273
|
app_str: str = typer.Option(
|
|
268
274
|
None, "--app", help="App instance (e.g. main:app) to import first"
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
"""Canonical Store-first operational context for Voodoo CLI commands.
|
|
2
|
+
|
|
3
|
+
CLI commands must observe the same application infrastructure contract as the
|
|
4
|
+
Runtime. The default path opens exactly one application RuntimeStore and binds
|
|
5
|
+
it for domain adapters; SQL adapters are resolved only when explicitly
|
|
6
|
+
configured by the application.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from collections.abc import Iterator
|
|
12
|
+
from contextlib import contextmanager
|
|
13
|
+
from dataclasses import dataclass
|
|
14
|
+
from typing import Any
|
|
15
|
+
|
|
16
|
+
from voodoo.config import VoodooConfig, get_config
|
|
17
|
+
from voodoo.data.store_backend import bind_runtime_store
|
|
18
|
+
from voodoo.runtime.store import (
|
|
19
|
+
RuntimeStore,
|
|
20
|
+
StoreConfig,
|
|
21
|
+
activate_runtime_store,
|
|
22
|
+
bind_active_runtime_store,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@dataclass(slots=True)
|
|
27
|
+
class CLIApplicationContext:
|
|
28
|
+
"""Operational view of the current Voodoo application."""
|
|
29
|
+
|
|
30
|
+
config: VoodooConfig
|
|
31
|
+
runtime_store: RuntimeStore
|
|
32
|
+
|
|
33
|
+
@property
|
|
34
|
+
def store_path(self) -> str:
|
|
35
|
+
return str(self.runtime_store.config.path)
|
|
36
|
+
|
|
37
|
+
def execution_store(self):
|
|
38
|
+
"""Return the configured execution store.
|
|
39
|
+
|
|
40
|
+
Voodoo Store is the default. SQLite/PostgreSQL are compatibility
|
|
41
|
+
adapters and are imported only when the user explicitly selects them.
|
|
42
|
+
"""
|
|
43
|
+
provider = self.config.database.provider.strip().lower()
|
|
44
|
+
if provider == "voodoo":
|
|
45
|
+
from voodoo.storage.execution import VoodooStoreExecutionStore
|
|
46
|
+
|
|
47
|
+
return VoodooStoreExecutionStore()
|
|
48
|
+
if provider == "sqlite":
|
|
49
|
+
from voodoo.storage.execution import SQLiteExecutionStore
|
|
50
|
+
|
|
51
|
+
path = self.config.database.path or self.config.db_path
|
|
52
|
+
if not path:
|
|
53
|
+
raise RuntimeError(
|
|
54
|
+
"database.provider='sqlite' requires database.path or VOODOO_DB_PATH"
|
|
55
|
+
)
|
|
56
|
+
return SQLiteExecutionStore(path)
|
|
57
|
+
if provider in {"postgres", "postgresql"}:
|
|
58
|
+
from voodoo.storage.execution import PostgresExecutionStore
|
|
59
|
+
|
|
60
|
+
url = self.config.database.url or self.config.db_path
|
|
61
|
+
if not url:
|
|
62
|
+
raise RuntimeError(
|
|
63
|
+
"database.provider='postgres' requires database.url or DATABASE_URL"
|
|
64
|
+
)
|
|
65
|
+
return PostgresExecutionStore(url)
|
|
66
|
+
raise RuntimeError(
|
|
67
|
+
f"Unknown execution provider {self.config.database.provider!r}. "
|
|
68
|
+
"Use 'voodoo' (default), 'sqlite', or 'postgres'."
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
def schedule_store(self):
|
|
72
|
+
from voodoo.storage.scheduler import create_schedule_store
|
|
73
|
+
|
|
74
|
+
return create_schedule_store()
|
|
75
|
+
|
|
76
|
+
def object_store(self):
|
|
77
|
+
provider = self.config.objects.provider.strip().lower()
|
|
78
|
+
if provider == "voodoo":
|
|
79
|
+
from voodoo.storage.objects import VoodooStoreObjectStore
|
|
80
|
+
|
|
81
|
+
return VoodooStoreObjectStore()
|
|
82
|
+
if provider == "local":
|
|
83
|
+
from voodoo.storage.objects import LocalObjectStore
|
|
84
|
+
|
|
85
|
+
return LocalObjectStore(self.config.objects.base_dir or ".voodoo/objects")
|
|
86
|
+
if provider == "s3":
|
|
87
|
+
from voodoo.storage.objects import S3ObjectStore
|
|
88
|
+
|
|
89
|
+
return S3ObjectStore()
|
|
90
|
+
raise RuntimeError(
|
|
91
|
+
f"Unknown object provider {self.config.objects.provider!r}. "
|
|
92
|
+
"Use 'voodoo' (default), 'local', or 's3'."
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
def agent_registry(self):
|
|
96
|
+
provider = self.config.database.provider.strip().lower()
|
|
97
|
+
if provider == "voodoo":
|
|
98
|
+
from voodoo.agents.registry import VoodooStoreAgentRegistry
|
|
99
|
+
|
|
100
|
+
return VoodooStoreAgentRegistry()
|
|
101
|
+
if provider == "sqlite":
|
|
102
|
+
from voodoo.agents.registry import SQLiteAgentRegistry
|
|
103
|
+
|
|
104
|
+
base = self.config.database.path or self.config.db_path
|
|
105
|
+
if not base:
|
|
106
|
+
raise RuntimeError(
|
|
107
|
+
"database.provider='sqlite' requires database.path or VOODOO_DB_PATH"
|
|
108
|
+
)
|
|
109
|
+
path = base.replace("data.db", "agents.db")
|
|
110
|
+
return SQLiteAgentRegistry(path)
|
|
111
|
+
raise RuntimeError(
|
|
112
|
+
"Agent registry currently supports the default Voodoo Store or an "
|
|
113
|
+
"explicit SQLite compatibility adapter."
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
@contextmanager
|
|
118
|
+
def open_application_context() -> Iterator[CLIApplicationContext]:
|
|
119
|
+
"""Open the current application using the Runtime's canonical Store lifecycle."""
|
|
120
|
+
config = get_config()
|
|
121
|
+
runtime_store = activate_runtime_store(
|
|
122
|
+
StoreConfig.from_mapping(config.store.model_dump())
|
|
123
|
+
)
|
|
124
|
+
bind_runtime_store(runtime_store)
|
|
125
|
+
try:
|
|
126
|
+
yield CLIApplicationContext(config=config, runtime_store=runtime_store)
|
|
127
|
+
finally:
|
|
128
|
+
bind_runtime_store(None)
|
|
129
|
+
bind_active_runtime_store(None)
|
|
130
|
+
runtime_store.stop()
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
class ManagedCLIResource:
|
|
134
|
+
"""Proxy that keeps the canonical CLI application context alive."""
|
|
135
|
+
|
|
136
|
+
def __init__(self, resource: Any, context_manager: Any) -> None:
|
|
137
|
+
self._resource = resource
|
|
138
|
+
self._context_manager = context_manager
|
|
139
|
+
self._closed = False
|
|
140
|
+
|
|
141
|
+
def __getattr__(self, name: str) -> Any:
|
|
142
|
+
return getattr(self._resource, name)
|
|
143
|
+
|
|
144
|
+
def close(self) -> None:
|
|
145
|
+
if self._closed:
|
|
146
|
+
return
|
|
147
|
+
self._closed = True
|
|
148
|
+
try:
|
|
149
|
+
close = getattr(self._resource, "close", None)
|
|
150
|
+
if close is not None:
|
|
151
|
+
close()
|
|
152
|
+
finally:
|
|
153
|
+
self._context_manager.__exit__(None, None, None)
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def _acquire_resource(factory: str) -> tuple[ManagedCLIResource, str]:
|
|
157
|
+
manager = open_application_context()
|
|
158
|
+
context = manager.__enter__()
|
|
159
|
+
try:
|
|
160
|
+
resource = getattr(context, factory)()
|
|
161
|
+
except Exception as exc:
|
|
162
|
+
manager.__exit__(type(exc), exc, exc.__traceback__)
|
|
163
|
+
raise
|
|
164
|
+
return ManagedCLIResource(resource, manager), context.store_path
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def acquire_execution_store() -> tuple[ManagedCLIResource, str]:
|
|
168
|
+
"""Open execution persistence through the canonical application context."""
|
|
169
|
+
return _acquire_resource("execution_store")
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def acquire_schedule_store() -> tuple[ManagedCLIResource, str]:
|
|
173
|
+
"""Open scheduler persistence through the canonical application context."""
|
|
174
|
+
return _acquire_resource("schedule_store")
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def acquire_object_store() -> tuple[ManagedCLIResource, str]:
|
|
178
|
+
"""Open object persistence through the canonical application context."""
|
|
179
|
+
return _acquire_resource("object_store")
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def acquire_agent_registry() -> tuple[ManagedCLIResource, str]:
|
|
183
|
+
"""Open the agent registry through the canonical application context."""
|
|
184
|
+
return _acquire_resource("agent_registry")
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
__all__ = [
|
|
188
|
+
"CLIApplicationContext",
|
|
189
|
+
"ManagedCLIResource",
|
|
190
|
+
"open_application_context",
|
|
191
|
+
"acquire_execution_store",
|
|
192
|
+
"acquire_schedule_store",
|
|
193
|
+
"acquire_object_store",
|
|
194
|
+
"acquire_agent_registry",
|
|
195
|
+
]
|
|
@@ -130,13 +130,14 @@ def _print_runtime_banner() -> None:
|
|
|
130
130
|
|
|
131
131
|
# Providers
|
|
132
132
|
terminal.heading("providers")
|
|
133
|
-
|
|
134
|
-
terminal.
|
|
133
|
+
terminal.status("store", cfg.store.provider.lower())
|
|
134
|
+
terminal.muted(f" {cfg.store.path}")
|
|
135
135
|
|
|
136
|
-
|
|
137
|
-
|
|
136
|
+
db_provider = cfg.database.provider.lower()
|
|
137
|
+
if db_provider != "voodoo":
|
|
138
|
+
terminal.status("database", db_provider)
|
|
138
139
|
|
|
139
|
-
|
|
140
|
+
terminal.status("queue", cfg.queue.provider.lower())
|
|
140
141
|
terminal.status("objects", cfg.objects.provider.lower())
|
|
141
142
|
|
|
142
143
|
# Agent runtime
|
|
@@ -163,11 +164,7 @@ def _print_runtime_banner() -> None:
|
|
|
163
164
|
except Exception:
|
|
164
165
|
terminal.label_value("workers", "none")
|
|
165
166
|
|
|
166
|
-
# Schedules
|
|
167
|
-
|
|
168
|
-
if schedule_path.exists():
|
|
169
|
-
terminal.status("scheduler", "ready")
|
|
170
|
-
else:
|
|
171
|
-
terminal.status("scheduler", "will be created")
|
|
167
|
+
# Schedules share the application Store by default.
|
|
168
|
+
terminal.status("scheduler", cfg.store.provider.lower())
|
|
172
169
|
|
|
173
170
|
terminal.blank()
|