quantum-framework 0.18.0__py3-none-any.whl

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 (333) hide show
  1. quantum/__init__.py +1 -0
  2. quantum/cli/__init__.py +2 -0
  3. quantum/cli/admin.py +131 -0
  4. quantum/cli/check.py +223 -0
  5. quantum/cli/commands/__init__.py +15 -0
  6. quantum/cli/commands/build.py +414 -0
  7. quantum/cli/commands/dev.py +185 -0
  8. quantum/cli/commands/docs.py +329 -0
  9. quantum/cli/commands/lint.py +523 -0
  10. quantum/cli/commands/migrate.py +548 -0
  11. quantum/cli/commands/new.py +622 -0
  12. quantum/cli/commands/serve.py +190 -0
  13. quantum/cli/commands/test.py +193 -0
  14. quantum/cli/deploy.py +810 -0
  15. quantum/cli/hot_reload.py +951 -0
  16. quantum/cli/jobs.py +356 -0
  17. quantum/cli/mq.py +582 -0
  18. quantum/cli/pkg.py +390 -0
  19. quantum/cli/runner.py +565 -0
  20. quantum/cli/server_process.py +159 -0
  21. quantum/cli/utils.py +334 -0
  22. quantum/compiler/__init__.py +30 -0
  23. quantum/compiler/base_generator.py +367 -0
  24. quantum/compiler/cli.py +295 -0
  25. quantum/compiler/expression_transformer.py +444 -0
  26. quantum/compiler/javascript/__init__.py +10 -0
  27. quantum/compiler/javascript/generator.py +659 -0
  28. quantum/compiler/optimizer.py +270 -0
  29. quantum/compiler/python/__init__.py +10 -0
  30. quantum/compiler/python/generator.py +883 -0
  31. quantum/compiler/python/runtime.py +863 -0
  32. quantum/compiler/transpiler.py +330 -0
  33. quantum/core/__init__.py +3 -0
  34. quantum/core/ast_nodes.py +2619 -0
  35. quantum/core/config_env.py +54 -0
  36. quantum/core/docs_links.py +8 -0
  37. quantum/core/expression_diagnostics.py +87 -0
  38. quantum/core/expression_stdlib.py +208 -0
  39. quantum/core/expressions.py +677 -0
  40. quantum/core/features/agents/src/__init__.py +30 -0
  41. quantum/core/features/agents/src/ast_node.py +540 -0
  42. quantum/core/features/conditionals/src/__init__.py +8 -0
  43. quantum/core/features/conditionals/src/ast_node.py +68 -0
  44. quantum/core/features/data_import/src/__init__.py +0 -0
  45. quantum/core/features/data_import/src/ast_node.py +292 -0
  46. quantum/core/features/data_import/src/runtime.py +533 -0
  47. quantum/core/features/dump/src/__init__.py +12 -0
  48. quantum/core/features/dump/src/ast_node.py +106 -0
  49. quantum/core/features/dump/src/parser.py +61 -0
  50. quantum/core/features/dump/src/runtime.py +246 -0
  51. quantum/core/features/functions/src/__init__.py +8 -0
  52. quantum/core/features/functions/src/ast_node.py +149 -0
  53. quantum/core/features/game_engine_2d/src/__init__.py +19 -0
  54. quantum/core/features/game_engine_2d/src/ast_nodes.py +1719 -0
  55. quantum/core/features/game_engine_2d/src/parser.py +983 -0
  56. quantum/core/features/invocation/src/__init__.py +0 -0
  57. quantum/core/features/invocation/src/ast_node.py +147 -0
  58. quantum/core/features/invocation/src/runtime.py +332 -0
  59. quantum/core/features/knowledge_base/src/__init__.py +6 -0
  60. quantum/core/features/knowledge_base/src/ast_node.py +113 -0
  61. quantum/core/features/knowledge_base/src/parser.py +82 -0
  62. quantum/core/features/logging/src/__init__.py +12 -0
  63. quantum/core/features/logging/src/ast_node.py +111 -0
  64. quantum/core/features/logging/src/parser.py +50 -0
  65. quantum/core/features/logging/src/runtime.py +190 -0
  66. quantum/core/features/loops/src/__init__.py +8 -0
  67. quantum/core/features/loops/src/ast_node.py +60 -0
  68. quantum/core/features/query/src/__init__.py +0 -0
  69. quantum/core/features/query/src/query_validators.py +20 -0
  70. quantum/core/features/state_management/src/__init__.py +11 -0
  71. quantum/core/features/state_management/src/ast_node.py +121 -0
  72. quantum/core/features/terminal_engine/src/__init__.py +21 -0
  73. quantum/core/features/terminal_engine/src/ast_nodes.py +560 -0
  74. quantum/core/features/terminal_engine/src/parser.py +361 -0
  75. quantum/core/features/testing_engine/src/__init__.py +41 -0
  76. quantum/core/features/testing_engine/src/ast_nodes.py +1212 -0
  77. quantum/core/features/testing_engine/src/parser.py +604 -0
  78. quantum/core/features/theming/src/__init__.py +48 -0
  79. quantum/core/features/theming/src/ast_node.py +137 -0
  80. quantum/core/features/theming/src/presets.py +405 -0
  81. quantum/core/features/ui_engine/src/__init__.py +20 -0
  82. quantum/core/features/ui_engine/src/ast_nodes.py +1913 -0
  83. quantum/core/features/ui_engine/src/parser.py +1192 -0
  84. quantum/core/features/websocket/src/__init__.py +24 -0
  85. quantum/core/features/websocket/src/ast_node.py +247 -0
  86. quantum/core/guards.py +53 -0
  87. quantum/core/html_compat.py +299 -0
  88. quantum/core/parser.py +1551 -0
  89. quantum/core/parser_registry.py +213 -0
  90. quantum/core/parsers/__init__.py +76 -0
  91. quantum/core/parsers/ai/__init__.py +12 -0
  92. quantum/core/parsers/ai/agent_parser.py +106 -0
  93. quantum/core/parsers/ai/knowledge_parser.py +86 -0
  94. quantum/core/parsers/ai/llm_parser.py +78 -0
  95. quantum/core/parsers/ai/team_parser.py +88 -0
  96. quantum/core/parsers/base.py +322 -0
  97. quantum/core/parsers/composition/__init__.py +10 -0
  98. quantum/core/parsers/composition/import_parser.py +50 -0
  99. quantum/core/parsers/composition/slot_parser.py +48 -0
  100. quantum/core/parsers/control_flow/__init__.py +11 -0
  101. quantum/core/parsers/control_flow/if_parser.py +71 -0
  102. quantum/core/parsers/control_flow/loop_parser.py +105 -0
  103. quantum/core/parsers/control_flow/set_parser.py +93 -0
  104. quantum/core/parsers/data/__init__.py +12 -0
  105. quantum/core/parsers/data/data_parser.py +229 -0
  106. quantum/core/parsers/data/invoke_parser.py +133 -0
  107. quantum/core/parsers/data/query_parser.py +213 -0
  108. quantum/core/parsers/data/transaction_parser.py +86 -0
  109. quantum/core/parsers/events/__init__.py +9 -0
  110. quantum/core/parsers/events/dispatch_event_parser.py +44 -0
  111. quantum/core/parsers/forms/__init__.py +11 -0
  112. quantum/core/parsers/forms/action_parser.py +79 -0
  113. quantum/core/parsers/forms/flash_parser.py +34 -0
  114. quantum/core/parsers/forms/redirect_parser.py +33 -0
  115. quantum/core/parsers/functions/__init__.py +11 -0
  116. quantum/core/parsers/functions/function_parser.py +98 -0
  117. quantum/core/parsers/functions/param_parser.py +73 -0
  118. quantum/core/parsers/functions/return_parser.py +31 -0
  119. quantum/core/parsers/html/__init__.py +10 -0
  120. quantum/core/parsers/html/component_call_parser.py +130 -0
  121. quantum/core/parsers/html/html_parser.py +115 -0
  122. quantum/core/parsers/jobs/__init__.py +11 -0
  123. quantum/core/parsers/jobs/job_parser.py +71 -0
  124. quantum/core/parsers/jobs/schedule_parser.py +62 -0
  125. quantum/core/parsers/jobs/thread_parser.py +57 -0
  126. quantum/core/parsers/messaging/__init__.py +17 -0
  127. quantum/core/parsers/messaging/message_ack_parser.py +30 -0
  128. quantum/core/parsers/messaging/message_nack_parser.py +30 -0
  129. quantum/core/parsers/messaging/message_parser.py +114 -0
  130. quantum/core/parsers/messaging/queue_parser.py +61 -0
  131. quantum/core/parsers/messaging/websocket_parser.py +121 -0
  132. quantum/core/parsers/routing/__init__.py +9 -0
  133. quantum/core/parsers/routing/route_parser.py +41 -0
  134. quantum/core/parsers/scripting/__init__.py +12 -0
  135. quantum/core/parsers/scripting/pyclass_parser.py +62 -0
  136. quantum/core/parsers/scripting/pydecorator_parser.py +68 -0
  137. quantum/core/parsers/scripting/pyimport_parser.py +52 -0
  138. quantum/core/parsers/scripting/python_parser.py +49 -0
  139. quantum/core/parsers/services/__init__.py +12 -0
  140. quantum/core/parsers/services/dump_parser.py +52 -0
  141. quantum/core/parsers/services/file_parser.py +48 -0
  142. quantum/core/parsers/services/log_parser.py +46 -0
  143. quantum/core/parsers/services/mail_parser.py +65 -0
  144. quantum/core/tiers.py +164 -0
  145. quantum/core/xml_lines.py +81 -0
  146. quantum/packages/__init__.py +28 -0
  147. quantum/packages/manager.py +413 -0
  148. quantum/packages/manifest.py +351 -0
  149. quantum/packages/registry.py +399 -0
  150. quantum/packages/resolver.py +336 -0
  151. quantum/plugins/__init__.py +33 -0
  152. quantum/plugins/hooks.py +329 -0
  153. quantum/plugins/loader.py +479 -0
  154. quantum/plugins/manifest.py +336 -0
  155. quantum/plugins/registry.py +371 -0
  156. quantum/runtime/__init__.py +25 -0
  157. quantum/runtime/action_handler.py +532 -0
  158. quantum/runtime/adapters/__init__.py +88 -0
  159. quantum/runtime/adapters/memory_adapter.py +690 -0
  160. quantum/runtime/adapters/rabbitmq_adapter.py +715 -0
  161. quantum/runtime/adapters/redis_adapter.py +582 -0
  162. quantum/runtime/adapters/sqlite_adapter.py +414 -0
  163. quantum/runtime/agent_service.py +1133 -0
  164. quantum/runtime/ast_cache.py +506 -0
  165. quantum/runtime/auth_service.py +267 -0
  166. quantum/runtime/component.py +1048 -0
  167. quantum/runtime/component_composer.py +133 -0
  168. quantum/runtime/component_resolver.py +174 -0
  169. quantum/runtime/conditions.py +54 -0
  170. quantum/runtime/database_service.py +595 -0
  171. quantum/runtime/db_schema.py +100 -0
  172. quantum/runtime/dev_panel.py +178 -0
  173. quantum/runtime/email_service.py +162 -0
  174. quantum/runtime/error_handler.py +295 -0
  175. quantum/runtime/execution_context.py +283 -0
  176. quantum/runtime/executor_registry.py +178 -0
  177. quantum/runtime/executors/__init__.py +71 -0
  178. quantum/runtime/executors/ai/__init__.py +12 -0
  179. quantum/runtime/executors/ai/agent_executor.py +217 -0
  180. quantum/runtime/executors/ai/knowledge_executor.py +114 -0
  181. quantum/runtime/executors/ai/llm_executor.py +153 -0
  182. quantum/runtime/executors/ai/team_executor.py +171 -0
  183. quantum/runtime/executors/base.py +264 -0
  184. quantum/runtime/executors/control_flow/__init__.py +12 -0
  185. quantum/runtime/executors/control_flow/if_executor.py +98 -0
  186. quantum/runtime/executors/control_flow/loop_executor.py +308 -0
  187. quantum/runtime/executors/control_flow/redirect_executor.py +43 -0
  188. quantum/runtime/executors/control_flow/set_executor.py +464 -0
  189. quantum/runtime/executors/data/__init__.py +12 -0
  190. quantum/runtime/executors/data/data_executor.py +156 -0
  191. quantum/runtime/executors/data/invoke_executor.py +228 -0
  192. quantum/runtime/executors/data/query_executor.py +290 -0
  193. quantum/runtime/executors/data/transaction_executor.py +91 -0
  194. quantum/runtime/executors/jobs/__init__.py +11 -0
  195. quantum/runtime/executors/jobs/job_executor.py +190 -0
  196. quantum/runtime/executors/jobs/schedule_executor.py +132 -0
  197. quantum/runtime/executors/jobs/thread_executor.py +127 -0
  198. quantum/runtime/executors/messaging/__init__.py +17 -0
  199. quantum/runtime/executors/messaging/message_ack_executor.py +51 -0
  200. quantum/runtime/executors/messaging/message_executor.py +174 -0
  201. quantum/runtime/executors/messaging/queue_executor.py +103 -0
  202. quantum/runtime/executors/messaging/websocket_executor.py +197 -0
  203. quantum/runtime/executors/scripting/__init__.py +11 -0
  204. quantum/runtime/executors/scripting/pyclass_executor.py +90 -0
  205. quantum/runtime/executors/scripting/pyimport_executor.py +81 -0
  206. quantum/runtime/executors/scripting/python_executor.py +249 -0
  207. quantum/runtime/executors/services/__init__.py +12 -0
  208. quantum/runtime/executors/services/dump_executor.py +72 -0
  209. quantum/runtime/executors/services/file_executor.py +89 -0
  210. quantum/runtime/executors/services/log_executor.py +77 -0
  211. quantum/runtime/executors/services/mail_executor.py +81 -0
  212. quantum/runtime/expression_cache.py +498 -0
  213. quantum/runtime/file_upload_service.py +326 -0
  214. quantum/runtime/function_registry.py +118 -0
  215. quantum/runtime/game_builder.py +166 -0
  216. quantum/runtime/game_code_generator.py +2371 -0
  217. quantum/runtime/game_templates.py +2006 -0
  218. quantum/runtime/godot_code_generator.py +4681 -0
  219. quantum/runtime/godot_templates.py +1449 -0
  220. quantum/runtime/job_executor.py +1599 -0
  221. quantum/runtime/knowledge_service.py +546 -0
  222. quantum/runtime/llm_cache.py +100 -0
  223. quantum/runtime/llm_providers.py +704 -0
  224. quantum/runtime/llm_service.py +287 -0
  225. quantum/runtime/local_server.py +28 -0
  226. quantum/runtime/logging_setup.py +141 -0
  227. quantum/runtime/message_broker.py +364 -0
  228. quantum/runtime/message_queue_service.py +571 -0
  229. quantum/runtime/param_validation.py +218 -0
  230. quantum/runtime/pypy_compat.py +317 -0
  231. quantum/runtime/python_bridge.py +698 -0
  232. quantum/runtime/query_validators.py +304 -0
  233. quantum/runtime/renderer.py +734 -0
  234. quantum/runtime/service_container.py +470 -0
  235. quantum/runtime/table_params.py +163 -0
  236. quantum/runtime/terminal_builder.py +76 -0
  237. quantum/runtime/terminal_code_generator.py +607 -0
  238. quantum/runtime/terminal_templates.py +243 -0
  239. quantum/runtime/testing_builder.py +77 -0
  240. quantum/runtime/testing_code_generator.py +833 -0
  241. quantum/runtime/testing_templates.py +85 -0
  242. quantum/runtime/ui_builder.py +222 -0
  243. quantum/runtime/ui_console.py +405 -0
  244. quantum/runtime/ui_desktop.py +56 -0
  245. quantum/runtime/ui_form_rules.py +193 -0
  246. quantum/runtime/ui_html_adapter.py +2567 -0
  247. quantum/runtime/ui_html_templates.py +2106 -0
  248. quantum/runtime/ui_mobile_adapter.py +1832 -0
  249. quantum/runtime/ui_mobile_templates.py +1003 -0
  250. quantum/runtime/ui_page_renderer.py +392 -0
  251. quantum/runtime/ui_pager.py +73 -0
  252. quantum/runtime/ui_table_edit.py +139 -0
  253. quantum/runtime/ui_textual_adapter.py +1866 -0
  254. quantum/runtime/ui_textual_templates.py +45 -0
  255. quantum/runtime/ui_tokens.py +465 -0
  256. quantum/runtime/ui_validator.py +365 -0
  257. quantum/runtime/ui_view.py +221 -0
  258. quantum/runtime/validators.py +256 -0
  259. quantum/runtime/web_server.py +2131 -0
  260. quantum/runtime/websocket_adapter.py +501 -0
  261. quantum/runtime/websocket_service.py +585 -0
  262. quantum/runtime/websocket_transport.py +289 -0
  263. quantum/runtime/wsgi.py +101 -0
  264. quantum/services.py +109 -0
  265. quantum/utils/__init__.py +1 -0
  266. quantum_admin/__init__.py +4 -0
  267. quantum_admin/assets/quantum-admin-connectors.js +123 -0
  268. quantum_admin/assets/quantum-admin.css +2058 -0
  269. quantum_admin/assets/quantum-source-highlight.js +106 -0
  270. quantum_admin/backend/__init__.py +4 -0
  271. quantum_admin/backend/audit_service.py +346 -0
  272. quantum_admin/backend/auth_service.py +394 -0
  273. quantum_admin/backend/component_discovery.py +766 -0
  274. quantum_admin/backend/config_generator.py +586 -0
  275. quantum_admin/backend/connector_service.py +1016 -0
  276. quantum_admin/backend/crud.py +557 -0
  277. quantum_admin/backend/database.py +226 -0
  278. quantum_admin/backend/db_setup_service.py +193 -0
  279. quantum_admin/backend/deploy_service.py +698 -0
  280. quantum_admin/backend/docker_service.py +422 -0
  281. quantum_admin/backend/environment_service.py +418 -0
  282. quantum_admin/backend/git_service.py +370 -0
  283. quantum_admin/backend/health_service.py +390 -0
  284. quantum_admin/backend/job_service.py +347 -0
  285. quantum_admin/backend/log_service.py +331 -0
  286. quantum_admin/backend/main.py +14426 -0
  287. quantum_admin/backend/models.py +986 -0
  288. quantum_admin/backend/pipeline_service.py +812 -0
  289. quantum_admin/backend/resource_manager.py +1118 -0
  290. quantum_admin/backend/schemas.py +419 -0
  291. quantum_admin/backend/secret_manager.py +277 -0
  292. quantum_admin/backend/settings_service.py +488 -0
  293. quantum_admin/backend/template_service.py +710 -0
  294. quantum_admin/backend/test_execution_service.py +364 -0
  295. quantum_admin/backend/test_generator.py +782 -0
  296. quantum_admin/backend/webhook_service.py +454 -0
  297. quantum_admin/backend/websocket_manager.py +360 -0
  298. quantum_admin/components/admin/_layout/AdminShell.q +121 -0
  299. quantum_admin/components/admin/agents.q +107 -0
  300. quantum_admin/components/admin/app/[name].q +558 -0
  301. quantum_admin/components/admin/applications.q +160 -0
  302. quantum_admin/components/admin/component/[...path].q +205 -0
  303. quantum_admin/components/admin/components.q +59 -0
  304. quantum_admin/components/admin/connectors.q +283 -0
  305. quantum_admin/components/admin/dashboard.q +86 -0
  306. quantum_admin/components/admin/database.q +95 -0
  307. quantum_admin/components/admin/features.q +69 -0
  308. quantum_admin/components/admin/index.q +12 -0
  309. quantum_admin/components/admin/jobs.q +75 -0
  310. quantum_admin/components/admin/login.q +65 -0
  311. quantum_admin/components/admin/logout.q +11 -0
  312. quantum_admin/components/admin/settings.q +174 -0
  313. quantum_admin/components/admin/source.q +45 -0
  314. quantum_admin/components/admin/tests.q +73 -0
  315. quantum_admin/run.py +13 -0
  316. quantum_admin/services/__init__.py +16 -0
  317. quantum_admin/services/_base.py +84 -0
  318. quantum_admin/services/_component_test_generator.py +205 -0
  319. quantum_admin/services/_yaml_editor.py +82 -0
  320. quantum_admin/services/apps.py +330 -0
  321. quantum_admin/services/auth.py +61 -0
  322. quantum_admin/services/components.py +210 -0
  323. quantum_admin/services/connectors.py +164 -0
  324. quantum_admin/services/projects.py +189 -0
  325. quantum_admin/services/repository.py +223 -0
  326. quantum_admin/services/settings.py +150 -0
  327. quantum_admin/services/yaml_import.py +118 -0
  328. quantum_framework-0.18.0.dist-info/METADATA +281 -0
  329. quantum_framework-0.18.0.dist-info/RECORD +333 -0
  330. quantum_framework-0.18.0.dist-info/WHEEL +5 -0
  331. quantum_framework-0.18.0.dist-info/entry_points.txt +2 -0
  332. quantum_framework-0.18.0.dist-info/licenses/LICENSE +21 -0
  333. quantum_framework-0.18.0.dist-info/top_level.txt +2 -0
quantum/cli/runner.py ADDED
@@ -0,0 +1,565 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ Quantum CLI Runner - Main orchestrator refactored
5
+ """
6
+
7
+ import argparse
8
+ import sys
9
+ import os
10
+ from pathlib import Path
11
+
12
+ # Fix encoding on Windows
13
+ if os.name == 'nt': # Windows
14
+ try:
15
+ os.system('chcp 65001 >nul 2>&1') # UTF-8
16
+ if hasattr(sys.stdout, 'reconfigure'):
17
+ sys.stdout.reconfigure(encoding='utf-8')
18
+ sys.stderr.reconfigure(encoding='utf-8')
19
+ except:
20
+ pass # Silent fallback
21
+
22
+ # Fix imports - use absolute imports
23
+
24
+ from quantum.core.parser import QuantumParser, QuantumParseError
25
+ from quantum.core.ast_nodes import ComponentNode, ApplicationNode, JobNode
26
+ from quantum.runtime.component import ComponentRuntime, ComponentExecutionError
27
+ from quantum.runtime.executors.control_flow.redirect_executor import PageRedirect
28
+ from quantum.runtime.web_server import QuantumWebServer
29
+
30
+ # Import deploy commands (lazy load to avoid import errors if requests not installed)
31
+ def _get_deploy_module():
32
+ try:
33
+ from quantum.cli.deploy import (
34
+ create_deploy_parser, create_apps_parser,
35
+ handle_deploy, handle_apps
36
+ )
37
+ return True, create_deploy_parser, create_apps_parser, handle_deploy, handle_apps
38
+ except ImportError as e:
39
+ return False, None, None, None, str(e)
40
+
41
+ # Import package commands
42
+ def _get_pkg_module():
43
+ try:
44
+ from quantum.cli.pkg import create_pkg_parser, handle_pkg
45
+ return True, create_pkg_parser, handle_pkg
46
+ except ImportError as e:
47
+ return False, None, str(e)
48
+
49
+ # Import jobs commands
50
+ def _get_jobs_module():
51
+ try:
52
+ from quantum.cli.jobs import create_jobs_parser, handle_jobs
53
+ return True, create_jobs_parser, handle_jobs
54
+ except ImportError as e:
55
+ return False, None, str(e)
56
+
57
+ # Import message queue commands
58
+ def _get_mq_module():
59
+ try:
60
+ from quantum.cli.mq import create_mq_parser, handle_mq
61
+ return True, create_mq_parser, handle_mq
62
+ except ImportError as e:
63
+ return False, None, str(e)
64
+
65
+ # Import migration commands
66
+ def _get_migrate_module():
67
+ try:
68
+ from quantum.cli.commands.migrate import MigrationRunner
69
+ return True, MigrationRunner
70
+ except ImportError as e:
71
+ return False, str(e)
72
+
73
+ def load_config(config_path: str = 'quantum.config.yaml') -> dict:
74
+ """Load quantum.config.yaml if present.
75
+
76
+ The `run` command used to build a ComponentRuntime with no config at all,
77
+ so `datasources:` declared in quantum.config.yaml were never seen and
78
+ every q:query fell through to the optional Quantum Admin API.
79
+ """
80
+ from quantum.core.config_env import ConfigEnvError, expand_env
81
+ try:
82
+ import yaml
83
+ path = Path(config_path)
84
+ if path.exists():
85
+ with open(path, 'r', encoding='utf-8') as fh:
86
+ return expand_env(yaml.safe_load(fh) or {})
87
+ except ConfigEnvError:
88
+ raise # CFG-1: never run with a half-read config
89
+ except Exception as exc:
90
+ print(f"[WARN] Could not read {config_path}: {exc}")
91
+ return {}
92
+
93
+
94
+ class QuantumRunner:
95
+ """Main Quantum Runner - Clean orchestration"""
96
+
97
+ def __init__(self, config: dict = None):
98
+ self.parser = QuantumParser()
99
+ self.config = config if config is not None else load_config()
100
+ self.component_runtime = ComponentRuntime(config=self.config)
101
+
102
+ def run(self, file_path: str, debug: bool = False) -> int:
103
+ """Execute .q file"""
104
+ try:
105
+ if debug:
106
+ print(f"[DEBUG] Parsing file: {Path(file_path).name}")
107
+
108
+ # Store source directory for asset resolution
109
+ self._source_dir = str(Path(file_path).resolve().parent)
110
+
111
+ # Parse file → AST
112
+ ast_node = self.parser.parse_file(file_path)
113
+
114
+ if debug:
115
+ print(f"[DEBUG] AST generated: {type(ast_node).__name__}")
116
+ print(f"[DEBUG] Validating AST...")
117
+
118
+ # Validate AST
119
+ validation_errors = ast_node.validate()
120
+ if validation_errors:
121
+ print("[ERROR] Validation errors:")
122
+ for error in validation_errors:
123
+ print(f" - {error}")
124
+ return 1
125
+
126
+ # Execute based on type
127
+ return self._execute_ast(ast_node, debug)
128
+
129
+ except QuantumParseError as e:
130
+ print(f"[ERROR] Parse error: {e}")
131
+ return 1
132
+ except Exception as e:
133
+ print(f"[ERROR] Unexpected error: {e}")
134
+ if debug:
135
+ import traceback
136
+ traceback.print_exc()
137
+ return 1
138
+
139
+ def _execute_ast(self, ast_node, debug: bool = False) -> int:
140
+ """Execute AST based on type"""
141
+ if isinstance(ast_node, ComponentNode):
142
+ return self._execute_component(ast_node, debug)
143
+ elif isinstance(ast_node, ApplicationNode):
144
+ return self._execute_application(ast_node, debug)
145
+ elif isinstance(ast_node, JobNode):
146
+ return self._execute_job(ast_node, debug)
147
+ else:
148
+ print(f"[ERROR] Unsupported AST type: {type(ast_node)}")
149
+ return 1
150
+
151
+ def _execute_component(self, component: ComponentNode, debug: bool = False) -> int:
152
+ """Execute q:component"""
153
+ print(f"[EXEC] Executing component: {component.name}")
154
+ if debug:
155
+ print(f" Type: {component.component_type}")
156
+ print(f" Params: {len(component.params)}")
157
+ print(f" Returns: {len(component.returns)}")
158
+
159
+ try:
160
+ result = self.component_runtime.execute_component(component)
161
+ if result is not None:
162
+ print(f"[SUCCESS] Result: {result}")
163
+ else:
164
+ print("[WARN] Component executed without return")
165
+ return 0
166
+
167
+ except ComponentExecutionError as e:
168
+ print(f"[ERROR] Execution error: {e}")
169
+ return 1
170
+ except PageRedirect as r:
171
+ print(f"[REDIRECT] {r.status} {r.url}")
172
+ return 0
173
+
174
+ def _execute_application(self, app: ApplicationNode, debug: bool = False) -> int:
175
+ """Execute q:application"""
176
+ print(f"[EXEC] Executing application: {app.app_id}")
177
+ print(f"[INFO] Type: {app.app_type}")
178
+
179
+ if debug:
180
+ print(f" Routes: {len(app.routes)}")
181
+ for route in app.routes:
182
+ print(f" {route.method} {route.path}")
183
+
184
+ from quantum.core.tiers import warn_app_type
185
+ warn_app_type(app.app_type)
186
+
187
+ if app.app_type == 'game':
188
+ return self._build_game(app, debug)
189
+ elif app.app_type == 'terminal':
190
+ return self._build_terminal(app, debug)
191
+ elif app.app_type == 'testing':
192
+ return self._build_tests(app, debug)
193
+ elif app.app_type == 'ui':
194
+ target = getattr(self, '_ui_target', 'html')
195
+ return self._build_ui(app, target, debug)
196
+ else:
197
+ print(f"[ERROR] Application type '{app.app_type}' not supported")
198
+ return 1
199
+
200
+ def _build_game(self, app: ApplicationNode, debug: bool = False) -> int:
201
+ """Build game from game application using selected engine backend."""
202
+ from quantum.runtime.game_builder import GameBuilder, GameBuildError
203
+ engine = getattr(self, '_game_engine', 'pixi')
204
+ try:
205
+ source_dir = getattr(self, '_source_dir', None)
206
+ builder = GameBuilder(engine=engine, source_dir=source_dir)
207
+ output_path = builder.build_to_file(app)
208
+ engine_label = 'Godot 4 project' if engine == 'godot' else 'HTML game'
209
+ print(f"[SUCCESS] {engine_label} built: {output_path}")
210
+ if debug:
211
+ print(f" Engine: {engine}")
212
+ print(f" Scenes: {len(getattr(app, 'scenes', []))}")
213
+ print(f" Behaviors: {len(getattr(app, 'behaviors', []))}")
214
+ print(f" Prefabs: {len(getattr(app, 'prefabs', []))}")
215
+ return 0
216
+ except GameBuildError as e:
217
+ print(f"[ERROR] Game build error: {e}")
218
+ return 1
219
+
220
+ def _build_terminal(self, app: ApplicationNode, debug: bool = False) -> int:
221
+ """Build standalone Python TUI app from terminal application."""
222
+ from quantum.runtime.terminal_builder import TerminalBuilder, TerminalBuildError
223
+ try:
224
+ builder = TerminalBuilder()
225
+ output_path = builder.build_to_file(app)
226
+ print(f"[SUCCESS] Terminal app built: {output_path}")
227
+ if debug:
228
+ print(f" Screens: {len(getattr(app, 'screens', []))}")
229
+ print(f" Keybindings: {len(getattr(app, 'keybindings', []))}")
230
+ return 0
231
+ except TerminalBuildError as e:
232
+ print(f"[ERROR] Terminal build error: {e}")
233
+ return 1
234
+
235
+ def _build_tests(self, app: ApplicationNode, debug: bool = False) -> int:
236
+ """Build standalone pytest file from testing application."""
237
+ from quantum.runtime.testing_builder import TestingBuilder, TestingBuildError
238
+ try:
239
+ builder = TestingBuilder()
240
+ output_path = builder.build_to_file(app)
241
+ print(f"[SUCCESS] Test file built: {output_path}")
242
+ if debug:
243
+ print(f" Suites: {len(getattr(app, 'test_suites', []))}")
244
+ print(f" Fixtures: {len(getattr(app, 'test_fixtures', []))}")
245
+ print(f" Mocks: {len(getattr(app, 'test_mocks', []))}")
246
+ return 0
247
+ except TestingBuildError as e:
248
+ print(f"[ERROR] Test build error: {e}")
249
+ return 1
250
+
251
+ def _build_ui(self, app: ApplicationNode, target: str = 'html', debug: bool = False) -> int:
252
+ """Build multi-target UI app from UI application."""
253
+ from quantum.runtime.ui_builder import UIBuilder, UIBuildError
254
+ try:
255
+ builder = UIBuilder()
256
+ output_path = builder.build_to_file(app, target=target)
257
+ print(f"[SUCCESS] UI app built ({target}): {output_path}")
258
+ if debug:
259
+ print(f" Windows: {len(getattr(app, 'ui_windows', []))}")
260
+ print(f" UI children: {len(getattr(app, 'ui_children', []))}")
261
+ print(f" Target: {target}")
262
+ return 0
263
+ except UIBuildError as e:
264
+ print(f"[ERROR] UI build error: {e}")
265
+ return 1
266
+
267
+ def _execute_job(self, job: JobNode, debug: bool = False) -> int:
268
+ """Execute q:job"""
269
+ print(f"[EXEC] Executing job: {job.job_id}")
270
+ if job.schedule:
271
+ print(f"[INFO] Schedule: {job.schedule}")
272
+
273
+ # TODO: Implement real job execution
274
+ print("[SUCCESS] Job executed successfully")
275
+ return 0
276
+
277
+
278
+ def main():
279
+ """CLI entry point"""
280
+ parser = argparse.ArgumentParser(
281
+ description='Quantum CLI - Execute .q files, start servers, and deploy applications',
282
+ formatter_class=argparse.RawDescriptionHelpFormatter,
283
+ epilog="""
284
+ Examples:
285
+ quantum start # Start web server (magic!)
286
+ quantum run hello.q # Execute component
287
+ quantum admin # Start the Quantum Admin
288
+ quantum console # The application's pages in the terminal
289
+ quantum desktop # The application's pages in a desktop window
290
+ quantum check # Pages parse, SQL compiles, query fields exist
291
+ quantum run game.q --engine godot # Build Godot 4 project
292
+ quantum run backup-job.q # Execute job
293
+ quantum deploy ./my-app # Deploy application
294
+ quantum apps # List deployed apps
295
+ quantum apps logs my-app # View app logs
296
+ quantum pkg init ./my-component # Initialize new package
297
+ quantum pkg install ./package # Install package
298
+ quantum pkg list # List installed packages
299
+ quantum jobs list # List scheduled jobs
300
+ quantum jobs run my-job # Run a job manually
301
+ quantum jobs worker start # Start job worker
302
+ quantum mq queues list # List message queues
303
+ quantum mq publish topic message # Publish to topic
304
+ quantum mq worker --queues q1,q2 # Start message worker
305
+ """
306
+ )
307
+ # --version: le a versao do metadata do pacote instalado (funciona quando
308
+ # veio de `pip install`), com fallback para quando roda da arvore fonte.
309
+ try:
310
+ from importlib.metadata import version as _pkg_version, PackageNotFoundError
311
+ try:
312
+ _versao = _pkg_version("quantum-framework")
313
+ except PackageNotFoundError:
314
+ _versao = "dev (nao instalado via pip)"
315
+ except Exception:
316
+ _versao = "unknown"
317
+ parser.add_argument('--version', action='version',
318
+ version=f'quantum {_versao}')
319
+
320
+ subparsers = parser.add_subparsers(dest='command', help='Command to execute')
321
+
322
+ # Run command
323
+ run_parser = subparsers.add_parser('run', help='Execute a .q file')
324
+ run_parser.add_argument('file', help='.q file to execute')
325
+ run_parser.add_argument('--debug', action='store_true', help='Debug mode')
326
+ run_parser.add_argument('--config', default='quantum.config.yaml', help='Config file')
327
+ run_parser.add_argument('--target', choices=['html', 'textual', 'desktop', 'mobile'], default='html',
328
+ help='UI target (for type="ui" apps): html, textual, desktop, or mobile')
329
+ run_parser.add_argument('--engine', choices=['pixi', 'godot'], default='pixi',
330
+ help='Game engine backend: pixi (default, HTML5) or godot (Godot 4 project)')
331
+
332
+ # Start command
333
+ start_parser = subparsers.add_parser('start', help='Start web server')
334
+ start_parser.add_argument('--port', type=int, help='Port (overrides config)')
335
+ start_parser.add_argument('--config', default='quantum.config.yaml', help='Config file')
336
+ start_parser.add_argument('--debug', action='store_true', help='Debug mode')
337
+
338
+ # Stop command
339
+ subparsers.add_parser('stop', help='Stop running web server')
340
+
341
+ # Console: the application's pages in the terminal (UI-3)
342
+ console_parser = subparsers.add_parser('console', help="Open the application's pages in the terminal")
343
+ console_parser.add_argument('path', nargs='?', default='/', help='Page to open (default: /)')
344
+ console_parser.add_argument('--config', default='quantum.config.yaml', help='Config file')
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
+
350
+ # Desktop: the application's pages in a native window (UI-4)
351
+ desktop_parser = subparsers.add_parser('desktop', help="Open the application's pages in a desktop window")
352
+ desktop_parser.add_argument('path', nargs='?', default='/', help='Page to open (default: /)')
353
+ desktop_parser.add_argument('--config', default='quantum.config.yaml', help='Config file')
354
+ desktop_parser.add_argument('--width', type=int, default=1024, help='Window width (default: 1024)')
355
+ desktop_parser.add_argument('--height', type=int, default=720, help='Window height (default: 720)')
356
+
357
+ # Admin command (the screens need the [admin] extra; checked when run)
358
+ from quantum.cli.admin import create_admin_parser
359
+ create_admin_parser(subparsers)
360
+
361
+ # Deploy commands (if available)
362
+ deploy_available, create_deploy_parser, create_apps_parser, handle_deploy, handle_apps = _get_deploy_module()
363
+
364
+ if deploy_available:
365
+ create_deploy_parser(subparsers)
366
+ create_apps_parser(subparsers)
367
+
368
+ # Package commands (if available)
369
+ pkg_available, create_pkg_parser, handle_pkg = _get_pkg_module()
370
+
371
+ if pkg_available:
372
+ create_pkg_parser(subparsers)
373
+
374
+ # Jobs commands (if available)
375
+ jobs_available, create_jobs_parser, handle_jobs = _get_jobs_module()
376
+
377
+ if jobs_available:
378
+ create_jobs_parser(subparsers)
379
+
380
+ # Message queue commands (if available)
381
+ mq_available, create_mq_parser, handle_mq = _get_mq_module()
382
+
383
+ if mq_available:
384
+ create_mq_parser(subparsers)
385
+
386
+ # Migration commands
387
+ migrate_parser = subparsers.add_parser('migrate', help='Database migration commands')
388
+ migrate_parser.add_argument('--datasource', help='Datasource from quantum.config.yaml (default: the only one declared)')
389
+ migrate_subparsers = migrate_parser.add_subparsers(dest='migrate_command')
390
+
391
+ migrate_subparsers.add_parser('status', help='Show migration status')
392
+
393
+ migrate_up_parser = migrate_subparsers.add_parser('up', help='Apply pending migrations')
394
+ migrate_up_parser.add_argument('-n', '--count', type=int, help='Number of migrations to apply')
395
+
396
+ migrate_down_parser = migrate_subparsers.add_parser('down', help='Rollback migrations')
397
+ migrate_down_parser.add_argument('-n', '--count', type=int, default=1, help='Number of migrations to rollback')
398
+
399
+ migrate_create_parser = migrate_subparsers.add_parser('create', help='Create a new migration')
400
+ migrate_create_parser.add_argument('name', help='Migration name')
401
+
402
+ # Parse arguments
403
+ args = parser.parse_args()
404
+
405
+ if not args.command:
406
+ parser.print_help()
407
+ sys.exit(0)
408
+
409
+ # Handle 'start' command
410
+ if args.command == 'start':
411
+ from quantum.runtime.web_server import start_server
412
+ try:
413
+ # Exit with whatever the server reports: a taken port or a failed
414
+ # bind must not look like a clean start to a supervisor or CI.
415
+ sys.exit(start_server(args.config, port=getattr(args, 'port', None)) or 0)
416
+ except Exception as e:
417
+ print(f"[ERROR] Failed to start server: {e}")
418
+ if getattr(args, 'debug', False):
419
+ import traceback
420
+ traceback.print_exc()
421
+ sys.exit(1)
422
+
423
+ elif args.command == 'console':
424
+ from quantum.runtime.ui_console import run_console
425
+ sys.exit(run_console(args.config, args.path))
426
+
427
+ elif args.command == 'check':
428
+ from quantum.cli.check import run_check
429
+ sys.exit(run_check(args.config))
430
+
431
+ elif args.command == 'desktop':
432
+ from quantum.runtime.ui_desktop import run_desktop
433
+ sys.exit(run_desktop(args.config, args.path, width=args.width, height=args.height))
434
+
435
+ elif args.command == 'admin':
436
+ from quantum.cli.admin import handle_admin
437
+ sys.exit(handle_admin(args))
438
+
439
+ # Handle 'stop' command
440
+ elif args.command == 'stop':
441
+ from quantum.cli.server_process import stop_server
442
+ sys.exit(stop_server())
443
+
444
+ # Handle 'run' command
445
+ elif args.command == 'run':
446
+ if not args.file:
447
+ print("[ERROR] File argument is required for 'run' command")
448
+ print("Usage: quantum run <file.q>")
449
+ sys.exit(1)
450
+
451
+ runner = QuantumRunner(config=load_config(getattr(args, 'config', 'quantum.config.yaml')))
452
+ runner._ui_target = getattr(args, 'target', 'html')
453
+ runner._game_engine = getattr(args, 'engine', 'pixi')
454
+ exit_code = runner.run(args.file, getattr(args, 'debug', False))
455
+ sys.exit(exit_code)
456
+
457
+ # Handle 'deploy' command
458
+ elif args.command == 'deploy':
459
+ if not deploy_available:
460
+ print("[ERROR] Deploy functionality not available.")
461
+ print(f"Missing dependency: {handle_apps}")
462
+ print("Install with: pip install requests")
463
+ sys.exit(1)
464
+ sys.exit(handle_deploy(args))
465
+
466
+ # Handle 'apps' command
467
+ elif args.command == 'apps':
468
+ if not deploy_available:
469
+ print("[ERROR] Apps functionality not available.")
470
+ print(f"Missing dependency: {handle_apps}")
471
+ print("Install with: pip install requests")
472
+ sys.exit(1)
473
+ sys.exit(handle_apps(args))
474
+
475
+ # Handle 'jobs' command
476
+ elif args.command == 'jobs':
477
+ if not jobs_available:
478
+ print("[ERROR] Jobs functionality not available.")
479
+ print(f"Error: {handle_jobs}")
480
+ sys.exit(1)
481
+ sys.exit(handle_jobs(args))
482
+
483
+ # Handle 'mq' command
484
+ elif args.command == 'mq':
485
+ if not mq_available:
486
+ print("[ERROR] Message queue functionality not available.")
487
+ print(f"Error: {handle_mq}")
488
+ sys.exit(1)
489
+ sys.exit(handle_mq(args))
490
+
491
+ # Handle 'pkg' command
492
+ elif args.command == 'pkg':
493
+ if not pkg_available:
494
+ print("[ERROR] Package functionality not available.")
495
+ print(f"Error: {handle_pkg}")
496
+ sys.exit(1)
497
+ sys.exit(handle_pkg(args))
498
+
499
+ # Handle 'migrate' command
500
+ elif args.command == 'migrate':
501
+ migrate_available, result = _get_migrate_module()
502
+ if not migrate_available:
503
+ print(f"[ERROR] Migration functionality not available: {result}")
504
+ sys.exit(1)
505
+
506
+ MigrationRunner = result
507
+
508
+ try:
509
+ runner = MigrationRunner(datasource=getattr(args, 'datasource', None))
510
+
511
+ if args.migrate_command == 'status':
512
+ import json
513
+ status = runner.status()
514
+ print(f"\nDatabase: {status['database_type']}")
515
+ print(f"Applied migrations: {status['total_applied']}")
516
+ print(f"Pending migrations: {status['total_pending']}")
517
+
518
+ if status['applied']:
519
+ print("\nApplied:")
520
+ for m in status['applied']:
521
+ print(f" {m['version']}: {m['name']} (applied: {m['applied_at']})")
522
+
523
+ if status['pending']:
524
+ print("\nPending:")
525
+ for m in status['pending']:
526
+ print(f" {m['version']}: {m['name']}")
527
+
528
+ elif args.migrate_command == 'up':
529
+ results = runner.up(count=getattr(args, 'count', None))
530
+ applied = sum(1 for r in results if r.get('status') == 'applied')
531
+ failed = sum(1 for r in results if r.get('status') == 'failed')
532
+ print(f"\nApplied: {applied}, Failed: {failed}")
533
+ if failed:
534
+ sys.exit(1)
535
+
536
+ elif args.migrate_command == 'down':
537
+ results = runner.down(count=getattr(args, 'count', 1))
538
+ rolled_back = sum(1 for r in results if r.get('status') == 'rolled_back')
539
+ failed = sum(1 for r in results if r.get('status') == 'failed')
540
+ print(f"\nRolled back: {rolled_back}, Failed: {failed}")
541
+ if failed:
542
+ sys.exit(1)
543
+
544
+ elif args.migrate_command == 'create':
545
+ filepath = runner.create(args.name)
546
+ print(f"Created migration: {filepath}")
547
+ print(f"Also created rollback: {filepath.with_suffix('.down.sql')}")
548
+
549
+ else:
550
+ print("Usage: quantum migrate <status|up|down|create> [options]")
551
+ sys.exit(1)
552
+
553
+ sys.exit(0)
554
+
555
+ except Exception as e:
556
+ print(f"[ERROR] Migration failed: {e}")
557
+ sys.exit(1)
558
+
559
+ else:
560
+ parser.print_help()
561
+ sys.exit(1)
562
+
563
+
564
+ if __name__ == '__main__':
565
+ main()