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