voodoo-framework 2.8.0__tar.gz → 2.8.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (345) hide show
  1. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/PKG-INFO +1 -1
  2. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/__init__.py +1 -1
  3. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/core/app.py +8 -0
  4. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/ui/__init__.py +1 -1
  5. voodoo_framework-2.8.2/src/voodoo/ui/brand.py +137 -0
  6. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/ui/rendering.py +4 -0
  7. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo_framework.egg-info/PKG-INFO +1 -1
  8. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo_framework.egg-info/SOURCES.txt +3 -0
  9. voodoo_framework-2.8.2/tests/test_brand.py +61 -0
  10. voodoo_framework-2.8.2/tests/test_public_assets.py +48 -0
  11. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/LICENSE +0 -0
  12. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/README.md +0 -0
  13. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/pyproject.toml +0 -0
  14. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/setup.cfg +0 -0
  15. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/adapters/__init__.py +0 -0
  16. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/adapters/capabilities.py +0 -0
  17. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/adapters/registry.py +0 -0
  18. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/adapters/tailwind.py +0 -0
  19. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/adapters/voodoo_css.py +0 -0
  20. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/agent.py +0 -0
  21. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/agents/__init__.py +0 -0
  22. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/agents/models.py +0 -0
  23. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/agents/registry.py +0 -0
  24. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/ai/__init__.py +0 -0
  25. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/ai/agent.py +0 -0
  26. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/ai/agent_legacy.py +0 -0
  27. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/ai/agent_runtime_truth.py +0 -0
  28. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/ai/providers/__init__.py +0 -0
  29. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/ai/providers/anthropic.py +0 -0
  30. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/ai/providers/gemini.py +0 -0
  31. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/ai/providers/mock.py +0 -0
  32. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/ai/providers/ollama.py +0 -0
  33. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/ai/providers/openai.py +0 -0
  34. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/ai/tools/__init__.py +0 -0
  35. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/ai/tools/registry.py +0 -0
  36. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/api.py +0 -0
  37. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/auth/__init__.py +0 -0
  38. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/auth/cookies.py +0 -0
  39. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/auth/guards.py +0 -0
  40. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/auth/jwt.py +0 -0
  41. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/auth/middleware.py +0 -0
  42. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/auth/passwords.py +0 -0
  43. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/auth/user.py +0 -0
  44. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/cli/__init__.py +0 -0
  45. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/cli/__main__.py +0 -0
  46. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/cli/agents.py +0 -0
  47. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/cli/ai.py +0 -0
  48. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/cli/approvals.py +0 -0
  49. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/cli/auth.py +0 -0
  50. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/cli/create.py +0 -0
  51. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/cli/dev.py +0 -0
  52. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/cli/doctor.py +0 -0
  53. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/cli/executions.py +0 -0
  54. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/cli/fabric.py +0 -0
  55. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/cli/generate.py +0 -0
  56. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/cli/inspect.py +0 -0
  57. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/cli/new.py +0 -0
  58. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/cli/objects.py +0 -0
  59. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/cli/protocol.py +0 -0
  60. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/cli/recover.py +0 -0
  61. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/cli/routes.py +0 -0
  62. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/cli/scaffolding.py +0 -0
  63. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/cli/schedules.py +0 -0
  64. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/cli/status.py +0 -0
  65. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/cli/tasks.py +0 -0
  66. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/cli/terminal.py +0 -0
  67. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/cli/theme.py +0 -0
  68. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/cli/version.py +0 -0
  69. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/cli/workers_cmd.py +0 -0
  70. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/components.py +0 -0
  71. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/config.py +0 -0
  72. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/core/__init__.py +0 -0
  73. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/core/errors.py +0 -0
  74. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/core/events.py +0 -0
  75. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/core/render.py +0 -0
  76. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/core/routing.py +0 -0
  77. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/core/sitemap.py +0 -0
  78. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/core/state.py +0 -0
  79. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/data/__init__.py +0 -0
  80. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/data/base.py +0 -0
  81. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/data/model.py +0 -0
  82. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/data/store_backend.py +0 -0
  83. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/data/store_facade.py +0 -0
  84. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/data/store_model.py +0 -0
  85. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/edge/__init__.py +0 -0
  86. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/edge/auth.py +0 -0
  87. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/edge/errors.py +0 -0
  88. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/edge/gateway.py +0 -0
  89. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/edge/http.py +0 -0
  90. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/edge/models.py +0 -0
  91. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/edge/mqtt.py +0 -0
  92. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/edge/protocol.py +0 -0
  93. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/edge/simulator.py +0 -0
  94. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/edge/store.py +0 -0
  95. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/edge/store_voodoo.py +0 -0
  96. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/edge/world.py +0 -0
  97. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/i18n.py +0 -0
  98. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/mcp/__init__.py +0 -0
  99. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/mcp/client.py +0 -0
  100. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/memory/__init__.py +0 -0
  101. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/memory/interfaces.py +0 -0
  102. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/memory/sqlite.py +0 -0
  103. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/mesh/__init__.py +0 -0
  104. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/mesh/auth.py +0 -0
  105. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/mesh/client.py +0 -0
  106. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/mesh/event_bus.py +0 -0
  107. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/mesh/remote.py +0 -0
  108. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/mesh/replay.py +0 -0
  109. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/primitives/__init__.py +0 -0
  110. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/primitives/capability.py +0 -0
  111. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/primitives/compute.py +0 -0
  112. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/primitives/constraint.py +0 -0
  113. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/primitives/effect.py +0 -0
  114. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/primitives/intent.py +0 -0
  115. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/primitives/resource.py +0 -0
  116. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/primitives/state.py +0 -0
  117. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/primitives/time.py +0 -0
  118. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/protocol/__init__.py +0 -0
  119. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/protocol/export.py +0 -0
  120. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/protocol/fabric.py +0 -0
  121. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/protocol/operational.py +0 -0
  122. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/protocol/schemas.py +0 -0
  123. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/py.typed +0 -0
  124. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/queue.py +0 -0
  125. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/routing/api.py +0 -0
  126. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/routing/pages.py +0 -0
  127. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/runtime/__init__.py +0 -0
  128. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/runtime/adaptive.py +0 -0
  129. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/runtime/capability.py +0 -0
  130. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/runtime/constraint.py +0 -0
  131. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/runtime/context.py +0 -0
  132. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/runtime/dashboard.py +0 -0
  133. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/runtime/engine.py +0 -0
  134. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/runtime/errors.py +0 -0
  135. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/runtime/execution.py +0 -0
  136. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/runtime/fabric.py +0 -0
  137. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/runtime/goal.py +0 -0
  138. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/runtime/goal_store.py +0 -0
  139. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/runtime/graph.py +0 -0
  140. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/runtime/human.py +0 -0
  141. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/runtime/identity.py +0 -0
  142. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/runtime/identity_store.py +0 -0
  143. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/runtime/membership.py +0 -0
  144. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/runtime/operations.py +0 -0
  145. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/runtime/persistence.py +0 -0
  146. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/runtime/planner.py +0 -0
  147. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/runtime/policy.py +0 -0
  148. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/runtime/scheduler.py +0 -0
  149. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/runtime/store.py +0 -0
  150. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/runtime/task.py +0 -0
  151. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/runtime/transaction.py +0 -0
  152. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/runtime/workflow.py +0 -0
  153. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/runtime/workflow_store.py +0 -0
  154. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/runtime/world_execution.py +0 -0
  155. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/schedule.py +0 -0
  156. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/security/__init__.py +0 -0
  157. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/security/cors.py +0 -0
  158. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/security/csrf.py +0 -0
  159. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/security/headers.py +0 -0
  160. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/security/passwords.py +0 -0
  161. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/security/rate_limit.py +0 -0
  162. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/security/redaction.py +0 -0
  163. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/security/secrets.py +0 -0
  164. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/seo.py +0 -0
  165. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/static/client.js +0 -0
  166. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/status.py +0 -0
  167. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/__init__.py +0 -0
  168. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/cache/__init__.py +0 -0
  169. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/cache/interfaces.py +0 -0
  170. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/cache/memory.py +0 -0
  171. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/cache/redis.py +0 -0
  172. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/database/__init__.py +0 -0
  173. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/database/interfaces.py +0 -0
  174. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/database/postgres.py +0 -0
  175. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/database/sqlite.py +0 -0
  176. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/events/__init__.py +0 -0
  177. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/events/interfaces.py +0 -0
  178. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/events/local.py +0 -0
  179. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/events/postgres.py +0 -0
  180. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/events/sqlite.py +0 -0
  181. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/events/store.py +0 -0
  182. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/execution/__init__.py +0 -0
  183. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/execution/migrations.py +0 -0
  184. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/execution/postgres.py +0 -0
  185. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/execution/sqlite.py +0 -0
  186. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/execution/store.py +0 -0
  187. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/manager.py +0 -0
  188. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/objects/__init__.py +0 -0
  189. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/objects/interfaces.py +0 -0
  190. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/objects/local.py +0 -0
  191. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/objects/s3.py +0 -0
  192. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/objects/store.py +0 -0
  193. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/queue/__init__.py +0 -0
  194. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/queue/interfaces.py +0 -0
  195. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/queue/memory.py +0 -0
  196. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/queue/postgres.py +0 -0
  197. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/queue/redis.py +0 -0
  198. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/queue/sqlite.py +0 -0
  199. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/queue/store.py +0 -0
  200. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/scheduler/__init__.py +0 -0
  201. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/scheduler/sqlite.py +0 -0
  202. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/storage/scheduler/store.py +0 -0
  203. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/telemetry/__init__.py +0 -0
  204. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/telemetry/api.py +0 -0
  205. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/telemetry/middleware.py +0 -0
  206. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/telemetry/otlp.py +0 -0
  207. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/telemetry/store.py +0 -0
  208. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/theme.py +0 -0
  209. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/tools/__init__.py +0 -0
  210. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/tools/registry.py +0 -0
  211. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/ui/component.py +0 -0
  212. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/ui/events.py +0 -0
  213. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/ui/interactive.py +0 -0
  214. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/ui/layout.py +0 -0
  215. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/ui/library.py +0 -0
  216. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/ui/markdown.py +0 -0
  217. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/ui/primitives.py +0 -0
  218. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/ui/product.py +0 -0
  219. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/ui/state.py +0 -0
  220. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/ui/styles/__init__.py +0 -0
  221. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/ui/styles/presets.py +0 -0
  222. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/ui/styles/product.py +0 -0
  223. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/ui/styles/system.py +0 -0
  224. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/ui/styles/theme.py +0 -0
  225. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/ui/styles/theme_contract.py +0 -0
  226. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/ui/styles/voodoo_system.py +0 -0
  227. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/ui/voodoo_system.py +0 -0
  228. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/workers/__init__.py +0 -0
  229. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/workers/queue.py +0 -0
  230. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/world/__init__.py +0 -0
  231. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/world/model.py +0 -0
  232. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/world/models.py +0 -0
  233. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/world/sqlite.py +0 -0
  234. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo/world/store.py +0 -0
  235. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo_framework.egg-info/dependency_links.txt +0 -0
  236. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo_framework.egg-info/entry_points.txt +0 -0
  237. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo_framework.egg-info/requires.txt +0 -0
  238. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/src/voodoo_framework.egg-info/top_level.txt +0 -0
  239. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_adaptive_agency_correctness.py +0 -0
  240. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_agency_runtime_truth.py +0 -0
  241. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_agent.py +0 -0
  242. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_agent_registry.py +0 -0
  243. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_agent_runtime.py +0 -0
  244. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_app.py +0 -0
  245. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_auth.py +0 -0
  246. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_capability_security.py +0 -0
  247. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_checkpoint_resume.py +0 -0
  248. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_chrome.py +0 -0
  249. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_cli.py +0 -0
  250. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_cli_fabric.py +0 -0
  251. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_cli_inspect.py +0 -0
  252. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_components.py +0 -0
  253. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_config.py +0 -0
  254. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_contract_api.py +0 -0
  255. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_create.py +0 -0
  256. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_create_store_smoke.py +0 -0
  257. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_data.py +0 -0
  258. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_design_system.py +0 -0
  259. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_design_system2.py +0 -0
  260. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_design_system_premium.py +0 -0
  261. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_design_system_theme_contract.py +0 -0
  262. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_durable_goal_runtime.py +0 -0
  263. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_durable_hitl.py +0 -0
  264. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_durable_workflow_runtime.py +0 -0
  265. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_edge_device.py +0 -0
  266. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_edge_e2e.py +0 -0
  267. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_edge_gateway.py +0 -0
  268. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_edge_http.py +0 -0
  269. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_edge_protocol.py +0 -0
  270. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_edge_security.py +0 -0
  271. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_edge_voodoo_store.py +0 -0
  272. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_edge_world.py +0 -0
  273. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_events.py +0 -0
  274. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_execution_sqlite_store.py +0 -0
  275. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_goal_runtime.py +0 -0
  276. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_hitl_persistence_correctness.py +0 -0
  277. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_http_runtime.py +0 -0
  278. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_human.py +0 -0
  279. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_i18n.py +0 -0
  280. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_identity_execution.py +0 -0
  281. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_identity_foundation.py +0 -0
  282. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_integration.py +0 -0
  283. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_mcp.py +0 -0
  284. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_mcp_runtime.py +0 -0
  285. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_memory.py +0 -0
  286. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_mesh.py +0 -0
  287. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_mesh_event_bus.py +0 -0
  288. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_mesh_remote_auth.py +0 -0
  289. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_mesh_remote_authority.py +0 -0
  290. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_mesh_remote_execution.py +0 -0
  291. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_mesh_remote_outcomes.py +0 -0
  292. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_mesh_remote_replay.py +0 -0
  293. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_mesh_two_node_acceptance.py +0 -0
  294. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_model.py +0 -0
  295. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_node_membership.py +0 -0
  296. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_object_store.py +0 -0
  297. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_observability.py +0 -0
  298. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_operational_policy.py +0 -0
  299. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_operational_runtime_ui.py +0 -0
  300. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_persistence.py +0 -0
  301. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_planner_adaptive.py +0 -0
  302. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_primitives.py +0 -0
  303. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_product_components.py +0 -0
  304. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_protocol.py +0 -0
  305. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_protocol_fabric.py +0 -0
  306. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_protocol_operational.py +0 -0
  307. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_provider_switching.py +0 -0
  308. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_providers.py +0 -0
  309. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_public_api_3.py +0 -0
  310. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_queue.py +0 -0
  311. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_reactive.py +0 -0
  312. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_runtime.py +0 -0
  313. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_runtime_correctness.py +0 -0
  314. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_runtime_fabric.py +0 -0
  315. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_runtime_store_app_lifecycle.py +0 -0
  316. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_runtime_store_lifecycle.py +0 -0
  317. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_runtime_store_provider.py +0 -0
  318. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_runtime_transaction.py +0 -0
  319. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_scheduler.py +0 -0
  320. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_security.py +0 -0
  321. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_seo.py +0 -0
  322. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_sprint27_convergence.py +0 -0
  323. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_sprint28_acceptance.py +0 -0
  324. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_state.py +0 -0
  325. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_store_first_user_journey.py +0 -0
  326. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_store_model_backend.py +0 -0
  327. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_store_only_core_import.py +0 -0
  328. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_theme.py +0 -0
  329. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_theme_presets.py +0 -0
  330. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_tools.py +0 -0
  331. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_ui.py +0 -0
  332. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_ui_magic.py +0 -0
  333. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_ui_magic_acceptance.py +0 -0
  334. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_voodoo_store_events.py +0 -0
  335. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_voodoo_store_execution.py +0 -0
  336. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_voodoo_store_hitl_restart.py +0 -0
  337. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_voodoo_store_queue.py +0 -0
  338. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_voodoo_store_scheduler.py +0 -0
  339. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_voodoo_system_components.py +0 -0
  340. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_websocket.py +0 -0
  341. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_worker_retry_semantics.py +0 -0
  342. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_workers.py +0 -0
  343. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_world_aware_execution.py +0 -0
  344. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_world_model.py +0 -0
  345. {voodoo_framework-2.8.0 → voodoo_framework-2.8.2}/tests/test_world_sqlite.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: voodoo-framework
3
- Version: 2.8.0
3
+ Version: 2.8.2
4
4
  Summary: The programmable runtime for adaptive applications and operational systems — web, APIs, agents, workers, human workflows, distributed systems, and physical systems in one runtime.
5
5
  Author-email: Helder Perez <contact@helderperez.com>
6
6
  Maintainer-email: Helder Perez <contact@helderperez.com>
@@ -105,7 +105,7 @@ from .ui.styles import (
105
105
  from .ui.styles.theme import Theme, ThemeColors, create_theme
106
106
  from .workers import task
107
107
 
108
- __version__ = "2.8.0"
108
+ __version__ = "2.8.2"
109
109
 
110
110
  __all__ = [
111
111
  # Core runtime
@@ -355,6 +355,14 @@ def create_app(app_dir: str = "app") -> Starlette: # noqa: C901
355
355
  Middleware(AuthMiddleware),
356
356
  ]
357
357
 
358
+ # ``public/`` is the filesystem root for static assets, not part of their
359
+ # public URL. Keep the explicit ``/public`` mount above for 2.x compatibility,
360
+ # then add a root mount last so application/runtime routes always win.
361
+ if os.path.isdir(public_dir):
362
+ routes.append(
363
+ Mount("/", app=StaticFiles(directory=public_dir), name="public-root")
364
+ )
365
+
358
366
  app = Starlette(
359
367
  debug=config.debug,
360
368
  routes=routes,
@@ -12,6 +12,7 @@ Voodoo::
12
12
  Button("Save", on_click=save)
13
13
  """
14
14
 
15
+ from voodoo.ui.brand import Brand
15
16
  from voodoo.ui.component import Component, Html, escape, tone_to_color_var
16
17
  from voodoo.ui.events import UIEvent
17
18
  from voodoo.ui.interactive import (
@@ -36,7 +37,6 @@ from voodoo.ui.library import (
36
37
  BackLink,
37
38
  Badge,
38
39
  Box,
39
- Brand,
40
40
  Card,
41
41
  ChatBox,
42
42
  ChatMessage,
@@ -0,0 +1,137 @@
1
+ """Branding primitives for logos and wordmarks.
2
+
3
+ ``Brand`` preserves the existing child-based API while adding a first-class
4
+ image mode that can switch logo assets with the active light/dark theme.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from typing import Any
10
+
11
+ from voodoo.ui.component import Component
12
+
13
+ BRAND_CSS = """
14
+ /* Brand image contract */
15
+ .vd-brand-logo {
16
+ display: block;
17
+ max-width: 100%;
18
+ height: auto;
19
+ border-radius: 0 !important;
20
+ }
21
+ .vd-brand-logo--light { display: block; }
22
+ .vd-brand-logo--dark { display: none; }
23
+ .dark .vd-brand-logo--light { display: none; }
24
+ .dark .vd-brand-logo--dark { display: block; }
25
+ """
26
+
27
+
28
+ class _BrandLogo(Component):
29
+ """Internal logo image with no generic ``Img`` presentation styles."""
30
+
31
+ tag = "img"
32
+ auto_id = False
33
+
34
+ def __init__(
35
+ self,
36
+ *,
37
+ src: str,
38
+ alt: str,
39
+ variant: str | None = None,
40
+ width: str | int | None = None,
41
+ height: str | int | None = None,
42
+ ) -> None:
43
+ classes = "vd-brand-logo"
44
+ if variant:
45
+ classes += f" vd-brand-logo--{variant}"
46
+ super().__init__(class_=classes)
47
+ self.attrs["src"] = src
48
+ self.attrs["alt"] = alt
49
+ if width is not None:
50
+ self.attrs["width"] = width
51
+ if height is not None:
52
+ self.attrs["height"] = height
53
+
54
+
55
+ class Brand(Component):
56
+ """Brand link supporting either child content or theme-aware logo assets.
57
+
58
+ Existing usage remains valid::
59
+
60
+ Brand("Acme", href="/")
61
+ Brand(Img(src="/logo.png", alt="Acme"), href="/")
62
+
63
+ Image mode keeps branding free of generic image presentation styles and
64
+ automatically selects the correct asset for the active theme::
65
+
66
+ Brand(
67
+ light="/logo-black.png",
68
+ dark="/logo-white.png",
69
+ alt="Acme",
70
+ width=160,
71
+ href="/",
72
+ )
73
+
74
+ When only ``light`` or ``dark`` is supplied, that asset is used for both
75
+ themes. Image mode and explicit children are intentionally mutually
76
+ exclusive so the rendered brand stays unambiguous.
77
+ """
78
+
79
+ tag = "a"
80
+ style = "brand"
81
+
82
+ def __init__(
83
+ self,
84
+ *children: Any,
85
+ href: str = "/",
86
+ light: str | None = None,
87
+ dark: str | None = None,
88
+ alt: str = "",
89
+ width: str | int | None = None,
90
+ height: str | int | None = None,
91
+ **kwargs: Any,
92
+ ) -> None:
93
+ image_mode = light is not None or dark is not None
94
+ if image_mode and children:
95
+ raise ValueError(
96
+ "Brand image mode cannot be combined with child content. "
97
+ "Use either Brand(...children) or Brand(light=..., dark=...)."
98
+ )
99
+
100
+ super().__init__(*children, **kwargs)
101
+ self.attrs["href"] = href
102
+
103
+ if not image_mode:
104
+ return
105
+
106
+ light_src = light or dark
107
+ dark_src = dark or light
108
+ assert light_src is not None
109
+ assert dark_src is not None
110
+
111
+ if light_src == dark_src:
112
+ self.children = (
113
+ _BrandLogo(
114
+ src=light_src,
115
+ alt=alt,
116
+ width=width,
117
+ height=height,
118
+ ),
119
+ )
120
+ return
121
+
122
+ self.children = (
123
+ _BrandLogo(
124
+ src=light_src,
125
+ alt=alt,
126
+ variant="light",
127
+ width=width,
128
+ height=height,
129
+ ),
130
+ _BrandLogo(
131
+ src=dark_src,
132
+ alt=alt,
133
+ variant="dark",
134
+ width=width,
135
+ height=height,
136
+ ),
137
+ )
@@ -40,6 +40,7 @@ def render_page(component: Any, seo: Any = None) -> str:
40
40
  """Render a complete HTML document for a Voodoo component tree."""
41
41
  from voodoo.config import config
42
42
  from voodoo.seo import SEO
43
+ from voodoo.ui.brand import BRAND_CSS
43
44
  from voodoo.ui.component import Component
44
45
  from voodoo.ui.styles.theme import default_theme
45
46
 
@@ -162,6 +163,9 @@ def render_page(component: Any, seo: Any = None) -> str:
162
163
  /* Stable primitive component layer */
163
164
  {component_css}
164
165
 
166
+ /* Brand asset switching */
167
+ {BRAND_CSS}
168
+
165
169
  /* Voodoo Design System 3 */
166
170
  {design_system_css}
167
171
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: voodoo-framework
3
- Version: 2.8.0
3
+ Version: 2.8.2
4
4
  Summary: The programmable runtime for adaptive applications and operational systems — web, APIs, agents, workers, human workflows, distributed systems, and physical systems in one runtime.
5
5
  Author-email: Helder Perez <contact@helderperez.com>
6
6
  Maintainer-email: Helder Perez <contact@helderperez.com>
@@ -200,6 +200,7 @@ src/voodoo/telemetry/store.py
200
200
  src/voodoo/tools/__init__.py
201
201
  src/voodoo/tools/registry.py
202
202
  src/voodoo/ui/__init__.py
203
+ src/voodoo/ui/brand.py
203
204
  src/voodoo/ui/component.py
204
205
  src/voodoo/ui/events.py
205
206
  src/voodoo/ui/interactive.py
@@ -238,6 +239,7 @@ tests/test_agent_registry.py
238
239
  tests/test_agent_runtime.py
239
240
  tests/test_app.py
240
241
  tests/test_auth.py
242
+ tests/test_brand.py
241
243
  tests/test_capability_security.py
242
244
  tests/test_checkpoint_resume.py
243
245
  tests/test_chrome.py
@@ -302,6 +304,7 @@ tests/test_protocol_operational.py
302
304
  tests/test_provider_switching.py
303
305
  tests/test_providers.py
304
306
  tests/test_public_api_3.py
307
+ tests/test_public_assets.py
305
308
  tests/test_queue.py
306
309
  tests/test_reactive.py
307
310
  tests/test_runtime.py
@@ -0,0 +1,61 @@
1
+ """Tests for the theme-aware Brand component."""
2
+
3
+ import pytest
4
+
5
+ from voodoo.ui import Brand
6
+ from voodoo.ui.brand import BRAND_CSS
7
+ from voodoo.ui.rendering import render_page
8
+
9
+
10
+ def test_brand_preserves_child_based_api():
11
+ html = Brand("Voodoo", href="/home").render()
12
+
13
+ assert 'href="/home"' in html
14
+ assert ">Voodoo</a>" in html
15
+ assert "vd-brand-logo" not in html
16
+
17
+
18
+ def test_brand_renders_theme_specific_assets_without_generic_img_style():
19
+ html = Brand(
20
+ light="/logo-black.png",
21
+ dark="/logo-white.png",
22
+ alt="Voodoo",
23
+ width=160,
24
+ href="/",
25
+ ).render()
26
+
27
+ assert 'src="/logo-black.png"' in html
28
+ assert 'src="/logo-white.png"' in html
29
+ assert 'alt="Voodoo"' in html
30
+ assert 'width="160"' in html
31
+ assert "vd-brand-logo--light" in html
32
+ assert "vd-brand-logo--dark" in html
33
+ assert "vd-img" not in html
34
+
35
+
36
+ def test_brand_single_asset_is_shared_by_both_themes():
37
+ html = Brand(light="/logo.svg", alt="Acme").render()
38
+
39
+ assert html.count("<img") == 1
40
+ assert 'src="/logo.svg"' in html
41
+ assert "vd-brand-logo--light" not in html
42
+ assert "vd-brand-logo--dark" not in html
43
+
44
+
45
+ def test_brand_rejects_children_in_image_mode():
46
+ with pytest.raises(ValueError, match="cannot be combined"):
47
+ Brand("Voodoo", light="/logo.svg")
48
+
49
+
50
+ def test_brand_css_switches_assets_and_removes_radius():
51
+ assert "border-radius: 0 !important" in BRAND_CSS
52
+ assert ".dark .vd-brand-logo--light { display: none; }" in BRAND_CSS
53
+ assert ".dark .vd-brand-logo--dark { display: block; }" in BRAND_CSS
54
+
55
+
56
+ def test_render_page_includes_brand_css():
57
+ html = render_page(Brand(light="/logo-black.png", dark="/logo-white.png"))
58
+
59
+ assert "/* Brand asset switching */" in html
60
+ assert ".vd-brand-logo--light" in html
61
+ assert ".dark .vd-brand-logo--dark" in html
@@ -0,0 +1,48 @@
1
+ """Acceptance tests for the public asset URL contract."""
2
+
3
+ from starlette.testclient import TestClient
4
+
5
+ from voodoo import App
6
+
7
+
8
+ def test_public_assets_are_served_from_root_without_shadowing_pages(
9
+ tmp_path, monkeypatch
10
+ ):
11
+ monkeypatch.chdir(tmp_path)
12
+
13
+ app_dir = tmp_path / "app"
14
+ app_dir.mkdir()
15
+ (app_dir / "page.py").write_text(
16
+ "from voodoo.ui import Text\n\n"
17
+ "def page(request):\n"
18
+ " return Text('Application page wins')\n"
19
+ )
20
+
21
+ public_dir = tmp_path / "public"
22
+ (public_dir / "assets").mkdir(parents=True)
23
+ (public_dir / "logo.txt").write_text("voodoo-logo")
24
+ (public_dir / "assets" / "icon.txt").write_text("voodoo-icon")
25
+ # A static index must never shadow the application root route.
26
+ (public_dir / "index.html").write_text("STATIC INDEX")
27
+
28
+ with TestClient(App(app_dir=str(app_dir))) as client:
29
+ root = client.get("/")
30
+ logo = client.get("/logo.txt")
31
+ nested = client.get("/assets/icon.txt")
32
+ legacy = client.get("/public/logo.txt")
33
+ missing = client.get("/does-not-exist.txt")
34
+
35
+ assert root.status_code == 200
36
+ assert "Application page wins" in root.text
37
+ assert "STATIC INDEX" not in root.text
38
+
39
+ assert logo.status_code == 200
40
+ assert logo.text == "voodoo-logo"
41
+ assert nested.status_code == 200
42
+ assert nested.text == "voodoo-icon"
43
+
44
+ # Preserve the 2.x URL as a compatibility alias while root URLs become canonical.
45
+ assert legacy.status_code == 200
46
+ assert legacy.text == "voodoo-logo"
47
+
48
+ assert missing.status_code == 404