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
@@ -0,0 +1,414 @@
1
+ """
2
+ Quantum CLI - Build Command
3
+
4
+ Build Quantum applications for production.
5
+ """
6
+
7
+ import os
8
+ import shutil
9
+ from pathlib import Path
10
+ from typing import Optional, List
11
+ from datetime import datetime
12
+
13
+ import click
14
+
15
+ from quantum.cli.utils import get_console, find_project_root, find_q_files
16
+
17
+
18
+ # Available build targets
19
+ TARGETS = ['html', 'mobile', 'textual', 'all']
20
+
21
+
22
+ @click.command('build')
23
+ @click.option('--target', '-t', type=click.Choice(TARGETS), default='html',
24
+ help='Build target (html, mobile, textual, all)')
25
+ @click.option('--output', '-o', type=click.Path(), default='./dist',
26
+ help='Output directory')
27
+ @click.option('--minify', is_flag=True, default=True, help='Minify output')
28
+ @click.option('--no-minify', is_flag=True, help='Disable minification')
29
+ @click.option('--sourcemap', is_flag=True, help='Generate source maps')
30
+ @click.option('--watch', '-w', is_flag=True, help='Watch mode - rebuild on changes')
31
+ @click.option('--clean', is_flag=True, help='Clean output directory before build')
32
+ @click.option('--config', '-c', type=click.Path(), default='quantum.config.yaml',
33
+ help='Config file path')
34
+ @click.option('--debug', is_flag=True, help='Debug mode with verbose output')
35
+ @click.option('--quiet', '-q', is_flag=True, help='Quiet mode')
36
+ def build(
37
+ target: str,
38
+ output: str,
39
+ minify: bool,
40
+ no_minify: bool,
41
+ sourcemap: bool,
42
+ watch: bool,
43
+ clean: bool,
44
+ config: str,
45
+ debug: bool,
46
+ quiet: bool
47
+ ):
48
+ """Build Quantum application for production.
49
+
50
+ Compiles .q files to the specified target format.
51
+
52
+ Examples:
53
+
54
+ quantum build
55
+
56
+ quantum build --target all --output ./build
57
+
58
+ quantum build --target mobile --no-minify
59
+ """
60
+ console = get_console(quiet=quiet)
61
+
62
+ # Find project root
63
+ project_root = find_project_root()
64
+ if not project_root:
65
+ console.error("No Quantum project found. Run from a project directory or use 'quantum new'")
66
+ raise click.Abort()
67
+
68
+ output_dir = Path(output)
69
+ if not output_dir.is_absolute():
70
+ output_dir = project_root / output
71
+
72
+ # Resolve minify flag
73
+ should_minify = minify and not no_minify
74
+
75
+ console.header(
76
+ "Building Quantum Application",
77
+ f"Target: {target} | Output: {output_dir}"
78
+ )
79
+
80
+ # Clean output directory
81
+ if clean and output_dir.exists():
82
+ with console.spinner("Cleaning output directory..."):
83
+ shutil.rmtree(output_dir)
84
+ console.info(f"Cleaned: {output_dir}")
85
+
86
+ # Create output directory
87
+ output_dir.mkdir(parents=True, exist_ok=True)
88
+
89
+ # Find .q files
90
+ q_files = find_q_files(project_root)
91
+ if not q_files:
92
+ console.error("No .q files found in project")
93
+ raise click.Abort()
94
+
95
+ console.info(f"Found {len(q_files)} .q files")
96
+
97
+ # Determine targets to build
98
+ if target == 'all':
99
+ targets_to_build = ['html', 'mobile', 'textual']
100
+ else:
101
+ targets_to_build = [target]
102
+
103
+ # Build each target
104
+ results = {}
105
+ for build_target in targets_to_build:
106
+ console.print()
107
+ console.info(f"Building for target: [bold]{build_target}[/bold]")
108
+
109
+ try:
110
+ result = _build_target(
111
+ project_root=project_root,
112
+ q_files=q_files,
113
+ target=build_target,
114
+ output_dir=output_dir / build_target if target == 'all' else output_dir,
115
+ minify=should_minify,
116
+ sourcemap=sourcemap,
117
+ debug=debug,
118
+ console=console
119
+ )
120
+ results[build_target] = result
121
+ console.success(f"Built {build_target}: {result['output_path']}")
122
+
123
+ except Exception as e:
124
+ console.error(f"Failed to build {build_target}: {e}")
125
+ if debug:
126
+ import traceback
127
+ console.print(traceback.format_exc())
128
+ results[build_target] = {'error': str(e)}
129
+
130
+ # Summary
131
+ console.print()
132
+ successful = [t for t, r in results.items() if 'error' not in r]
133
+ failed = [t for t, r in results.items() if 'error' in r]
134
+
135
+ if successful:
136
+ console.panel(
137
+ f"[bold green]Successfully built:[/bold green] {', '.join(successful)}\n"
138
+ f"[bold]Output:[/bold] {output_dir}",
139
+ title="Build Complete"
140
+ )
141
+
142
+ if failed:
143
+ console.warning(f"Failed targets: {', '.join(failed)}")
144
+
145
+ # Watch mode
146
+ if watch:
147
+ console.print()
148
+ console.info("Watching for changes... (Ctrl+C to stop)")
149
+ _watch_and_rebuild(
150
+ project_root=project_root,
151
+ targets=targets_to_build,
152
+ output_dir=output_dir,
153
+ minify=should_minify,
154
+ sourcemap=sourcemap,
155
+ debug=debug,
156
+ console=console,
157
+ target=target
158
+ )
159
+
160
+
161
+ def _build_target(
162
+ project_root: Path,
163
+ q_files: List[Path],
164
+ target: str,
165
+ output_dir: Path,
166
+ minify: bool,
167
+ sourcemap: bool,
168
+ debug: bool,
169
+ console
170
+ ) -> dict:
171
+ """Build a specific target."""
172
+ import sys
173
+
174
+ from quantum.core.parser import QuantumParser
175
+ from quantum.core.ast_nodes import ApplicationNode
176
+
177
+ parser = QuantumParser()
178
+ output_dir.mkdir(parents=True, exist_ok=True)
179
+
180
+ built_files = []
181
+
182
+ with console.progress("Building...", total=len(q_files)) as advance:
183
+ for q_file in q_files:
184
+ try:
185
+ # Parse file
186
+ ast = parser.parse_file(str(q_file))
187
+
188
+ # Only build ApplicationNode files
189
+ if isinstance(ast, ApplicationNode):
190
+ output_path = _build_application(
191
+ app=ast,
192
+ target=target,
193
+ output_dir=output_dir,
194
+ minify=minify,
195
+ debug=debug
196
+ )
197
+ built_files.append(output_path)
198
+
199
+ if advance:
200
+ advance()
201
+
202
+ except Exception as e:
203
+ if debug:
204
+ console.warning(f"Skipping {q_file.name}: {e}")
205
+
206
+ # Copy static assets
207
+ assets_dir = project_root / 'assets'
208
+ if assets_dir.exists():
209
+ target_assets = output_dir / 'assets'
210
+ if target_assets.exists():
211
+ shutil.rmtree(target_assets)
212
+ shutil.copytree(assets_dir, target_assets)
213
+ console.info(f"Copied assets to {target_assets}")
214
+
215
+ return {
216
+ 'target': target,
217
+ 'output_path': str(output_dir),
218
+ 'files_built': len(built_files),
219
+ 'minified': minify,
220
+ }
221
+
222
+
223
+ def _build_application(
224
+ app,
225
+ target: str,
226
+ output_dir: Path,
227
+ minify: bool,
228
+ debug: bool
229
+ ) -> str:
230
+ """Build an application node to target."""
231
+ from quantum.runtime.ui_builder import UIBuilder, UIBuildError
232
+
233
+ # Determine builder based on app type
234
+ app_type = getattr(app, 'app_type', 'html')
235
+
236
+ if app_type == 'game':
237
+ from quantum.runtime.game_builder import GameBuilder
238
+ builder = GameBuilder()
239
+ ext = '.html'
240
+ elif app_type == 'terminal':
241
+ from quantum.runtime.terminal_builder import TerminalBuilder
242
+ builder = TerminalBuilder()
243
+ ext = '.py'
244
+ elif app_type == 'testing':
245
+ from quantum.runtime.testing_builder import TestingBuilder
246
+ builder = TestingBuilder()
247
+ ext = '.py'
248
+ elif app_type == 'ui' or target in ('html', 'mobile', 'textual'):
249
+ builder = UIBuilder()
250
+ # Map target to extension
251
+ ext_map = {
252
+ 'html': '.html',
253
+ 'mobile': '.js',
254
+ 'textual': '.py',
255
+ }
256
+ ext = ext_map.get(target, '.html')
257
+ else:
258
+ # Default to HTML
259
+ builder = UIBuilder()
260
+ ext = '.html'
261
+ target = 'html'
262
+
263
+ # Build output
264
+ output_file = output_dir / f"{app.app_id}{ext}"
265
+
266
+ if hasattr(builder, 'build_to_file'):
267
+ # UI builder with target
268
+ if isinstance(builder, UIBuilder):
269
+ output_path = builder.build_to_file(app, target=target, output_path=str(output_file))
270
+ else:
271
+ output_path = builder.build_to_file(app, output_path=str(output_file))
272
+ else:
273
+ # Generic builder
274
+ code = builder.build(app)
275
+ output_file.write_text(code, encoding='utf-8')
276
+ output_path = str(output_file)
277
+
278
+ # Minify if requested
279
+ if minify and ext == '.html':
280
+ _minify_html(output_path)
281
+ elif minify and ext == '.js':
282
+ _minify_js(output_path)
283
+ elif minify and ext == '.css':
284
+ _minify_css(output_path)
285
+
286
+ return output_path
287
+
288
+
289
+ def _minify_html(path: str) -> None:
290
+ """Minify HTML file."""
291
+ try:
292
+ import re
293
+ content = Path(path).read_text(encoding='utf-8')
294
+
295
+ # Basic HTML minification
296
+ # Remove comments
297
+ content = re.sub(r'<!--(?!\[if).*?-->', '', content, flags=re.DOTALL)
298
+ # Remove extra whitespace between tags
299
+ content = re.sub(r'>\s+<', '><', content)
300
+ # Remove leading/trailing whitespace
301
+ content = '\n'.join(line.strip() for line in content.splitlines() if line.strip())
302
+
303
+ Path(path).write_text(content, encoding='utf-8')
304
+ except Exception:
305
+ pass # Minification is optional
306
+
307
+
308
+ def _minify_js(path: str) -> None:
309
+ """Minify JavaScript file."""
310
+ try:
311
+ import re
312
+ content = Path(path).read_text(encoding='utf-8')
313
+
314
+ # Basic JS minification
315
+ # Remove single-line comments (but not URLs)
316
+ content = re.sub(r'(?<!:)//.*$', '', content, flags=re.MULTILINE)
317
+ # Remove multi-line comments
318
+ content = re.sub(r'/\*.*?\*/', '', content, flags=re.DOTALL)
319
+ # Remove extra whitespace
320
+ content = ' '.join(content.split())
321
+
322
+ Path(path).write_text(content, encoding='utf-8')
323
+ except Exception:
324
+ pass
325
+
326
+
327
+ def _minify_css(path: str) -> None:
328
+ """Minify CSS file."""
329
+ try:
330
+ import re
331
+ content = Path(path).read_text(encoding='utf-8')
332
+
333
+ # Basic CSS minification
334
+ # Remove comments
335
+ content = re.sub(r'/\*.*?\*/', '', content, flags=re.DOTALL)
336
+ # Remove extra whitespace
337
+ content = re.sub(r'\s+', ' ', content)
338
+ # Remove space around special chars
339
+ content = re.sub(r'\s*([{};:,])\s*', r'\1', content)
340
+
341
+ Path(path).write_text(content, encoding='utf-8')
342
+ except Exception:
343
+ pass
344
+
345
+
346
+ def _watch_and_rebuild(
347
+ project_root: Path,
348
+ targets: List[str],
349
+ output_dir: Path,
350
+ minify: bool,
351
+ sourcemap: bool,
352
+ debug: bool,
353
+ console,
354
+ target: str
355
+ ):
356
+ """Watch for changes and rebuild."""
357
+ import time
358
+ import signal
359
+
360
+ last_mtimes = {}
361
+
362
+ def get_file_mtimes():
363
+ mtimes = {}
364
+ for ext in ['.q', '.yaml', '.yml']:
365
+ for f in project_root.rglob(f'*{ext}'):
366
+ try:
367
+ mtimes[f] = f.stat().st_mtime
368
+ except OSError:
369
+ pass
370
+ return mtimes
371
+
372
+ def signal_handler(sig, frame):
373
+ console.print()
374
+ console.info("Stopping watch mode...")
375
+ raise SystemExit(0)
376
+
377
+ signal.signal(signal.SIGINT, signal_handler)
378
+ last_mtimes = get_file_mtimes()
379
+
380
+ while True:
381
+ time.sleep(1)
382
+ current_mtimes = get_file_mtimes()
383
+
384
+ changed = []
385
+ for f, mtime in current_mtimes.items():
386
+ if f not in last_mtimes or mtime > last_mtimes[f]:
387
+ changed.append(f)
388
+
389
+ if changed:
390
+ console.print()
391
+ for f in changed:
392
+ rel_path = f.relative_to(project_root)
393
+ console.info(f"Changed: {rel_path}")
394
+
395
+ console.info("Rebuilding...")
396
+
397
+ q_files = find_q_files(project_root)
398
+ for build_target in targets:
399
+ try:
400
+ _build_target(
401
+ project_root=project_root,
402
+ q_files=q_files,
403
+ target=build_target,
404
+ output_dir=output_dir / build_target if target == 'all' else output_dir,
405
+ minify=minify,
406
+ sourcemap=sourcemap,
407
+ debug=debug,
408
+ console=console
409
+ )
410
+ console.success(f"Rebuilt {build_target}")
411
+ except Exception as e:
412
+ console.error(f"Failed to rebuild {build_target}: {e}")
413
+
414
+ last_mtimes = current_mtimes
@@ -0,0 +1,185 @@
1
+ """
2
+ Quantum CLI - Dev Command
3
+
4
+ Start development server with hot reload.
5
+ """
6
+
7
+ import os
8
+ import sys
9
+ import time
10
+ import signal
11
+ import threading
12
+ from pathlib import Path
13
+ from typing import Optional, Set, List
14
+ from datetime import datetime
15
+
16
+ import click
17
+
18
+ from quantum.cli.utils import get_console, find_project_root, find_q_files
19
+
20
+
21
+ @click.command('dev')
22
+ @click.option('--port', '-p', type=int, default=8080, help='Port to run on')
23
+ @click.option('--host', '-h', type=str, default='0.0.0.0', help='Host to bind to')
24
+ @click.option('--no-reload', is_flag=True, help='Disable hot reload')
25
+ @click.option('--config', '-c', type=click.Path(), default='quantum.config.yaml',
26
+ help='Config file path')
27
+ @click.option('--debug', is_flag=True, help='Enable debug mode')
28
+ @click.option('--quiet', '-q', is_flag=True, help='Quiet mode')
29
+ @click.option('--ws-port', type=int, default=35729, help='WebSocket port for hot reload')
30
+ @click.pass_context
31
+ def dev(ctx, port: int, host: str, no_reload: bool, config: str, debug: bool, quiet: bool, ws_port: int):
32
+ """Start development server with hot reload.
33
+
34
+ Watches .q files for changes and automatically reloads.
35
+
36
+ Examples:
37
+
38
+ quantum dev
39
+
40
+ quantum dev --port 3000
41
+
42
+ quantum dev --no-reload --debug
43
+
44
+ quantum dev --ws-port 35730
45
+ """
46
+ console = get_console(quiet=quiet)
47
+
48
+ # Find project root
49
+ project_root = find_project_root()
50
+ if not project_root:
51
+ console.warning("No Quantum project found in current directory.")
52
+ console.info("Creating a minimal dev server for current directory...")
53
+ project_root = Path.cwd()
54
+
55
+ config_path = project_root / config
56
+
57
+ console.header(
58
+ "Quantum Development Server",
59
+ f"Project: {project_root.name}"
60
+ )
61
+
62
+ # Find .q files
63
+ q_files = find_q_files(project_root)
64
+ console.info(f"Found {len(q_files)} .q files")
65
+
66
+ # Hot reload manager
67
+ hot_reload_manager = None
68
+
69
+ if not no_reload:
70
+ try:
71
+ from quantum.cli.hot_reload import HotReloadManager, ReloadType
72
+
73
+ # Determine watch paths
74
+ watch_paths = [project_root]
75
+
76
+ # Also watch components directory if it exists
77
+ components_dir = project_root / 'components'
78
+ if components_dir.exists():
79
+ watch_paths.append(components_dir)
80
+
81
+ # Watch static directory for CSS/JS changes
82
+ static_dir = project_root / 'static'
83
+ if static_dir.exists():
84
+ watch_paths.append(static_dir)
85
+
86
+ def on_reload(changes, reload_type):
87
+ """Callback when files change."""
88
+ console.print()
89
+ for change in changes:
90
+ try:
91
+ rel_path = change.path.relative_to(project_root)
92
+ except ValueError:
93
+ rel_path = change.path
94
+
95
+ timestamp = datetime.now().strftime('%H:%M:%S')
96
+ console.info(f"[dim]{timestamp}[/dim] {change.change_type}: [path]{rel_path}[/path]")
97
+
98
+ if reload_type == ReloadType.CSS:
99
+ console.info("[bold green]CSS updated[/bold green] (no full reload)")
100
+ else:
101
+ console.info("[bold blue]Reloading...[/bold blue]")
102
+
103
+ hot_reload_manager = HotReloadManager(
104
+ watch_paths=watch_paths,
105
+ extensions=['.q', '.yaml', '.yml', '.css', '.js', '.html'],
106
+ ws_host='localhost',
107
+ ws_port=ws_port,
108
+ debounce_ms=100,
109
+ on_reload=on_reload,
110
+ console=console
111
+ )
112
+
113
+ hot_reload_manager.start()
114
+
115
+ except ImportError as e:
116
+ console.warning(f"Hot reload dependencies not fully available: {e}")
117
+ console.info("Install with: pip install watchdog websockets")
118
+ hot_reload_manager = None
119
+
120
+ # Display server info
121
+ url = f"http://{host if host != '0.0.0.0' else 'localhost'}:{port}"
122
+
123
+ info_lines = [
124
+ f"[bold]Server:[/bold] {url}",
125
+ f"[bold]Hot Reload:[/bold] {'Disabled' if no_reload else 'Enabled'}",
126
+ ]
127
+
128
+ if not no_reload and hot_reload_manager:
129
+ info_lines.append(f"[bold]WebSocket:[/bold] ws://localhost:{ws_port}")
130
+
131
+ info_lines.append(f"[bold]Debug:[/bold] {'On' if debug else 'Off'}")
132
+
133
+ console.panel(
134
+ '\n'.join(info_lines),
135
+ title="Development Server",
136
+ style="green"
137
+ )
138
+
139
+ # Setup signal handler
140
+ def signal_handler(sig, frame):
141
+ console.print()
142
+ console.info("Shutting down...")
143
+ if hot_reload_manager:
144
+ hot_reload_manager.stop()
145
+ sys.exit(0)
146
+
147
+ signal.signal(signal.SIGINT, signal_handler)
148
+ if hasattr(signal, 'SIGTERM'):
149
+ signal.signal(signal.SIGTERM, signal_handler)
150
+
151
+ try:
152
+ # Import and start server
153
+
154
+ from quantum.runtime.web_server import QuantumWebServer, start_server
155
+
156
+ console.info(f"Starting server on {url}")
157
+ console.print()
158
+ console.print("[dim]Press Ctrl+C to stop[/dim]")
159
+ console.print()
160
+
161
+ # Start the server with hot reload config
162
+ start_server(
163
+ str(config_path),
164
+ port=port,
165
+ hot_reload=not no_reload,
166
+ hot_reload_port=ws_port if not no_reload else None
167
+ )
168
+
169
+ except ImportError as e:
170
+ console.error(f"Failed to import Quantum runtime: {e}")
171
+ console.info("Make sure you're in the Quantum project directory")
172
+ if hot_reload_manager:
173
+ hot_reload_manager.stop()
174
+ raise click.Abort()
175
+ except Exception as e:
176
+ console.error(f"Server error: {e}")
177
+ if debug:
178
+ import traceback
179
+ console.print(traceback.format_exc())
180
+ if hot_reload_manager:
181
+ hot_reload_manager.stop()
182
+ raise click.Abort()
183
+ finally:
184
+ if hot_reload_manager:
185
+ hot_reload_manager.stop()