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
@@ -0,0 +1,399 @@
1
+ """
2
+ Quantum Package Registry
3
+
4
+ Local registry for storing and managing installed packages.
5
+
6
+ Registry structure:
7
+ ~/.quantum/
8
+ ├── packages/
9
+ │ ├── my-component/
10
+ │ │ ├── 1.0.0/ # Version directory
11
+ │ │ │ ├── quantum.yaml
12
+ │ │ │ ├── src/
13
+ │ │ │ └── ...
14
+ │ │ └── 1.0.1/
15
+ │ └── other-package/
16
+ ├── registry.json # Package index
17
+ └── config.yaml # User config
18
+ """
19
+
20
+ import json
21
+ import os
22
+ import shutil
23
+ from pathlib import Path
24
+ from typing import Dict, List, Optional, Any
25
+ from datetime import datetime
26
+
27
+ from .manifest import PackageManifest, ManifestError
28
+
29
+
30
+ class RegistryError(Exception):
31
+ """Error in package registry operations."""
32
+ pass
33
+
34
+
35
+ class PackageRegistry:
36
+ """
37
+ Local package registry manager.
38
+
39
+ Handles:
40
+ - Package installation/removal
41
+ - Version management
42
+ - Package index maintenance
43
+ - Package search
44
+ """
45
+
46
+ def __init__(self, registry_path: Optional[Path] = None):
47
+ """Initialize registry at given path or default ~/.quantum."""
48
+ if registry_path is None:
49
+ # Default to ~/.quantum/
50
+ home = Path.home()
51
+ registry_path = home / '.quantum'
52
+
53
+ self.registry_path = Path(registry_path)
54
+ self.packages_path = self.registry_path / 'packages'
55
+ self.index_path = self.registry_path / 'registry.json'
56
+
57
+ # Ensure directories exist
58
+ self._init_registry()
59
+
60
+ def _init_registry(self) -> None:
61
+ """Initialize registry directories and files."""
62
+ self.registry_path.mkdir(parents=True, exist_ok=True)
63
+ self.packages_path.mkdir(exist_ok=True)
64
+
65
+ if not self.index_path.exists():
66
+ self._save_index({})
67
+
68
+ def _load_index(self) -> Dict[str, Any]:
69
+ """Load registry index."""
70
+ try:
71
+ with open(self.index_path, 'r', encoding='utf-8') as f:
72
+ return json.load(f)
73
+ except (json.JSONDecodeError, FileNotFoundError):
74
+ return {}
75
+
76
+ def _save_index(self, index: Dict[str, Any]) -> None:
77
+ """Save registry index."""
78
+ with open(self.index_path, 'w', encoding='utf-8') as f:
79
+ json.dump(index, f, indent=2)
80
+
81
+ def install_package(
82
+ self,
83
+ source_path: Path,
84
+ manifest: Optional[PackageManifest] = None
85
+ ) -> PackageManifest:
86
+ """
87
+ Install a package from source directory.
88
+
89
+ Args:
90
+ source_path: Path to package directory (with quantum.yaml)
91
+ manifest: Pre-loaded manifest (optional)
92
+
93
+ Returns:
94
+ Installed package manifest
95
+ """
96
+ source_path = Path(source_path)
97
+
98
+ # Load manifest if not provided
99
+ if manifest is None:
100
+ manifest_path = source_path / 'quantum.yaml'
101
+ if not manifest_path.exists():
102
+ raise RegistryError(f"No quantum.yaml found in {source_path}")
103
+ manifest = PackageManifest.load(manifest_path)
104
+
105
+ package_name = manifest.name
106
+ version = manifest.version
107
+
108
+ # Create package version directory
109
+ version_dir = self.packages_path / package_name / version
110
+ if version_dir.exists():
111
+ # Remove existing version
112
+ shutil.rmtree(version_dir)
113
+
114
+ version_dir.mkdir(parents=True)
115
+
116
+ # Copy package contents
117
+ for item in source_path.iterdir():
118
+ if item.name.startswith('.'):
119
+ continue # Skip hidden files
120
+
121
+ dest = version_dir / item.name
122
+ if item.is_dir():
123
+ shutil.copytree(item, dest)
124
+ else:
125
+ shutil.copy2(item, dest)
126
+
127
+ # Update registry index
128
+ index = self._load_index()
129
+ if package_name not in index:
130
+ index[package_name] = {
131
+ 'versions': {},
132
+ 'latest': None,
133
+ 'installed_at': None,
134
+ }
135
+
136
+ index[package_name]['versions'][version] = {
137
+ 'path': str(version_dir),
138
+ 'installed_at': datetime.now().isoformat(),
139
+ 'description': manifest.description,
140
+ 'author': manifest.author,
141
+ 'keywords': manifest.keywords,
142
+ }
143
+ index[package_name]['latest'] = version
144
+ index[package_name]['installed_at'] = datetime.now().isoformat()
145
+
146
+ self._save_index(index)
147
+
148
+ # Update manifest path
149
+ manifest._path = version_dir
150
+
151
+ return manifest
152
+
153
+ def remove_package(
154
+ self,
155
+ package_name: str,
156
+ version: Optional[str] = None
157
+ ) -> bool:
158
+ """
159
+ Remove a package or specific version.
160
+
161
+ Args:
162
+ package_name: Name of package to remove
163
+ version: Specific version to remove (None = all versions)
164
+
165
+ Returns:
166
+ True if removed, False if not found
167
+ """
168
+ index = self._load_index()
169
+
170
+ if package_name not in index:
171
+ return False
172
+
173
+ package_dir = self.packages_path / package_name
174
+
175
+ if version:
176
+ # Remove specific version
177
+ version_dir = package_dir / version
178
+ if version_dir.exists():
179
+ shutil.rmtree(version_dir)
180
+
181
+ if version in index[package_name]['versions']:
182
+ del index[package_name]['versions'][version]
183
+
184
+ # Update latest version
185
+ remaining_versions = list(index[package_name]['versions'].keys())
186
+ if remaining_versions:
187
+ # Sort by version and get highest
188
+ remaining_versions.sort(key=self._version_key, reverse=True)
189
+ index[package_name]['latest'] = remaining_versions[0]
190
+ else:
191
+ # No versions left, remove package entirely
192
+ del index[package_name]
193
+ if package_dir.exists():
194
+ shutil.rmtree(package_dir)
195
+ else:
196
+ # Remove all versions
197
+ if package_dir.exists():
198
+ shutil.rmtree(package_dir)
199
+ del index[package_name]
200
+
201
+ self._save_index(index)
202
+ return True
203
+
204
+ def get_package(
205
+ self,
206
+ package_name: str,
207
+ version: Optional[str] = None
208
+ ) -> Optional[PackageManifest]:
209
+ """
210
+ Get installed package manifest.
211
+
212
+ Args:
213
+ package_name: Package name
214
+ version: Specific version (None = latest)
215
+
216
+ Returns:
217
+ Package manifest or None if not found
218
+ """
219
+ index = self._load_index()
220
+
221
+ if package_name not in index:
222
+ return None
223
+
224
+ pkg_info = index[package_name]
225
+
226
+ if version is None:
227
+ version = pkg_info.get('latest')
228
+
229
+ if not version or version not in pkg_info['versions']:
230
+ return None
231
+
232
+ version_info = pkg_info['versions'][version]
233
+ version_dir = Path(version_info['path'])
234
+
235
+ manifest_path = version_dir / 'quantum.yaml'
236
+ if not manifest_path.exists():
237
+ return None
238
+
239
+ try:
240
+ return PackageManifest.load(manifest_path)
241
+ except ManifestError:
242
+ return None
243
+
244
+ def get_package_path(
245
+ self,
246
+ package_name: str,
247
+ version: Optional[str] = None
248
+ ) -> Optional[Path]:
249
+ """
250
+ Get path to installed package directory.
251
+
252
+ Args:
253
+ package_name: Package name
254
+ version: Specific version (None = latest)
255
+
256
+ Returns:
257
+ Path to package directory or None
258
+ """
259
+ index = self._load_index()
260
+
261
+ if package_name not in index:
262
+ return None
263
+
264
+ pkg_info = index[package_name]
265
+
266
+ if version is None:
267
+ version = pkg_info.get('latest')
268
+
269
+ if not version or version not in pkg_info['versions']:
270
+ return None
271
+
272
+ version_info = pkg_info['versions'][version]
273
+ return Path(version_info['path'])
274
+
275
+ def list_packages(self) -> List[Dict[str, Any]]:
276
+ """
277
+ List all installed packages.
278
+
279
+ Returns:
280
+ List of package info dictionaries
281
+ """
282
+ index = self._load_index()
283
+ packages = []
284
+
285
+ for name, info in index.items():
286
+ pkg = {
287
+ 'name': name,
288
+ 'latest': info.get('latest'),
289
+ 'versions': list(info.get('versions', {}).keys()),
290
+ 'installed_at': info.get('installed_at'),
291
+ }
292
+
293
+ # Get description from latest version
294
+ if info.get('latest') and info['latest'] in info.get('versions', {}):
295
+ version_info = info['versions'][info['latest']]
296
+ pkg['description'] = version_info.get('description', '')
297
+ pkg['author'] = version_info.get('author', '')
298
+ pkg['keywords'] = version_info.get('keywords', [])
299
+
300
+ packages.append(pkg)
301
+
302
+ return packages
303
+
304
+ def search_packages(self, query: str) -> List[Dict[str, Any]]:
305
+ """
306
+ Search installed packages by name or keywords.
307
+
308
+ Args:
309
+ query: Search query
310
+
311
+ Returns:
312
+ List of matching package info dictionaries
313
+ """
314
+ query = query.lower()
315
+ packages = self.list_packages()
316
+ results = []
317
+
318
+ for pkg in packages:
319
+ # Match by name
320
+ if query in pkg['name'].lower():
321
+ results.append(pkg)
322
+ continue
323
+
324
+ # Match by keywords
325
+ keywords = pkg.get('keywords', [])
326
+ if any(query in kw.lower() for kw in keywords):
327
+ results.append(pkg)
328
+ continue
329
+
330
+ # Match by description
331
+ description = pkg.get('description', '')
332
+ if query in description.lower():
333
+ results.append(pkg)
334
+
335
+ return results
336
+
337
+ def has_package(self, package_name: str, version: Optional[str] = None) -> bool:
338
+ """Check if package is installed."""
339
+ index = self._load_index()
340
+
341
+ if package_name not in index:
342
+ return False
343
+
344
+ if version:
345
+ return version in index[package_name].get('versions', {})
346
+
347
+ return True
348
+
349
+ def get_all_versions(self, package_name: str) -> List[str]:
350
+ """Get all installed versions of a package."""
351
+ index = self._load_index()
352
+
353
+ if package_name not in index:
354
+ return []
355
+
356
+ versions = list(index[package_name].get('versions', {}).keys())
357
+ versions.sort(key=self._version_key, reverse=True)
358
+ return versions
359
+
360
+ @staticmethod
361
+ def _version_key(version: str) -> tuple:
362
+ """Convert version string to sortable tuple."""
363
+ # Remove prerelease suffix for comparison
364
+ base_version = version.split('-')[0]
365
+ try:
366
+ parts = [int(p) for p in base_version.split('.')]
367
+ # Pad to 3 parts
368
+ while len(parts) < 3:
369
+ parts.append(0)
370
+ return tuple(parts)
371
+ except ValueError:
372
+ return (0, 0, 0)
373
+
374
+
375
+ class RemoteRegistry:
376
+ """
377
+ Remote package registry client.
378
+
379
+ TODO: Implement when remote registry server is available.
380
+ For now, packages are shared via local paths or git URLs.
381
+ """
382
+
383
+ def __init__(self, registry_url: str = "https://packages.quantum.dev"):
384
+ self.registry_url = registry_url
385
+
386
+ def search(self, query: str) -> List[Dict[str, Any]]:
387
+ """Search remote registry."""
388
+ # TODO: Implement HTTP search
389
+ raise NotImplementedError("Remote registry not yet implemented")
390
+
391
+ def download(self, package_name: str, version: Optional[str] = None) -> Path:
392
+ """Download package from remote registry."""
393
+ # TODO: Implement HTTP download
394
+ raise NotImplementedError("Remote registry not yet implemented")
395
+
396
+ def publish(self, manifest: PackageManifest, archive_path: Path) -> bool:
397
+ """Publish package to remote registry."""
398
+ # TODO: Implement HTTP publish
399
+ raise NotImplementedError("Remote registry not yet implemented")