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/__init__.py ADDED
@@ -0,0 +1 @@
1
+ # Quantum main package
@@ -0,0 +1,2 @@
1
+ # CLI Quantum modules
2
+ from .runner import QuantumRunner, main
@@ -0,0 +1,15 @@
1
+ """
2
+ Quantum CLI Commands
3
+
4
+ Each command module provides a click command group or command.
5
+ """
6
+
7
+ from quantum.cli.commands.new import new
8
+ from quantum.cli.commands.dev import dev
9
+ from quantum.cli.commands.build import build
10
+ from quantum.cli.commands.serve import serve
11
+ from quantum.cli.commands.test import test
12
+ from quantum.cli.commands.lint import lint
13
+ from quantum.cli.commands.docs import docs
14
+
15
+ __all__ = ['new', 'dev', 'build', 'serve', 'test', 'lint', 'docs']
@@ -0,0 +1,417 @@
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', 'desktop', '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, desktop, 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 desktop
57
+
58
+ quantum build --target all --output ./build
59
+
60
+ quantum build --target mobile --no-minify
61
+ """
62
+ console = get_console(quiet=quiet)
63
+
64
+ # Find project root
65
+ project_root = find_project_root()
66
+ if not project_root:
67
+ console.error("No Quantum project found. Run from a project directory or use 'quantum new'")
68
+ raise click.Abort()
69
+
70
+ output_dir = Path(output)
71
+ if not output_dir.is_absolute():
72
+ output_dir = project_root / output
73
+
74
+ # Resolve minify flag
75
+ should_minify = minify and not no_minify
76
+
77
+ console.header(
78
+ "Building Quantum Application",
79
+ f"Target: {target} | Output: {output_dir}"
80
+ )
81
+
82
+ # Clean output directory
83
+ if clean and output_dir.exists():
84
+ with console.spinner("Cleaning output directory..."):
85
+ shutil.rmtree(output_dir)
86
+ console.info(f"Cleaned: {output_dir}")
87
+
88
+ # Create output directory
89
+ output_dir.mkdir(parents=True, exist_ok=True)
90
+
91
+ # Find .q files
92
+ q_files = find_q_files(project_root)
93
+ if not q_files:
94
+ console.error("No .q files found in project")
95
+ raise click.Abort()
96
+
97
+ console.info(f"Found {len(q_files)} .q files")
98
+
99
+ # Determine targets to build
100
+ if target == 'all':
101
+ targets_to_build = ['html', 'desktop', 'mobile', 'textual']
102
+ else:
103
+ targets_to_build = [target]
104
+
105
+ # Build each target
106
+ results = {}
107
+ for build_target in targets_to_build:
108
+ console.print()
109
+ console.info(f"Building for target: [bold]{build_target}[/bold]")
110
+
111
+ try:
112
+ result = _build_target(
113
+ project_root=project_root,
114
+ q_files=q_files,
115
+ target=build_target,
116
+ output_dir=output_dir / build_target if target == 'all' else output_dir,
117
+ minify=should_minify,
118
+ sourcemap=sourcemap,
119
+ debug=debug,
120
+ console=console
121
+ )
122
+ results[build_target] = result
123
+ console.success(f"Built {build_target}: {result['output_path']}")
124
+
125
+ except Exception as e:
126
+ console.error(f"Failed to build {build_target}: {e}")
127
+ if debug:
128
+ import traceback
129
+ console.print(traceback.format_exc())
130
+ results[build_target] = {'error': str(e)}
131
+
132
+ # Summary
133
+ console.print()
134
+ successful = [t for t, r in results.items() if 'error' not in r]
135
+ failed = [t for t, r in results.items() if 'error' in r]
136
+
137
+ if successful:
138
+ console.panel(
139
+ f"[bold green]Successfully built:[/bold green] {', '.join(successful)}\n"
140
+ f"[bold]Output:[/bold] {output_dir}",
141
+ title="Build Complete"
142
+ )
143
+
144
+ if failed:
145
+ console.warning(f"Failed targets: {', '.join(failed)}")
146
+
147
+ # Watch mode
148
+ if watch:
149
+ console.print()
150
+ console.info("Watching for changes... (Ctrl+C to stop)")
151
+ _watch_and_rebuild(
152
+ project_root=project_root,
153
+ targets=targets_to_build,
154
+ output_dir=output_dir,
155
+ minify=should_minify,
156
+ sourcemap=sourcemap,
157
+ debug=debug,
158
+ console=console,
159
+ target=target
160
+ )
161
+
162
+
163
+ def _build_target(
164
+ project_root: Path,
165
+ q_files: List[Path],
166
+ target: str,
167
+ output_dir: Path,
168
+ minify: bool,
169
+ sourcemap: bool,
170
+ debug: bool,
171
+ console
172
+ ) -> dict:
173
+ """Build a specific target."""
174
+ import sys
175
+
176
+ from quantum.core.parser import QuantumParser
177
+ from quantum.core.ast_nodes import ApplicationNode
178
+
179
+ parser = QuantumParser()
180
+ output_dir.mkdir(parents=True, exist_ok=True)
181
+
182
+ built_files = []
183
+
184
+ with console.progress("Building...", total=len(q_files)) as advance:
185
+ for q_file in q_files:
186
+ try:
187
+ # Parse file
188
+ ast = parser.parse_file(str(q_file))
189
+
190
+ # Only build ApplicationNode files
191
+ if isinstance(ast, ApplicationNode):
192
+ output_path = _build_application(
193
+ app=ast,
194
+ target=target,
195
+ output_dir=output_dir,
196
+ minify=minify,
197
+ debug=debug
198
+ )
199
+ built_files.append(output_path)
200
+
201
+ if advance:
202
+ advance()
203
+
204
+ except Exception as e:
205
+ if debug:
206
+ console.warning(f"Skipping {q_file.name}: {e}")
207
+
208
+ # Copy static assets
209
+ assets_dir = project_root / 'assets'
210
+ if assets_dir.exists():
211
+ target_assets = output_dir / 'assets'
212
+ if target_assets.exists():
213
+ shutil.rmtree(target_assets)
214
+ shutil.copytree(assets_dir, target_assets)
215
+ console.info(f"Copied assets to {target_assets}")
216
+
217
+ return {
218
+ 'target': target,
219
+ 'output_path': str(output_dir),
220
+ 'files_built': len(built_files),
221
+ 'minified': minify,
222
+ }
223
+
224
+
225
+ def _build_application(
226
+ app,
227
+ target: str,
228
+ output_dir: Path,
229
+ minify: bool,
230
+ debug: bool
231
+ ) -> str:
232
+ """Build an application node to target."""
233
+ from quantum.runtime.ui_builder import UIBuilder, UIBuildError
234
+
235
+ # Determine builder based on app type
236
+ app_type = getattr(app, 'app_type', 'html')
237
+
238
+ if app_type == 'game':
239
+ from quantum.runtime.game_builder import GameBuilder
240
+ builder = GameBuilder()
241
+ ext = '.html'
242
+ elif app_type == 'terminal':
243
+ from quantum.runtime.terminal_builder import TerminalBuilder
244
+ builder = TerminalBuilder()
245
+ ext = '.py'
246
+ elif app_type == 'testing':
247
+ from quantum.runtime.testing_builder import TestingBuilder
248
+ builder = TestingBuilder()
249
+ ext = '.py'
250
+ elif app_type == 'ui' or target in ('html', 'desktop', 'mobile', 'textual'):
251
+ builder = UIBuilder()
252
+ # Map target to extension
253
+ ext_map = {
254
+ 'html': '.html',
255
+ 'desktop': '.py',
256
+ 'mobile': '.js',
257
+ 'textual': '.py',
258
+ }
259
+ ext = ext_map.get(target, '.html')
260
+ else:
261
+ # Default to HTML
262
+ builder = UIBuilder()
263
+ ext = '.html'
264
+ target = 'html'
265
+
266
+ # Build output
267
+ output_file = output_dir / f"{app.app_id}{ext}"
268
+
269
+ if hasattr(builder, 'build_to_file'):
270
+ # UI builder with target
271
+ if isinstance(builder, UIBuilder):
272
+ output_path = builder.build_to_file(app, target=target, output_path=str(output_file))
273
+ else:
274
+ output_path = builder.build_to_file(app, output_path=str(output_file))
275
+ else:
276
+ # Generic builder
277
+ code = builder.build(app)
278
+ output_file.write_text(code, encoding='utf-8')
279
+ output_path = str(output_file)
280
+
281
+ # Minify if requested
282
+ if minify and ext == '.html':
283
+ _minify_html(output_path)
284
+ elif minify and ext == '.js':
285
+ _minify_js(output_path)
286
+ elif minify and ext == '.css':
287
+ _minify_css(output_path)
288
+
289
+ return output_path
290
+
291
+
292
+ def _minify_html(path: str) -> None:
293
+ """Minify HTML file."""
294
+ try:
295
+ import re
296
+ content = Path(path).read_text(encoding='utf-8')
297
+
298
+ # Basic HTML minification
299
+ # Remove comments
300
+ content = re.sub(r'<!--(?!\[if).*?-->', '', content, flags=re.DOTALL)
301
+ # Remove extra whitespace between tags
302
+ content = re.sub(r'>\s+<', '><', content)
303
+ # Remove leading/trailing whitespace
304
+ content = '\n'.join(line.strip() for line in content.splitlines() if line.strip())
305
+
306
+ Path(path).write_text(content, encoding='utf-8')
307
+ except Exception:
308
+ pass # Minification is optional
309
+
310
+
311
+ def _minify_js(path: str) -> None:
312
+ """Minify JavaScript file."""
313
+ try:
314
+ import re
315
+ content = Path(path).read_text(encoding='utf-8')
316
+
317
+ # Basic JS minification
318
+ # Remove single-line comments (but not URLs)
319
+ content = re.sub(r'(?<!:)//.*$', '', content, flags=re.MULTILINE)
320
+ # Remove multi-line comments
321
+ content = re.sub(r'/\*.*?\*/', '', content, flags=re.DOTALL)
322
+ # Remove extra whitespace
323
+ content = ' '.join(content.split())
324
+
325
+ Path(path).write_text(content, encoding='utf-8')
326
+ except Exception:
327
+ pass
328
+
329
+
330
+ def _minify_css(path: str) -> None:
331
+ """Minify CSS file."""
332
+ try:
333
+ import re
334
+ content = Path(path).read_text(encoding='utf-8')
335
+
336
+ # Basic CSS minification
337
+ # Remove comments
338
+ content = re.sub(r'/\*.*?\*/', '', content, flags=re.DOTALL)
339
+ # Remove extra whitespace
340
+ content = re.sub(r'\s+', ' ', content)
341
+ # Remove space around special chars
342
+ content = re.sub(r'\s*([{};:,])\s*', r'\1', content)
343
+
344
+ Path(path).write_text(content, encoding='utf-8')
345
+ except Exception:
346
+ pass
347
+
348
+
349
+ def _watch_and_rebuild(
350
+ project_root: Path,
351
+ targets: List[str],
352
+ output_dir: Path,
353
+ minify: bool,
354
+ sourcemap: bool,
355
+ debug: bool,
356
+ console,
357
+ target: str
358
+ ):
359
+ """Watch for changes and rebuild."""
360
+ import time
361
+ import signal
362
+
363
+ last_mtimes = {}
364
+
365
+ def get_file_mtimes():
366
+ mtimes = {}
367
+ for ext in ['.q', '.yaml', '.yml']:
368
+ for f in project_root.rglob(f'*{ext}'):
369
+ try:
370
+ mtimes[f] = f.stat().st_mtime
371
+ except OSError:
372
+ pass
373
+ return mtimes
374
+
375
+ def signal_handler(sig, frame):
376
+ console.print()
377
+ console.info("Stopping watch mode...")
378
+ raise SystemExit(0)
379
+
380
+ signal.signal(signal.SIGINT, signal_handler)
381
+ last_mtimes = get_file_mtimes()
382
+
383
+ while True:
384
+ time.sleep(1)
385
+ current_mtimes = get_file_mtimes()
386
+
387
+ changed = []
388
+ for f, mtime in current_mtimes.items():
389
+ if f not in last_mtimes or mtime > last_mtimes[f]:
390
+ changed.append(f)
391
+
392
+ if changed:
393
+ console.print()
394
+ for f in changed:
395
+ rel_path = f.relative_to(project_root)
396
+ console.info(f"Changed: {rel_path}")
397
+
398
+ console.info("Rebuilding...")
399
+
400
+ q_files = find_q_files(project_root)
401
+ for build_target in targets:
402
+ try:
403
+ _build_target(
404
+ project_root=project_root,
405
+ q_files=q_files,
406
+ target=build_target,
407
+ output_dir=output_dir / build_target if target == 'all' else output_dir,
408
+ minify=minify,
409
+ sourcemap=sourcemap,
410
+ debug=debug,
411
+ console=console
412
+ )
413
+ console.success(f"Rebuilt {build_target}")
414
+ except Exception as e:
415
+ console.error(f"Failed to rebuild {build_target}: {e}")
416
+
417
+ 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()