quantum-framework 0.16.0__tar.gz → 0.17.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 (366) hide show
  1. {quantum_framework-0.16.0/quantum_framework.egg-info → quantum_framework-0.17.0}/PKG-INFO +1 -1
  2. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/pyproject.toml +1 -1
  3. quantum_framework-0.17.0/quantum/cli/check.py +202 -0
  4. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/cli/runner.py +9 -0
  5. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/features/ui_engine/src/parser.py +17 -2
  6. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/parser.py +62 -17
  7. quantum_framework-0.17.0/quantum/core/xml_lines.py +81 -0
  8. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/action_handler.py +7 -2
  9. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/component.py +1 -1
  10. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/database_service.py +5 -0
  11. quantum_framework-0.17.0/quantum/runtime/db_schema.py +100 -0
  12. quantum_framework-0.17.0/quantum/runtime/dev_panel.py +178 -0
  13. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/executor_registry.py +8 -1
  14. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/renderer.py +9 -0
  15. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/ui_page_renderer.py +13 -7
  16. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/ui_view.py +3 -1
  17. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/web_server.py +149 -22
  18. {quantum_framework-0.16.0 → quantum_framework-0.17.0/quantum_framework.egg-info}/PKG-INFO +1 -1
  19. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_framework.egg-info/SOURCES.txt +4 -0
  20. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/LICENSE +0 -0
  21. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/README.md +0 -0
  22. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/__init__.py +0 -0
  23. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/cli/__init__.py +0 -0
  24. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/cli/admin.py +0 -0
  25. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/cli/commands/__init__.py +0 -0
  26. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/cli/commands/build.py +0 -0
  27. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/cli/commands/dev.py +0 -0
  28. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/cli/commands/docs.py +0 -0
  29. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/cli/commands/lint.py +0 -0
  30. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/cli/commands/migrate.py +0 -0
  31. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/cli/commands/new.py +0 -0
  32. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/cli/commands/serve.py +0 -0
  33. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/cli/commands/test.py +0 -0
  34. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/cli/deploy.py +0 -0
  35. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/cli/hot_reload.py +0 -0
  36. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/cli/jobs.py +0 -0
  37. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/cli/mq.py +0 -0
  38. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/cli/pkg.py +0 -0
  39. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/cli/server_process.py +0 -0
  40. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/cli/utils.py +0 -0
  41. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/compiler/__init__.py +0 -0
  42. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/compiler/base_generator.py +0 -0
  43. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/compiler/cli.py +0 -0
  44. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/compiler/expression_transformer.py +0 -0
  45. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/compiler/javascript/__init__.py +0 -0
  46. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/compiler/javascript/generator.py +0 -0
  47. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/compiler/optimizer.py +0 -0
  48. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/compiler/python/__init__.py +0 -0
  49. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/compiler/python/generator.py +0 -0
  50. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/compiler/python/runtime.py +0 -0
  51. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/compiler/transpiler.py +0 -0
  52. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/__init__.py +0 -0
  53. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/ast_nodes.py +0 -0
  54. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/config_env.py +0 -0
  55. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/docs_links.py +0 -0
  56. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/expression_diagnostics.py +0 -0
  57. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/expression_stdlib.py +0 -0
  58. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/expressions.py +0 -0
  59. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/features/agents/src/__init__.py +0 -0
  60. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/features/agents/src/ast_node.py +0 -0
  61. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/features/conditionals/src/__init__.py +0 -0
  62. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/features/conditionals/src/ast_node.py +0 -0
  63. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/features/data_import/src/__init__.py +0 -0
  64. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/features/data_import/src/ast_node.py +0 -0
  65. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/features/data_import/src/runtime.py +0 -0
  66. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/features/dump/src/__init__.py +0 -0
  67. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/features/dump/src/ast_node.py +0 -0
  68. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/features/dump/src/parser.py +0 -0
  69. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/features/dump/src/runtime.py +0 -0
  70. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/features/functions/src/__init__.py +0 -0
  71. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/features/functions/src/ast_node.py +0 -0
  72. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/features/game_engine_2d/src/__init__.py +0 -0
  73. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/features/game_engine_2d/src/ast_nodes.py +0 -0
  74. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/features/game_engine_2d/src/parser.py +0 -0
  75. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/features/invocation/src/__init__.py +0 -0
  76. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/features/invocation/src/ast_node.py +0 -0
  77. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/features/invocation/src/runtime.py +0 -0
  78. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/features/knowledge_base/src/__init__.py +0 -0
  79. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/features/knowledge_base/src/ast_node.py +0 -0
  80. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/features/knowledge_base/src/parser.py +0 -0
  81. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/features/logging/src/__init__.py +0 -0
  82. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/features/logging/src/ast_node.py +0 -0
  83. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/features/logging/src/parser.py +0 -0
  84. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/features/logging/src/runtime.py +0 -0
  85. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/features/loops/src/__init__.py +0 -0
  86. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/features/loops/src/ast_node.py +0 -0
  87. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/features/query/src/__init__.py +0 -0
  88. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/features/query/src/query_validators.py +0 -0
  89. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/features/state_management/src/__init__.py +0 -0
  90. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/features/state_management/src/ast_node.py +0 -0
  91. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/features/terminal_engine/src/__init__.py +0 -0
  92. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/features/terminal_engine/src/ast_nodes.py +0 -0
  93. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/features/terminal_engine/src/parser.py +0 -0
  94. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/features/testing_engine/src/__init__.py +0 -0
  95. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/features/testing_engine/src/ast_nodes.py +0 -0
  96. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/features/testing_engine/src/parser.py +0 -0
  97. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/features/theming/src/__init__.py +0 -0
  98. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/features/theming/src/ast_node.py +0 -0
  99. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/features/theming/src/presets.py +0 -0
  100. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/features/ui_engine/src/__init__.py +0 -0
  101. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/features/ui_engine/src/ast_nodes.py +0 -0
  102. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/features/websocket/src/__init__.py +0 -0
  103. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/features/websocket/src/ast_node.py +0 -0
  104. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/guards.py +0 -0
  105. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/html_compat.py +0 -0
  106. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/parser_registry.py +0 -0
  107. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/parsers/__init__.py +0 -0
  108. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/parsers/ai/__init__.py +0 -0
  109. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/parsers/ai/agent_parser.py +0 -0
  110. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/parsers/ai/knowledge_parser.py +0 -0
  111. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/parsers/ai/llm_parser.py +0 -0
  112. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/parsers/ai/team_parser.py +0 -0
  113. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/parsers/base.py +0 -0
  114. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/parsers/composition/__init__.py +0 -0
  115. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/parsers/composition/import_parser.py +0 -0
  116. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/parsers/composition/slot_parser.py +0 -0
  117. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/parsers/control_flow/__init__.py +0 -0
  118. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/parsers/control_flow/if_parser.py +0 -0
  119. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/parsers/control_flow/loop_parser.py +0 -0
  120. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/parsers/control_flow/set_parser.py +0 -0
  121. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/parsers/data/__init__.py +0 -0
  122. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/parsers/data/data_parser.py +0 -0
  123. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/parsers/data/invoke_parser.py +0 -0
  124. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/parsers/data/query_parser.py +0 -0
  125. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/parsers/data/transaction_parser.py +0 -0
  126. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/parsers/events/__init__.py +0 -0
  127. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/parsers/events/dispatch_event_parser.py +0 -0
  128. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/parsers/forms/__init__.py +0 -0
  129. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/parsers/forms/action_parser.py +0 -0
  130. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/parsers/forms/flash_parser.py +0 -0
  131. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/parsers/forms/redirect_parser.py +0 -0
  132. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/parsers/functions/__init__.py +0 -0
  133. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/parsers/functions/function_parser.py +0 -0
  134. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/parsers/functions/param_parser.py +0 -0
  135. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/parsers/functions/return_parser.py +0 -0
  136. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/parsers/html/__init__.py +0 -0
  137. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/parsers/html/component_call_parser.py +0 -0
  138. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/parsers/html/html_parser.py +0 -0
  139. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/parsers/jobs/__init__.py +0 -0
  140. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/parsers/jobs/job_parser.py +0 -0
  141. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/parsers/jobs/schedule_parser.py +0 -0
  142. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/parsers/jobs/thread_parser.py +0 -0
  143. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/parsers/messaging/__init__.py +0 -0
  144. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/parsers/messaging/message_ack_parser.py +0 -0
  145. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/parsers/messaging/message_nack_parser.py +0 -0
  146. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/parsers/messaging/message_parser.py +0 -0
  147. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/parsers/messaging/queue_parser.py +0 -0
  148. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/parsers/messaging/websocket_parser.py +0 -0
  149. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/parsers/routing/__init__.py +0 -0
  150. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/parsers/routing/route_parser.py +0 -0
  151. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/parsers/scripting/__init__.py +0 -0
  152. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/parsers/scripting/pyclass_parser.py +0 -0
  153. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/parsers/scripting/pydecorator_parser.py +0 -0
  154. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/parsers/scripting/pyimport_parser.py +0 -0
  155. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/parsers/scripting/python_parser.py +0 -0
  156. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/parsers/services/__init__.py +0 -0
  157. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/parsers/services/dump_parser.py +0 -0
  158. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/parsers/services/file_parser.py +0 -0
  159. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/parsers/services/log_parser.py +0 -0
  160. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/parsers/services/mail_parser.py +0 -0
  161. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/core/tiers.py +0 -0
  162. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/packages/__init__.py +0 -0
  163. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/packages/manager.py +0 -0
  164. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/packages/manifest.py +0 -0
  165. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/packages/registry.py +0 -0
  166. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/packages/resolver.py +0 -0
  167. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/plugins/__init__.py +0 -0
  168. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/plugins/hooks.py +0 -0
  169. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/plugins/loader.py +0 -0
  170. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/plugins/manifest.py +0 -0
  171. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/plugins/registry.py +0 -0
  172. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/__init__.py +0 -0
  173. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/adapters/__init__.py +0 -0
  174. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/adapters/memory_adapter.py +0 -0
  175. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/adapters/rabbitmq_adapter.py +0 -0
  176. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/adapters/redis_adapter.py +0 -0
  177. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/adapters/sqlite_adapter.py +0 -0
  178. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/agent_service.py +0 -0
  179. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/ast_cache.py +0 -0
  180. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/auth_service.py +0 -0
  181. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/component_composer.py +0 -0
  182. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/component_resolver.py +0 -0
  183. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/conditions.py +0 -0
  184. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/email_service.py +0 -0
  185. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/error_handler.py +0 -0
  186. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/execution_context.py +0 -0
  187. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/executors/__init__.py +0 -0
  188. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/executors/ai/__init__.py +0 -0
  189. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/executors/ai/agent_executor.py +0 -0
  190. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/executors/ai/knowledge_executor.py +0 -0
  191. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/executors/ai/llm_executor.py +0 -0
  192. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/executors/ai/team_executor.py +0 -0
  193. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/executors/base.py +0 -0
  194. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/executors/control_flow/__init__.py +0 -0
  195. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/executors/control_flow/if_executor.py +0 -0
  196. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/executors/control_flow/loop_executor.py +0 -0
  197. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/executors/control_flow/redirect_executor.py +0 -0
  198. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/executors/control_flow/set_executor.py +0 -0
  199. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/executors/data/__init__.py +0 -0
  200. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/executors/data/data_executor.py +0 -0
  201. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/executors/data/invoke_executor.py +0 -0
  202. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/executors/data/query_executor.py +0 -0
  203. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/executors/data/transaction_executor.py +0 -0
  204. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/executors/jobs/__init__.py +0 -0
  205. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/executors/jobs/job_executor.py +0 -0
  206. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/executors/jobs/schedule_executor.py +0 -0
  207. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/executors/jobs/thread_executor.py +0 -0
  208. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/executors/messaging/__init__.py +0 -0
  209. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/executors/messaging/message_ack_executor.py +0 -0
  210. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/executors/messaging/message_executor.py +0 -0
  211. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/executors/messaging/queue_executor.py +0 -0
  212. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/executors/messaging/websocket_executor.py +0 -0
  213. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/executors/scripting/__init__.py +0 -0
  214. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/executors/scripting/pyclass_executor.py +0 -0
  215. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/executors/scripting/pyimport_executor.py +0 -0
  216. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/executors/scripting/python_executor.py +0 -0
  217. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/executors/services/__init__.py +0 -0
  218. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/executors/services/dump_executor.py +0 -0
  219. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/executors/services/file_executor.py +0 -0
  220. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/executors/services/log_executor.py +0 -0
  221. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/executors/services/mail_executor.py +0 -0
  222. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/expression_cache.py +0 -0
  223. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/file_upload_service.py +0 -0
  224. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/function_registry.py +0 -0
  225. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/game_builder.py +0 -0
  226. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/game_code_generator.py +0 -0
  227. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/game_templates.py +0 -0
  228. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/godot_code_generator.py +0 -0
  229. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/godot_templates.py +0 -0
  230. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/job_executor.py +0 -0
  231. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/knowledge_service.py +0 -0
  232. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/llm_cache.py +0 -0
  233. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/llm_providers.py +0 -0
  234. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/llm_service.py +0 -0
  235. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/local_server.py +0 -0
  236. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/logging_setup.py +0 -0
  237. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/message_broker.py +0 -0
  238. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/message_queue_service.py +0 -0
  239. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/param_validation.py +0 -0
  240. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/pypy_compat.py +0 -0
  241. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/python_bridge.py +0 -0
  242. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/query_validators.py +0 -0
  243. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/service_container.py +0 -0
  244. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/terminal_builder.py +0 -0
  245. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/terminal_code_generator.py +0 -0
  246. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/terminal_templates.py +0 -0
  247. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/testing_builder.py +0 -0
  248. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/testing_code_generator.py +0 -0
  249. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/testing_templates.py +0 -0
  250. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/ui_builder.py +0 -0
  251. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/ui_console.py +0 -0
  252. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/ui_desktop.py +0 -0
  253. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/ui_html_adapter.py +0 -0
  254. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/ui_html_templates.py +0 -0
  255. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/ui_mobile_adapter.py +0 -0
  256. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/ui_mobile_templates.py +0 -0
  257. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/ui_textual_adapter.py +0 -0
  258. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/ui_textual_templates.py +0 -0
  259. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/ui_tokens.py +0 -0
  260. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/ui_validator.py +0 -0
  261. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/validators.py +0 -0
  262. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/websocket_adapter.py +0 -0
  263. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/websocket_service.py +0 -0
  264. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/websocket_transport.py +0 -0
  265. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/runtime/wsgi.py +0 -0
  266. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/services.py +0 -0
  267. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum/utils/__init__.py +0 -0
  268. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_admin/__init__.py +0 -0
  269. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_admin/assets/quantum-admin-connectors.js +0 -0
  270. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_admin/assets/quantum-admin.css +0 -0
  271. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_admin/assets/quantum-source-highlight.js +0 -0
  272. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_admin/backend/__init__.py +0 -0
  273. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_admin/backend/audit_service.py +0 -0
  274. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_admin/backend/auth_service.py +0 -0
  275. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_admin/backend/component_discovery.py +0 -0
  276. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_admin/backend/config_generator.py +0 -0
  277. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_admin/backend/connector_service.py +0 -0
  278. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_admin/backend/crud.py +0 -0
  279. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_admin/backend/database.py +0 -0
  280. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_admin/backend/db_setup_service.py +0 -0
  281. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_admin/backend/deploy_service.py +0 -0
  282. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_admin/backend/docker_service.py +0 -0
  283. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_admin/backend/environment_service.py +0 -0
  284. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_admin/backend/git_service.py +0 -0
  285. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_admin/backend/health_service.py +0 -0
  286. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_admin/backend/job_service.py +0 -0
  287. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_admin/backend/log_service.py +0 -0
  288. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_admin/backend/main.py +0 -0
  289. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_admin/backend/models.py +0 -0
  290. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_admin/backend/pipeline_service.py +0 -0
  291. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_admin/backend/resource_manager.py +0 -0
  292. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_admin/backend/schemas.py +0 -0
  293. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_admin/backend/secret_manager.py +0 -0
  294. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_admin/backend/settings_service.py +0 -0
  295. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_admin/backend/template_service.py +0 -0
  296. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_admin/backend/test_execution_service.py +0 -0
  297. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_admin/backend/test_generator.py +0 -0
  298. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_admin/backend/webhook_service.py +0 -0
  299. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_admin/backend/websocket_manager.py +0 -0
  300. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_admin/components/admin/_layout/AdminShell.q +0 -0
  301. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_admin/components/admin/agents.q +0 -0
  302. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_admin/components/admin/app/[name].q +0 -0
  303. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_admin/components/admin/applications.q +0 -0
  304. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_admin/components/admin/component/[...path].q +0 -0
  305. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_admin/components/admin/components.q +0 -0
  306. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_admin/components/admin/connectors.q +0 -0
  307. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_admin/components/admin/dashboard.q +0 -0
  308. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_admin/components/admin/database.q +0 -0
  309. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_admin/components/admin/features.q +0 -0
  310. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_admin/components/admin/index.q +0 -0
  311. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_admin/components/admin/jobs.q +0 -0
  312. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_admin/components/admin/login.q +0 -0
  313. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_admin/components/admin/logout.q +0 -0
  314. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_admin/components/admin/settings.q +0 -0
  315. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_admin/components/admin/source.q +0 -0
  316. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_admin/components/admin/tests.q +0 -0
  317. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_admin/run.py +0 -0
  318. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_admin/services/__init__.py +0 -0
  319. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_admin/services/_base.py +0 -0
  320. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_admin/services/_component_test_generator.py +0 -0
  321. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_admin/services/_yaml_editor.py +0 -0
  322. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_admin/services/apps.py +0 -0
  323. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_admin/services/auth.py +0 -0
  324. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_admin/services/components.py +0 -0
  325. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_admin/services/connectors.py +0 -0
  326. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_admin/services/projects.py +0 -0
  327. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_admin/services/repository.py +0 -0
  328. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_admin/services/settings.py +0 -0
  329. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_admin/services/yaml_import.py +0 -0
  330. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_framework.egg-info/dependency_links.txt +0 -0
  331. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_framework.egg-info/entry_points.txt +0 -0
  332. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_framework.egg-info/requires.txt +0 -0
  333. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/quantum_framework.egg-info/top_level.txt +0 -0
  334. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/setup.cfg +0 -0
  335. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/tests/test_agent.py +0 -0
  336. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/tests/test_animations.py +0 -0
  337. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/tests/test_ast_cache.py +0 -0
  338. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/tests/test_cli_commands.py +0 -0
  339. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/tests/test_component_library.py +0 -0
  340. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/tests/test_expression_cache.py +0 -0
  341. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/tests/test_form_validation.py +0 -0
  342. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/tests/test_game_codegen.py +0 -0
  343. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/tests/test_game_e2e.py +0 -0
  344. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/tests/test_game_engine.py +0 -0
  345. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/tests/test_game_parser.py +0 -0
  346. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/tests/test_godot_codegen.py +0 -0
  347. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/tests/test_job_executor.py +0 -0
  348. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/tests/test_llm_providers.py +0 -0
  349. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/tests/test_message_broker.py +0 -0
  350. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/tests/test_message_queue.py +0 -0
  351. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/tests/test_mobile_target.py +0 -0
  352. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/tests/test_multi_agent.py +0 -0
  353. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/tests/test_packages.py +0 -0
  354. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/tests/test_plugins.py +0 -0
  355. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/tests/test_pypy_compat.py +0 -0
  356. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/tests/test_python_scripting.py +0 -0
  357. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/tests/test_terminal_codegen.py +0 -0
  358. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/tests/test_terminal_parser.py +0 -0
  359. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/tests/test_testing_codegen.py +0 -0
  360. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/tests/test_testing_parser.py +0 -0
  361. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/tests/test_theming.py +0 -0
  362. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/tests/test_ui_html_adapter.py +0 -0
  363. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/tests/test_ui_parity.py +0 -0
  364. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/tests/test_ui_parser.py +0 -0
  365. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/tests/test_ui_textual_adapter.py +0 -0
  366. {quantum_framework-0.16.0 → quantum_framework-0.17.0}/tests/test_websocket.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: quantum-framework
3
- Version: 0.16.0
3
+ Version: 0.17.0
4
4
  Summary: Full-stack declarative framework for building web, desktop, and mobile applications
5
5
  Author-email: Daniel Gregorio <danielgregorio2611@gmail.com>
6
6
  License: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "quantum-framework"
7
- version = "0.16.0"
7
+ version = "0.17.0"
8
8
  description = "Full-stack declarative framework for building web, desktop, and mobile applications"
9
9
  readme = "README.md"
10
10
  license = {text = "MIT"}
@@ -0,0 +1,202 @@
1
+ """`quantum check`: every page parses, every q:query compiles against the database,
2
+ and every `{query.field}` a page reads is a column the query returns (M8, DEV-3).
3
+
4
+ A typo in SQL or in a field name used to surface only when someone opened the
5
+ page — `no such column` as a 500, or, for a field, an empty cell. This reads
6
+ the project the way the server would and reports each problem with its file
7
+ and line, without running anything: a query is compiled by the database
8
+ (EXPLAIN) and a SELECT's columns come from running it with LIMIT 0.
9
+ """
10
+
11
+ import re
12
+ from dataclasses import dataclass
13
+ from pathlib import Path
14
+ from typing import Dict, Iterator, List, Optional
15
+
16
+ # Fields of `<name>_result` and of a query row that are not columns.
17
+ _META = {'recordCount', 'columnList', 'executionTime', 'success', 'error', 'sql', 'page',
18
+ 'totalPages', 'hasMore', 'cached', 'affectedRows', 'lastInsertId', 'data', 'length'}
19
+ _EXPR = re.compile(r'\{([^{}]*)\}')
20
+
21
+
22
+ @dataclass
23
+ class Problem:
24
+ file: str
25
+ line: Optional[int]
26
+ message: str
27
+
28
+ def __str__(self) -> str:
29
+ return f'{self.file}:{self.line or "?"}: {self.message}'
30
+
31
+
32
+ def _config(config_path: Path) -> dict:
33
+ import yaml
34
+ from quantum.core.config_env import expand_env
35
+ if not config_path.exists():
36
+ return {}
37
+ return expand_env(yaml.safe_load(config_path.read_text(encoding='utf-8')) or {})
38
+
39
+
40
+ def _children(node) -> Iterator:
41
+ """The nodes inside a node, whatever the field is called."""
42
+ for campo in ('statements', 'body', 'if_body', 'else_body', 'children'):
43
+ for filho in getattr(node, campo, None) or []:
44
+ if hasattr(filho, '__dict__'):
45
+ yield filho
46
+ for bloco in getattr(node, 'elseif_blocks', None) or []:
47
+ corpo = bloco.get('body') if isinstance(bloco, dict) else getattr(bloco, 'body', None)
48
+ for filho in corpo or []:
49
+ yield filho
50
+
51
+
52
+ def _texts(node) -> List[str]:
53
+ """The strings of a node that may hold {expressions}."""
54
+ textos = []
55
+ for campo, valor in vars(node).items():
56
+ if campo.startswith('_') or campo in ('sql',):
57
+ continue
58
+ if isinstance(valor, str) and '{' in valor:
59
+ textos.append(valor)
60
+ elif isinstance(valor, dict):
61
+ textos += [v for v in valor.values() if isinstance(v, str) and '{' in v]
62
+ return textos
63
+
64
+
65
+ class ProjectChecker:
66
+ def __init__(self, project: Path, config_path: Path):
67
+ self.project = project
68
+ self.config = _config(config_path)
69
+ self.datasources = self.config.get('datasources') or {}
70
+ self._conexoes: Dict[str, object] = {}
71
+ self.problems: List[Problem] = []
72
+ self.notes: List[str] = []
73
+ self.queries_checked = 0
74
+ self.files = 0
75
+
76
+ # -- the database ---------------------------------------------------------
77
+
78
+ def _connection(self, nome: str):
79
+ from quantum.runtime.db_schema import SchemaError, connect_readonly
80
+ if nome not in self._conexoes:
81
+ try:
82
+ self._conexoes[nome] = connect_readonly(self.datasources[nome], self.project)
83
+ except SchemaError as exc:
84
+ self._conexoes[nome] = None
85
+ self.notes.append(f'datasource {nome!r} not checked: {exc}')
86
+ return self._conexoes[nome]
87
+
88
+ # -- a file ---------------------------------------------------------------
89
+
90
+ def check_file(self, arquivo: Path) -> None:
91
+ from quantum.core.parser import QuantumParser
92
+ rel = arquivo.relative_to(self.project).as_posix() if arquivo.is_relative_to(self.project) else str(arquivo)
93
+ self.files += 1
94
+ try:
95
+ ast = QuantumParser(use_cache=False).parse_file(str(arquivo))
96
+ except Exception as exc: # a parse error is a problem like any other
97
+ primeira = str(exc).split('\n')[0]
98
+ self.problems.append(Problem(rel, getattr(exc, 'line', None), primeira))
99
+ return
100
+ colunas: Dict[str, List[str]] = {}
101
+ self._queries(ast, rel, colunas)
102
+ self._fields(ast, rel, colunas, {nome: nome for nome in colunas}, None)
103
+
104
+ def _queries(self, node, rel: str, colunas: Dict[str, List[str]]) -> None:
105
+ from quantum.core.ast_nodes import QueryNode
106
+ from quantum.runtime.db_schema import check_sql
107
+ for filho in _children(node):
108
+ if isinstance(filho, QueryNode):
109
+ ds = filho.datasource
110
+ if not ds or ds.startswith('knowledge:') or getattr(filho, 'source', None):
111
+ pass # RAG or query of queries: not SQL on a database
112
+ elif ds not in self.datasources:
113
+ self.problems.append(Problem(rel, getattr(filho, 'source_line', None),
114
+ f'<q:query name="{filho.name}">: datasource {ds!r} is not '
115
+ f'declared in quantum.config.yaml'))
116
+ else:
117
+ conexao = self._connection(ds)
118
+ if conexao is not None:
119
+ self.queries_checked += 1
120
+ erro, cols = check_sql(conexao, filho.sql or '')
121
+ if erro:
122
+ self.problems.append(Problem(rel, getattr(filho, 'source_line', None),
123
+ f'<q:query name="{filho.name}">: {erro}'))
124
+ elif cols is not None:
125
+ colunas[filho.name] = cols
126
+ self._queries(filho, rel, colunas)
127
+
128
+ def _fields(self, node, rel: str, colunas: Dict[str, List[str]], ligados: Dict[str, str],
129
+ linha: Optional[int]) -> None:
130
+ """Each `{var.field}` where var is a query, or a row of one, names a column it returns."""
131
+ from quantum.core.features.loops.src.ast_node import LoopNode
132
+ from quantum.core.features.ui_engine.src.ast_nodes import UIColumnNode, UIListNode, UITableNode
133
+ linha = getattr(node, 'source_line', None) or linha
134
+ for texto in _texts(node):
135
+ for expressao in _EXPR.findall(texto):
136
+ for var, campo in re.findall(r'(?<![\w.])(\w+)\.(\w+)', expressao):
137
+ self._field(rel, linha, colunas, ligados, var, campo)
138
+ if isinstance(node, UIColumnNode) and node.key and '$tabela' in ligados:
139
+ self._field(rel, linha, colunas, ligados, '$tabela', node.key, f'<ui:column key="{node.key}">')
140
+
141
+ for filho in _children(node):
142
+ dentro = dict(ligados)
143
+ origem = None
144
+ if isinstance(filho, LoopNode):
145
+ origem = filho.query_name if filho.loop_type == 'query' else _single_name(filho.items)
146
+ if origem in colunas:
147
+ dentro[filho.var_name] = origem
148
+ elif isinstance(filho, (UITableNode, UIListNode)):
149
+ origem = _single_name(filho.source)
150
+ if origem in colunas:
151
+ dentro[filho.as_var or ('row' if isinstance(filho, UITableNode) else 'item')] = origem
152
+ if isinstance(filho, UITableNode):
153
+ dentro['$tabela'] = origem
154
+ self._fields(filho, rel, colunas, dentro, linha)
155
+
156
+ def _field(self, rel, linha, colunas, ligados, var, campo, como=None) -> None:
157
+ consulta = ligados.get(var)
158
+ if consulta is None or campo in _META:
159
+ return
160
+ cols = colunas.get(consulta, [])
161
+ if campo not in cols:
162
+ quem = como or f'{{{var}.{campo}}}'
163
+ self.problems.append(Problem(
164
+ rel, linha, f'{quem}: query "{consulta}" returns no column "{campo}" '
165
+ f'(columns: {", ".join(cols) or "none"})'))
166
+
167
+ # -- the project ----------------------------------------------------------
168
+
169
+ def run(self) -> List[Problem]:
170
+ pasta = self.project / (self.config.get('paths', {}) or {}).get('components', 'components')
171
+ if not pasta.exists():
172
+ self.notes.append(f'no components folder at {pasta}')
173
+ return self.problems
174
+ for arquivo in sorted(pasta.rglob('*.q')):
175
+ self.check_file(arquivo)
176
+ for conexao in self._conexoes.values():
177
+ if conexao is not None:
178
+ conexao.close()
179
+ return self.problems
180
+
181
+
182
+ def _single_name(expr: Optional[str]) -> Optional[str]:
183
+ """`{tarefas}` -> 'tarefas'; anything more complex -> None."""
184
+ m = re.fullmatch(r'\s*\{\s*(\w+)\s*\}\s*', expr or '')
185
+ return m.group(1) if m else None
186
+
187
+
188
+ def run_check(config_path: str = 'quantum.config.yaml') -> int:
189
+ """`quantum check`: print each problem as file:line: message; exit 1 if there is any."""
190
+ caminho = Path(config_path).resolve()
191
+ checker = ProjectChecker(caminho.parent, caminho)
192
+ problemas = checker.run()
193
+ for nota in checker.notes:
194
+ print(f'[NOTE] {nota}')
195
+ for problema in problemas:
196
+ print(problema)
197
+ resumo = (f'{checker.files} file(s), {checker.queries_checked} query(ies) checked against the database')
198
+ if problemas:
199
+ print(f'\n{len(problemas)} problem(s) — {resumo}.')
200
+ return 1
201
+ print(f'OK — {resumo}.')
202
+ return 0
@@ -287,6 +287,7 @@ Examples:
287
287
  quantum admin # Start the Quantum Admin
288
288
  quantum console # The application's pages in the terminal
289
289
  quantum desktop # The application's pages in a desktop window
290
+ quantum check # Pages parse, SQL compiles, query fields exist
290
291
  quantum run game.q --engine godot # Build Godot 4 project
291
292
  quantum run backup-job.q # Execute job
292
293
  quantum deploy ./my-app # Deploy application
@@ -342,6 +343,10 @@ Examples:
342
343
  console_parser.add_argument('path', nargs='?', default='/', help='Page to open (default: /)')
343
344
  console_parser.add_argument('--config', default='quantum.config.yaml', help='Config file')
344
345
 
346
+ # Check: pages parse, queries compile, fields exist (M8, DEV-3)
347
+ check_parser = subparsers.add_parser('check', help='Check pages, SQL and query fields against the database')
348
+ check_parser.add_argument('--config', default='quantum.config.yaml', help='Config file')
349
+
345
350
  # Desktop: the application's pages in a native window (UI-4)
346
351
  desktop_parser = subparsers.add_parser('desktop', help="Open the application's pages in a desktop window")
347
352
  desktop_parser.add_argument('path', nargs='?', default='/', help='Page to open (default: /)')
@@ -419,6 +424,10 @@ Examples:
419
424
  from quantum.runtime.ui_console import run_console
420
425
  sys.exit(run_console(args.config, args.path))
421
426
 
427
+ elif args.command == 'check':
428
+ from quantum.cli.check import run_check
429
+ sys.exit(run_check(args.config))
430
+
422
431
  elif args.command == 'desktop':
423
432
  from quantum.runtime.ui_desktop import run_desktop
424
433
  sys.exit(run_desktop(args.config, args.path, width=args.width, height=args.height))
@@ -137,9 +137,24 @@ class UIParser:
137
137
  import difflib
138
138
  parecidas = difflib.get_close_matches(local_name, self.UI_TAG_MAP, n=1)
139
139
  dica = f"; did you mean <ui:{parecidas[0]}>?" if parecidas else ""
140
- raise UIParseError(f"Unknown UI tag: <ui:{local_name}>{dica}")
140
+ erro = UIParseError(f"Unknown UI tag: <ui:{local_name}>{dica}")
141
+ erro.line = getattr(element, 'sourceline', None)
142
+ raise erro
141
143
  method = getattr(self, method_name)
142
- return method(element)
144
+ try:
145
+ node = method(element)
146
+ except UIParseError as exc:
147
+ if getattr(exc, 'line', None) is None:
148
+ exc.line = getattr(element, 'sourceline', None)
149
+ raise
150
+ # DEV-2: a ui:* element knows its line and file, like a q: statement.
151
+ if getattr(element, 'sourceline', None) and node is not None:
152
+ try:
153
+ node.source_line = element.sourceline
154
+ node.source_file = getattr(self.parent, '_source_path', None)
155
+ except AttributeError:
156
+ pass
157
+ return node
143
158
 
144
159
  # ------------------------------------------------------------------
145
160
  # Helpers
@@ -11,6 +11,7 @@ from typing import Union, Optional, List
11
11
  # Fix imports
12
12
 
13
13
  from quantum.core.html_compat import normalise_html
14
+ from quantum.core.xml_lines import fromstring_with_lines, line_of
14
15
  from quantum.core.ast_nodes import (
15
16
  QuantumNode, ComponentNode, ApplicationNode, JobNode,
16
17
  QuantumParam, QuantumReturn, QuantumRoute,
@@ -222,6 +223,23 @@ def _explain_xml_error(error, source: str) -> str:
222
223
  return message
223
224
 
224
225
 
226
+ def _at(erro: 'QuantumParseError', onde) -> 'QuantumParseError':
227
+ """The error belongs to this node's (or element's) line."""
228
+ erro.line = line_of(onde)
229
+ return erro
230
+
231
+
232
+ def _with_line(erro: 'QuantumParseError', source: str, line: Optional[int] = None) -> 'QuantumParseError':
233
+ """DEV-2: a parse error says where it is — `at line N: <the line>`."""
234
+ line = line or getattr(erro, 'line', None)
235
+ erro.line = line
236
+ if line and ' at line ' not in str(erro):
237
+ linhas = source.splitlines()
238
+ trecho = linhas[line - 1].strip() if 0 < line <= len(linhas) else ''
239
+ erro.args = (f"{erro}\n at line {line}: {trecho}" if trecho else f"{erro} (line {line})",)
240
+ return erro
241
+
242
+
225
243
  class QuantumParser:
226
244
  """Main parser for .q files"""
227
245
 
@@ -370,17 +388,19 @@ class QuantumParser:
370
388
  # parse for exactly those two reasons and returned HTTP 400.
371
389
  content = normalise_html(source)
372
390
  content = self._inject_namespace(content)
373
- root = ET.fromstring(content)
391
+ root = fromstring_with_lines(content)
374
392
  self._nest_else_siblings(root)
375
393
  return self._parse_root_element(root, Path("<string>"))
376
394
  except ET.ParseError as e:
377
- raise QuantumParseError(_explain_xml_error(e, source))
378
- except QuantumParseError:
379
- raise
395
+ erro = QuantumParseError(_explain_xml_error(e, source))
396
+ erro.line = getattr(e, 'position', (None, None))[0]
397
+ raise erro
398
+ except QuantumParseError as e:
399
+ raise _with_line(e, source)
380
400
  except ParserError as e:
381
401
  # A tag parser's own error is a parse error with a message meant
382
402
  # for the author, not an "Unexpected error".
383
- raise QuantumParseError(str(e)) from e
403
+ raise _with_line(QuantumParseError(str(e)), source, getattr(e, 'line', None)) from e
384
404
  except Exception as e:
385
405
  raise QuantumParseError(f"Unexpected error: {e}")
386
406
 
@@ -412,7 +432,9 @@ class QuantumParser:
412
432
  self._source_path = str(path.resolve())
413
433
  source = Path(file_path).read_text(encoding="utf-8")
414
434
  return self.parse(source)
415
- except QuantumParseError:
435
+ except QuantumParseError as e:
436
+ if getattr(e, 'file', None) is None:
437
+ e.file = str(path.resolve()) # DEV-2
416
438
  raise
417
439
  except ParserError as e:
418
440
  # A tag parser's own error is a parse error with a message meant
@@ -498,7 +520,7 @@ class QuantumParser:
498
520
  conhecidas |= {'return', 'else', 'elseif'}
499
521
  parecidas = difflib.get_close_matches(name, sorted(conhecidas), n=3, cutoff=0.6)
500
522
  dica = (" Did you mean " + " or ".join(f"<q:{p}>" for p in parecidas) + "?") if parecidas else ""
501
- return f"<q:{name}> is not a Quantum tag.{dica}"
523
+ return f"<q:{name}> is not a Quantum tag (PARSE-1).{dica}"
502
524
 
503
525
  @staticmethod
504
526
  def _is_quantum_tag(element: ET.Element) -> bool:
@@ -683,12 +705,12 @@ class QuantumParser:
683
705
  lidos = names_read(re.sub(r'\{([^{}]*)\}', r'\1', condicao)) & definidos
684
706
  if lidos:
685
707
  nome = sorted(lidos)[0]
686
- raise QuantumParseError(
708
+ raise _at(QuantumParseError(
687
709
  f'<q:if condition="{condicao}"> in <q:component name="{component.name}"> '
688
- f'redirects, so it also runs before the page\'s q:action — where the page '
710
+ f'redirects (AUTH-6), so it also runs before the page\'s q:action — where the page '
689
711
  f'has not run and {{{nome}}} does not exist, and the guard would let the '
690
712
  f'action through. Read the scope directly (e.g. session.x), or protect the '
691
- f'page with require_auth / require_role. See {HOW_A_PAGE_RUNS}')
713
+ f'page with require_auth / require_role. See {HOW_A_PAGE_RUNS}'), guarda)
692
714
 
693
715
  # Nodes the HTML renderer draws. Anything else inside markup is a statement,
694
716
  # and statements run in the execution pass, before the render pass sees
@@ -762,21 +784,21 @@ class QuantumParser:
762
784
  for node in nodes:
763
785
  if not isinstance(node, self._RENDERED) and not is_ui_node(node):
764
786
  if onde and onde[0] == 'markup':
765
- raise QuantumParseError(
787
+ raise _at(QuantumParseError(
766
788
  f'{tag(node)} inside {onde[1]} in <q:component name="{component.name}"> '
767
- f'never runs: statements run before the page is rendered, and markup '
789
+ f'never runs (PARSE-2): statements run before the page is rendered, and markup '
768
790
  f'is only rendered. Move it above the markup (or into a q:action). '
769
- f'See {HOW_A_PAGE_RUNS}')
791
+ f'See {HOW_A_PAGE_RUNS}'), node)
770
792
  nome = getattr(node, 'name', None)
771
793
  # A running total read AFTER the loop is fine; a value the
772
794
  # loop's own rows read is not.
773
795
  if onde and isinstance(nome, str) and usado(nome, onde[1]):
774
- raise QuantumParseError(
796
+ raise _at(QuantumParseError(
775
797
  f'{tag(node)} inside a q:loop whose rows use {{{nome}}} in '
776
798
  f'<q:component name="{component.name}">: the loop runs for every item '
777
- f'before any row is rendered, so every row would show the last value. '
799
+ f'before any row is rendered, so every row would show the last value (PARSE-2). '
778
800
  f'Compute it in the expression instead, e.g. {{item.price * item.qty}}. '
779
- f'See {HOW_A_PAGE_RUNS}')
801
+ f'See {HOW_A_PAGE_RUNS}'), node)
780
802
  continue
781
803
  if isinstance(node, HTMLNode):
782
804
  andar(filhos(node), onde if onde and onde[0] == 'markup' else ('markup', f'<{node.tag}>'))
@@ -844,6 +866,27 @@ class QuantumParser:
844
866
  if_node.add_else_statement(stmt)
845
867
 
846
868
  def _parse_statement(self, element: ET.Element) -> Optional[QuantumNode]:
869
+ """Parse one statement, and remember where it is in the file (DEV-2).
870
+
871
+ The node gets `source_line`, which runtime errors report; a parse
872
+ error from this element — or from inside it, if nothing deeper
873
+ claimed it — gets `line`.
874
+ """
875
+ try:
876
+ node = self._parse_statement_node(element)
877
+ except (QuantumParseError, ParserError) as exc:
878
+ if getattr(exc, 'line', None) is None:
879
+ exc.line = getattr(element, 'sourceline', None)
880
+ raise
881
+ if node is not None and getattr(element, 'sourceline', None):
882
+ try:
883
+ node.source_line = element.sourceline
884
+ node.source_file = self._source_path
885
+ except AttributeError:
886
+ pass # a node with __slots__
887
+ return node
888
+
889
+ def _parse_statement_node(self, element: ET.Element) -> Optional[QuantumNode]:
847
890
  """Parse individual statement (return, set, dispatchEvent, etc)"""
848
891
  element_type = self._get_element_name(element)
849
892
 
@@ -857,7 +900,9 @@ class QuantumParser:
857
900
  try:
858
901
  return UIParser(self, page_mode=True).parse_ui_element(element_type, element)
859
902
  except UIParseError as exc:
860
- raise QuantumParseError(str(exc)) from exc
903
+ erro = QuantumParseError(str(exc))
904
+ erro.line = getattr(exc, 'line', None) # the inner ui:* element's line
905
+ raise erro from exc
861
906
 
862
907
  # PARSE-1: <q:html>, <q:div> — an HTML element name in the q:
863
908
  # namespace. The registry answered for it with the HTML parser, so
@@ -0,0 +1,81 @@
1
+ """XML into an ElementTree whose elements know their line (M2, DEV-2).
2
+
3
+ `xml.etree` does not keep source positions, so an error found after parsing —
4
+ a statement inside markup, an unknown attribute, a failing expression — could
5
+ name the tag but not where it is. This builds the same tree with expat (the
6
+ parser ElementTree itself runs on) and sets `element.sourceline` on each
7
+ element.
8
+ """
9
+
10
+ from xml.etree import ElementTree as ET
11
+ from xml.parsers import expat
12
+
13
+
14
+ class _Element(ET.Element):
15
+ """An Element that can carry `sourceline` (the C Element takes no new attributes)."""
16
+ sourceline = None
17
+
18
+
19
+ def fromstring_with_lines(text: str) -> ET.Element:
20
+ """Like ET.fromstring(text); every element gets `sourceline` (1-based)."""
21
+ builder = ET.TreeBuilder(element_factory=_Element)
22
+ parser = expat.ParserCreate(None, '}')
23
+ parser.buffer_text = True
24
+ parser.ordered_attributes = True
25
+
26
+ def nome(bruto: str) -> str:
27
+ # expat with a separator reports "uri}local"; ElementTree spells it "{uri}local".
28
+ return '{' + bruto if '}' in bruto else bruto
29
+
30
+ def inicio(tag, atributos):
31
+ pares = dict(zip(atributos[0::2], atributos[1::2]))
32
+ elemento = builder.start(nome(tag), {nome(k): v for k, v in pares.items()})
33
+ elemento.sourceline = parser.CurrentLineNumber
34
+
35
+ parser.StartElementHandler = inicio
36
+ parser.EndElementHandler = lambda tag: builder.end(nome(tag))
37
+ parser.CharacterDataHandler = builder.data
38
+ try:
39
+ parser.Parse(text, True)
40
+ except expat.ExpatError as exc:
41
+ erro = ET.ParseError(str(exc))
42
+ erro.code = exc.code
43
+ erro.position = (exc.lineno, exc.offset)
44
+ raise erro from None
45
+ return builder.close()
46
+
47
+
48
+ def line_of(item) -> int:
49
+ """The source line of an element or an AST node, or None."""
50
+ return getattr(item, 'sourceline', None) or getattr(item, 'source_line', None)
51
+
52
+
53
+ def tag_error(exc: BaseException, node) -> None:
54
+ """DEV-2: the innermost node an error passes through names its file and line.
55
+
56
+ Innermost across wrapping too: an error in a called component is re-raised
57
+ as a new exception by the page; the line inside the component, already in
58
+ the chain, wins over the line of the call."""
59
+ if error_location(exc)[1] is not None:
60
+ return
61
+ linha = getattr(node, 'source_line', None)
62
+ if not linha:
63
+ return
64
+ try:
65
+ exc.quantum_line = linha
66
+ exc.quantum_file = getattr(node, 'source_file', None)
67
+ except (AttributeError, TypeError):
68
+ pass # an exception type with __slots__
69
+
70
+
71
+ def error_location(exc: BaseException):
72
+ """(file, line) of an error or of any error it wraps; (None, None) if unknown."""
73
+ visto = set()
74
+ while exc is not None and id(exc) not in visto:
75
+ visto.add(id(exc))
76
+ if getattr(exc, 'quantum_line', None) is not None:
77
+ return getattr(exc, 'quantum_file', None), exc.quantum_line
78
+ if getattr(exc, 'line', None) is not None and type(exc).__name__ == 'QuantumParseError':
79
+ return getattr(exc, 'file', None), exc.line
80
+ exc = exc.__cause__ or exc.__context__
81
+ return None, None
@@ -107,7 +107,12 @@ class ActionHandler:
107
107
  context.set_variable(key, value)
108
108
 
109
109
  # 4. Execute action body
110
- redirect_info = self._execute_action_body(action, context)
110
+ try:
111
+ redirect_info = self._execute_action_body(action, context)
112
+ finally:
113
+ # M12: the /_dev panel shows the action's variables (no-op off debug).
114
+ from quantum.runtime.dev_panel import note_scopes
115
+ note_scopes(context, 'action')
111
116
 
112
117
  # 5. Sync session mutations back to Flask (mirrors web_server.py's
113
118
  # render path, which does the same after execute_component()).
@@ -144,7 +149,7 @@ class ActionHandler:
144
149
  mensagem = str(e)
145
150
  if 'is not defined' in mensagem:
146
151
  from quantum.core.docs_links import HOW_A_PAGE_RUNS
147
- mensagem += (". A q:action does not run the page's statements: "
152
+ mensagem += (". A q:action does not run the page's statements (ACT-9): "
148
153
  f"query or compute what it needs inside the action. See {HOW_A_PAGE_RUNS}")
149
154
  logger.exception(
150
155
  "q:action %r failed: %s", getattr(action, 'name', '?'), mensagem
@@ -284,7 +284,7 @@ class ComponentRuntime:
284
284
  return None
285
285
 
286
286
  except Exception as e:
287
- raise ComponentExecutionError(f"Execution error: {e}")
287
+ raise ComponentExecutionError(f"Execution error: {e}") from e
288
288
 
289
289
  def _enter(self, component: ComponentNode, params: Dict[str, Any]) -> None:
290
290
  """Make `component` current: its functions, and the scopes passed in params."""
@@ -7,11 +7,13 @@ import time
7
7
  from pathlib import Path
8
8
  from typing import Dict, Any, List, Optional
9
9
  from dataclasses import dataclass, asdict
10
+ from quantum.runtime.dev_panel import note_query
10
11
 
11
12
  logger = logging.getLogger('quantum.database')
12
13
 
13
14
 
14
15
  @dataclass
16
+
15
17
  class QueryResult:
16
18
  """Container for query results and metadata"""
17
19
  data: List[Dict[str, Any]]
@@ -346,6 +348,8 @@ class DatabaseService:
346
348
 
347
349
  # Calculate execution time
348
350
  execution_time = (time.time() - start_time) * 1000 # Convert to ms
351
+ # M12: the /_dev panel shows each query of the request (no-op off debug).
352
+ note_query(datasource_name, sql, params, execution_time, record_count)
349
353
 
350
354
  return QueryResult(
351
355
  data=data,
@@ -369,6 +373,7 @@ class DatabaseService:
369
373
  # a failed rollback on a broken connection must not
370
374
  # replace it. Deliberately silent.
371
375
  pass
376
+ note_query(datasource_name, sql, params, (time.time() - start_time) * 1000, None, error=str(e))
372
377
  raise QueryExecutionError(f"Query execution failed: {e}")
373
378
 
374
379
  def _prepare_query(self, sql: str, params: Dict[str, Any], db_type: str) -> tuple: