voodoo-framework 3.1.0__tar.gz → 3.2.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.
Files changed (268) hide show
  1. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/PKG-INFO +4 -2
  2. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/README.md +1 -1
  3. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/pyproject.toml +3 -0
  4. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/__init__.py +1 -1
  5. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/adapters/tailwind.py +28 -0
  6. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/adapters/voodoo_css.py +21 -4
  7. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/agents/registry.py +122 -3
  8. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/cli/__init__.py +1 -1
  9. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/cli/agents.py +5 -12
  10. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/cli/approvals.py +21 -15
  11. voodoo_framework-3.2.0/src/voodoo/cli/context.py +195 -0
  12. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/cli/dev.py +8 -11
  13. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/cli/doctor.py +120 -14
  14. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/cli/executions.py +8 -14
  15. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/cli/inspect.py +4 -4
  16. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/cli/new.py +22 -19
  17. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/cli/objects.py +7 -7
  18. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/cli/recover.py +15 -21
  19. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/cli/scaffolding.py +34 -28
  20. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/cli/schedules.py +6 -5
  21. voodoo_framework-3.2.0/src/voodoo/cli/status.py +107 -0
  22. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/static/client.js +200 -6
  23. voodoo_framework-3.2.0/src/voodoo/storage/objects/__init__.py +17 -0
  24. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/ui/data_extended.py +28 -3
  25. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/ui/library.py +65 -58
  26. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/ui/rendering.py +8 -8
  27. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/ui/styles/system.py +279 -3
  28. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/ui/styles/theme_contract.py +7 -7
  29. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/ui/workspace.py +45 -11
  30. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo_framework.egg-info/PKG-INFO +4 -2
  31. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo_framework.egg-info/SOURCES.txt +1 -0
  32. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo_framework.egg-info/requires.txt +3 -0
  33. voodoo_framework-3.1.0/src/voodoo/cli/status.py +0 -73
  34. voodoo_framework-3.1.0/src/voodoo/storage/objects/__init__.py +0 -12
  35. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/LICENSE +0 -0
  36. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/setup.cfg +0 -0
  37. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/adapters/__init__.py +0 -0
  38. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/adapters/capabilities.py +0 -0
  39. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/adapters/registry.py +0 -0
  40. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/agents/__init__.py +0 -0
  41. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/agents/models.py +0 -0
  42. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/ai/__init__.py +0 -0
  43. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/ai/agent.py +0 -0
  44. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/ai/agent_legacy.py +0 -0
  45. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/ai/agent_runtime_truth.py +0 -0
  46. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/ai/providers/__init__.py +0 -0
  47. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/ai/providers/anthropic.py +0 -0
  48. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/ai/providers/gemini.py +0 -0
  49. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/ai/providers/mock.py +0 -0
  50. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/ai/providers/ollama.py +0 -0
  51. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/ai/providers/openai.py +0 -0
  52. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/ai/tools/__init__.py +0 -0
  53. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/ai/tools/registry.py +0 -0
  54. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/auth/__init__.py +0 -0
  55. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/auth/cookies.py +0 -0
  56. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/auth/guards.py +0 -0
  57. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/auth/jwt.py +0 -0
  58. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/auth/middleware.py +0 -0
  59. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/auth/passwords.py +0 -0
  60. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/auth/user.py +0 -0
  61. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/cli/__main__.py +0 -0
  62. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/cli/ai.py +0 -0
  63. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/cli/auth.py +0 -0
  64. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/cli/create.py +0 -0
  65. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/cli/fabric.py +0 -0
  66. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/cli/generate.py +0 -0
  67. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/cli/graph.py +0 -0
  68. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/cli/protocol.py +0 -0
  69. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/cli/routes.py +0 -0
  70. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/cli/start.py +0 -0
  71. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/cli/tasks.py +0 -0
  72. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/cli/terminal.py +0 -0
  73. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/cli/theme.py +0 -0
  74. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/cli/version.py +0 -0
  75. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/cli/workers_cmd.py +0 -0
  76. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/components.py +0 -0
  77. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/config.py +0 -0
  78. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/core/__init__.py +0 -0
  79. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/core/app.py +0 -0
  80. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/core/errors.py +0 -0
  81. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/core/events.py +0 -0
  82. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/core/render.py +0 -0
  83. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/core/routing.py +0 -0
  84. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/core/sitemap.py +0 -0
  85. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/core/state.py +0 -0
  86. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/data/__init__.py +0 -0
  87. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/data/base.py +0 -0
  88. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/data/model.py +0 -0
  89. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/data/store_backend.py +0 -0
  90. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/data/store_facade.py +0 -0
  91. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/data/store_model.py +0 -0
  92. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/edge/__init__.py +0 -0
  93. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/edge/auth.py +0 -0
  94. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/edge/errors.py +0 -0
  95. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/edge/gateway.py +0 -0
  96. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/edge/http.py +0 -0
  97. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/edge/models.py +0 -0
  98. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/edge/mqtt.py +0 -0
  99. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/edge/protocol.py +0 -0
  100. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/edge/simulator.py +0 -0
  101. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/edge/store.py +0 -0
  102. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/edge/store_voodoo.py +0 -0
  103. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/edge/world.py +0 -0
  104. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/i18n.py +0 -0
  105. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/integrations/__init__.py +0 -0
  106. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/integrations/ai/__init__.py +0 -0
  107. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/integrations/ai/anthropic.py +0 -0
  108. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/integrations/ai/gemini.py +0 -0
  109. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/integrations/ai/ollama.py +0 -0
  110. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/integrations/ai/openai.py +0 -0
  111. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/integrations/mcp/__init__.py +0 -0
  112. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/integrations/mcp/client.py +0 -0
  113. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/integrations/otel.py +0 -0
  114. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/memory/__init__.py +0 -0
  115. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/memory/interfaces.py +0 -0
  116. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/memory/sqlite.py +0 -0
  117. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/mesh/__init__.py +0 -0
  118. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/mesh/client.py +0 -0
  119. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/mesh/event_bus.py +0 -0
  120. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/observability/__init__.py +0 -0
  121. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/observability/api.py +0 -0
  122. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/observability/middleware.py +0 -0
  123. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/observability/store.py +0 -0
  124. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/primitives/__init__.py +0 -0
  125. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/primitives/capability.py +0 -0
  126. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/primitives/compute.py +0 -0
  127. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/primitives/constraint.py +0 -0
  128. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/primitives/effect.py +0 -0
  129. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/primitives/intent.py +0 -0
  130. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/primitives/resource.py +0 -0
  131. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/primitives/state.py +0 -0
  132. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/primitives/time.py +0 -0
  133. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/protocol/__init__.py +0 -0
  134. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/protocol/export.py +0 -0
  135. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/protocol/fabric.py +0 -0
  136. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/protocol/operational.py +0 -0
  137. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/protocol/schemas.py +0 -0
  138. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/py.typed +0 -0
  139. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/routing/api.py +0 -0
  140. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/routing/pages.py +0 -0
  141. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/runtime/__init__.py +0 -0
  142. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/runtime/agency/__init__.py +0 -0
  143. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/runtime/agency/adaptive.py +0 -0
  144. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/runtime/agency/goal.py +0 -0
  145. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/runtime/agency/goal_store.py +0 -0
  146. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/runtime/application_graph.py +0 -0
  147. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/runtime/capability.py +0 -0
  148. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/runtime/constraint.py +0 -0
  149. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/runtime/context.py +0 -0
  150. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/runtime/conventions.py +0 -0
  151. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/runtime/dependency_graph.py +0 -0
  152. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/runtime/distributed/__init__.py +0 -0
  153. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/runtime/distributed/auth.py +0 -0
  154. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/runtime/distributed/fabric.py +0 -0
  155. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/runtime/distributed/membership.py +0 -0
  156. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/runtime/distributed/remote.py +0 -0
  157. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/runtime/distributed/replay.py +0 -0
  158. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/runtime/errors.py +0 -0
  159. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/runtime/execution/__init__.py +0 -0
  160. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/runtime/execution/engine.py +0 -0
  161. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/runtime/execution/model.py +0 -0
  162. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/runtime/execution/world.py +0 -0
  163. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/runtime/extension.py +0 -0
  164. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/runtime/graph.py +0 -0
  165. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/runtime/human.py +0 -0
  166. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/runtime/identity.py +0 -0
  167. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/runtime/identity_store.py +0 -0
  168. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/runtime/inspection/__init__.py +0 -0
  169. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/runtime/inspection/dashboard.py +0 -0
  170. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/runtime/inspection/lineage.py +0 -0
  171. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/runtime/operations.py +0 -0
  172. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/runtime/persistence.py +0 -0
  173. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/runtime/planner.py +0 -0
  174. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/runtime/policy.py +0 -0
  175. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/runtime/reconciliation/__init__.py +0 -0
  176. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/runtime/reconciliation/reconcile.py +0 -0
  177. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/runtime/runtime.py +0 -0
  178. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/runtime/scheduling/__init__.py +0 -0
  179. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/runtime/scheduling/dispatch.py +0 -0
  180. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/runtime/scheduling/handoff.py +0 -0
  181. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/runtime/scheduling/schedule_service.py +0 -0
  182. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/runtime/scheduling/tasks.py +0 -0
  183. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/runtime/scheduling/work.py +0 -0
  184. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/runtime/scheduling/workers.py +0 -0
  185. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/runtime/store.py +0 -0
  186. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/runtime/task.py +0 -0
  187. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/runtime/transaction.py +0 -0
  188. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/runtime/workflow.py +0 -0
  189. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/runtime/workflow_store.py +0 -0
  190. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/schedule.py +0 -0
  191. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/security/__init__.py +0 -0
  192. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/security/cors.py +0 -0
  193. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/security/csrf.py +0 -0
  194. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/security/headers.py +0 -0
  195. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/security/passwords.py +0 -0
  196. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/security/rate_limit.py +0 -0
  197. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/security/redaction.py +0 -0
  198. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/security/secrets.py +0 -0
  199. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/seo.py +0 -0
  200. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/status.py +0 -0
  201. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/storage/__init__.py +0 -0
  202. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/storage/cache/__init__.py +0 -0
  203. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/storage/cache/interfaces.py +0 -0
  204. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/storage/cache/memory.py +0 -0
  205. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/storage/cache/redis.py +0 -0
  206. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/storage/database/__init__.py +0 -0
  207. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/storage/database/interfaces.py +0 -0
  208. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/storage/database/postgres.py +0 -0
  209. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/storage/database/sqlite.py +0 -0
  210. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/storage/events/__init__.py +0 -0
  211. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/storage/events/interfaces.py +0 -0
  212. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/storage/events/local.py +0 -0
  213. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/storage/events/postgres.py +0 -0
  214. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/storage/events/sqlite.py +0 -0
  215. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/storage/events/store.py +0 -0
  216. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/storage/execution/__init__.py +0 -0
  217. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/storage/execution/migrations.py +0 -0
  218. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/storage/execution/postgres.py +0 -0
  219. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/storage/execution/sqlite.py +0 -0
  220. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/storage/execution/store.py +0 -0
  221. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/storage/manager.py +0 -0
  222. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/storage/objects/interfaces.py +0 -0
  223. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/storage/objects/local.py +0 -0
  224. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/storage/objects/s3.py +0 -0
  225. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/storage/objects/store.py +0 -0
  226. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/storage/queue/__init__.py +0 -0
  227. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/storage/queue/interfaces.py +0 -0
  228. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/storage/queue/memory.py +0 -0
  229. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/storage/queue/postgres.py +0 -0
  230. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/storage/queue/redis.py +0 -0
  231. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/storage/queue/sqlite.py +0 -0
  232. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/storage/queue/store.py +0 -0
  233. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/storage/scheduler/__init__.py +0 -0
  234. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/storage/scheduler/sqlite.py +0 -0
  235. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/storage/scheduler/store.py +0 -0
  236. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/ui/__init__.py +0 -0
  237. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/ui/brand.py +0 -0
  238. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/ui/component.py +0 -0
  239. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/ui/controls.py +0 -0
  240. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/ui/events.py +0 -0
  241. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/ui/forms_extended.py +0 -0
  242. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/ui/foundation.py +0 -0
  243. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/ui/interaction_kernel.py +0 -0
  244. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/ui/interactions.py +0 -0
  245. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/ui/interactive.py +0 -0
  246. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/ui/layout.py +0 -0
  247. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/ui/markdown.py +0 -0
  248. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/ui/navigation.py +0 -0
  249. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/ui/navigation_extended.py +0 -0
  250. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/ui/primitives.py +0 -0
  251. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/ui/product.py +0 -0
  252. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/ui/state.py +0 -0
  253. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/ui/styles/__init__.py +0 -0
  254. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/ui/styles/extended.py +0 -0
  255. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/ui/styles/palette.py +0 -0
  256. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/ui/styles/presets.py +0 -0
  257. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/ui/styles/product.py +0 -0
  258. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/ui/styles/theme.py +0 -0
  259. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/ui/styles/voodoo_system.py +0 -0
  260. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/ui/voodoo_system.py +0 -0
  261. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/world/__init__.py +0 -0
  262. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/world/model.py +0 -0
  263. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/world/models.py +0 -0
  264. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/world/sqlite.py +0 -0
  265. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo/world/store.py +0 -0
  266. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo_framework.egg-info/dependency_links.txt +0 -0
  267. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/src/voodoo_framework.egg-info/entry_points.txt +0 -0
  268. {voodoo_framework-3.1.0 → voodoo_framework-3.2.0}/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.0
3
+ Version: 3.2.0
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 create my_app
147
+ voodoo new my_app
146
148
  cd my_app
147
149
  voodoo dev
148
150
  ```
@@ -71,7 +71,7 @@ Voodoo requires Python 3.12+.
71
71
  ```bash
72
72
  pip install voodoo-framework
73
73
 
74
- voodoo create my_app
74
+ voodoo new my_app
75
75
  cd my_app
76
76
  voodoo dev
77
77
  ```
@@ -76,6 +76,9 @@ ai = [
76
76
  "ollama"
77
77
  ]
78
78
  mcp = []
79
+ browser = [
80
+ "playwright",
81
+ ]
79
82
  dev = [
80
83
  "pytest",
81
84
  "pytest-asyncio",
@@ -12,7 +12,7 @@ from .core import App, page, state
12
12
  from .data import Model
13
13
  from .runtime.scheduling.tasks import task
14
14
 
15
- __version__ = "3.1.0"
15
+ __version__ = "3.2.0"
16
16
 
17
17
  __all__ = [
18
18
  "Agent",
@@ -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; display: flex; flex-direction: column; gap: {s}md);
609
- color: var(--vd-color-text);
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-name {{ line-height: 1; font-size: {t}sm); }}
1191
- .vd-user-badge-meta {{ font-size: {t}xs); color: var(--vd-color-text-muted); }}
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 — Protocol, in-memory, and SQLite implementations (Sprint 17).
1
+ """Agent registry persistence.
2
2
 
3
- The registry persists agent identity and links every run to its execution
4
- history. The default backend is SQLite (WAL mode, busy_timeout=5000).
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
  # ---------------------------------------------------------------------------
@@ -36,7 +36,7 @@ app = typer.Typer(
36
36
  )
37
37
 
38
38
  app.command()(new.new)
39
- app.command()(create.create)
39
+ app.command("create", hidden=True)(create.create)
40
40
  app.command()(dev.dev)
41
41
  app.command()(start.start)
42
42
  app.command()(generate.generate)
@@ -1,8 +1,4 @@
1
- """voodoo agents — list and inspect registered agents.
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 an AgentRegistry — SQLite by default."""
23
- from voodoo.agents.registry import SQLiteAgentRegistry
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
- return SQLiteAgentRegistry(db_path)
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 (SQLite by default), so a decision can be made on any
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 the configured execution store (SQLite by default)."""
38
- from voodoo.config import config
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
- if store_path is None:
43
- store_path = os.environ.get("VOODOO_EXECUTION_STORE", config.db_path).replace(
44
- ":memory:", ".voodoo/state/data.db"
45
- )
46
-
47
- if Path(store_path).suffix == ".jsonl":
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, "--store", help="Path to the execution store (SQLite by default)"
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, "--store", help="Path to the execution store (SQLite by default)"
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, "--store", help="Path to the execution store (SQLite by default)"
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, "--store", help="Path to the execution store (SQLite by default)"
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
- db_provider = cfg.database.provider.lower()
134
- terminal.status("database", db_provider)
133
+ terminal.status("store", cfg.store.provider.lower())
134
+ terminal.muted(f" {cfg.store.path}")
135
135
 
136
- queue_provider = cfg.queue.provider.lower()
137
- terminal.status("queue", queue_provider)
136
+ db_provider = cfg.database.provider.lower()
137
+ if db_provider != "voodoo":
138
+ terminal.status("database", db_provider)
138
139
 
139
- # Object store
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 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")
167
+ # Schedules share the application Store by default.
168
+ terminal.status("scheduler", cfg.store.provider.lower())
172
169
 
173
170
  terminal.blank()