tzero-mcp 10.7.0 → 10.7.1

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 (96) hide show
  1. package/bin/tzero-mcp.js +9 -16
  2. package/bin/tzero.js +9 -16
  3. package/index.js +7 -2
  4. package/package.json +2 -1
  5. package/src/addmcp.py +1194 -0
  6. package/src/main.py +60 -0
  7. package/src/siber_akademi_icon.py +77 -0
  8. package/src/tzero/jarvis/semantic_compressor.py +373 -0
  9. package/src/tzero.py +58 -0
  10. package/src/tzero_benchmark.py +475 -0
  11. package/src/tzero_bridge.py +362 -0
  12. package/src/tzero_ci.py +153 -0
  13. package/src/tzero_commit.py +192 -0
  14. package/src/tzero_cost.py +163 -0
  15. package/src/tzero_dashboard.py +1448 -0
  16. package/src/tzero_deps.py +287 -0
  17. package/src/tzero_drift.py +208 -0
  18. package/src/tzero_explain.py +240 -0
  19. package/src/tzero_features.py +3022 -0
  20. package/src/tzero_fix.py +228 -0
  21. package/src/tzero_fixer/__init__.py +63 -0
  22. package/src/tzero_fixer/amalgamation.py +334 -0
  23. package/src/tzero_fixer/ast_syntax_healer.py +464 -0
  24. package/src/tzero_fixer/ast_type_modernizer.py +288 -0
  25. package/src/tzero_fixer/async_io_modernizer.py +127 -0
  26. package/src/tzero_fixer/automated_regression_suite.py +600 -0
  27. package/src/tzero_fixer/benchmarks_and_diagnostics.py +174 -0
  28. package/src/tzero_fixer/ci_cd_self_healing_gate.py +246 -0
  29. package/src/tzero_fixer/code_duplicity_and_refactorer.py +151 -0
  30. package/src/tzero_fixer/code_smells_healer.py +260 -0
  31. package/src/tzero_fixer/cwe_remediator.py +171 -0
  32. package/src/tzero_fixer/dead_code_eliminator.py +150 -0
  33. package/src/tzero_fixer/dependency_vulnerability_auditor.py +309 -0
  34. package/src/tzero_fixer/git_advanced_surgeon.py +280 -0
  35. package/src/tzero_fixer/hardware_and_disk_doctor.py +325 -0
  36. package/src/tzero_fixer/import_graph_healer.py +412 -0
  37. package/src/tzero_fixer/interactive_tui.py +91 -0
  38. package/src/tzero_fixer/knowledge_base.py +295 -0
  39. package/src/tzero_fixer/knowledge_base_extended.py +940 -0
  40. package/src/tzero_fixer/linters_and_static_analyzer.py +307 -0
  41. package/src/tzero_fixer/mcp_server.py +447 -0
  42. package/src/tzero_fixer/models.py +385 -0
  43. package/src/tzero_fixer/orchestrator.py +375 -0
  44. package/src/tzero_fixer/os_doctor.py +502 -0
  45. package/src/tzero_fixer/packaging_abi_surgeon.py +323 -0
  46. package/src/tzero_fixer/pc_fixer_doctor.py +599 -0
  47. package/src/tzero_fixer/performance_and_memory_profiler.py +274 -0
  48. package/src/tzero_fixer/polyglot_ast_parsers.py +313 -0
  49. package/src/tzero_fixer/polyglot_build_healer.py +364 -0
  50. package/src/tzero_fixer/polyglot_config_healer.py +318 -0
  51. package/src/tzero_fixer/polyglot_doctor.py +372 -0
  52. package/src/tzero_fixer/polyglot_linters.py +619 -0
  53. package/src/tzero_fixer/polyglot_schema_validator.py +305 -0
  54. package/src/tzero_fixer/security_cwe_database.py +444 -0
  55. package/src/tzero_fixer/security_deep_rules.py +114 -0
  56. package/src/tzero_fixer/security_rules_catalog.py +110 -0
  57. package/src/tzero_fixer/security_zero_leak.py +326 -0
  58. package/src/tzero_fixer/smart_patch_recommender.py +223 -0
  59. package/src/tzero_fixer/synthetic_workspace_generator.py +220 -0
  60. package/src/tzero_fixer/system_diagnostics_extended.py +493 -0
  61. package/src/tzero_fixer/system_repair_recipes.py +447 -0
  62. package/src/tzero_fixer/venv_doctor.py +309 -0
  63. package/src/tzero_gateway.py +885 -0
  64. package/src/tzero_guard.py +243 -0
  65. package/src/tzero_infra.py +274 -0
  66. package/src/tzero_jarvis/__init__.py +124 -0
  67. package/src/tzero_jarvis/causal_graph.py +310 -0
  68. package/src/tzero_jarvis/graph_visualizer.py +395 -0
  69. package/src/tzero_jarvis/hybrid_search.py +214 -0
  70. package/src/tzero_jarvis/latent_press.py +137 -0
  71. package/src/tzero_jarvis/memory_consolidation.py +212 -0
  72. package/src/tzero_jarvis/minhash_lsh.py +184 -0
  73. package/src/tzero_jarvis/orchestrator.py +335 -0
  74. package/src/tzero_jarvis/self_healing.py +308 -0
  75. package/src/tzero_jarvis/semantic_compressor.py +887 -0
  76. package/src/tzero_jarvis/swarm.py +261 -0
  77. package/src/tzero_jarvis/swarm_bft.py +144 -0
  78. package/src/tzero_jarvis/workspace_orchestrator.py +1167 -0
  79. package/src/tzero_jarvis/zero_key_router.py +173 -0
  80. package/src/tzero_mcp.py +4858 -0
  81. package/src/tzero_neural_cortex.py +1425 -0
  82. package/src/tzero_packer.py +370 -0
  83. package/src/tzero_patch.py +624 -0
  84. package/src/tzero_pc_fixer.py +12657 -0
  85. package/src/tzero_pipe.py +95 -0
  86. package/src/tzero_polyglot.py +422 -0
  87. package/src/tzero_reachability.py +272 -0
  88. package/src/tzero_replay.py +141 -0
  89. package/src/tzero_security.py +570 -0
  90. package/src/tzero_snapshot.py +258 -0
  91. package/src/tzero_stubs.py +313 -0
  92. package/src/tzero_superdesign.py +774 -0
  93. package/src/tzero_sync.py +241 -0
  94. package/src/tzero_task_benchmark.py +363 -0
  95. package/src/tzero_tui.py +244 -0
  96. package/src/tzero_v3.py +9435 -0
@@ -0,0 +1,774 @@
1
+ # -*- coding: utf-8 -*-
2
+ """Siber Akademi T-Zero — Superdesign MCP Orchestrator Module.
3
+
4
+ Brings the open-source Superdesign AI design orchestrator capabilities natively to
5
+ MCP clients (Claude Code, Cursor, Antigravity IDE, Windsurf).
6
+
7
+ Operates as a design orchestrator providing structured specifications, design system
8
+ extraction, iterative refinement, and interactive HTML galleries without requiring
9
+ external API keys or cloud dependencies.
10
+
11
+ Developer: Toprak Ahmet Aydoğmuş (Siber Akademi)
12
+ License: MIT
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ import html
18
+ import json
19
+ import os
20
+ import re
21
+ import time
22
+ from typing import Any, Dict, List, Optional, Tuple
23
+
24
+ VALID_DESIGN_TYPES = {"ui", "wireframe", "component", "logo", "icon"}
25
+ VALID_FRAMEWORKS = {"html", "react", "vue"}
26
+
27
+ DEFAULT_DESIGN_SYSTEM = {
28
+ "$schema": "https://superdesign.dev/schema/design-system.json",
29
+ "name": "T-Zero Modern Design System",
30
+ "version": "1.0.0",
31
+ "theme": "dark",
32
+ "colors": {
33
+ "background": {
34
+ "canvas": "#090d16",
35
+ "surface": "#0f172a",
36
+ "surface_hover": "#1e293b",
37
+ "surface_active": "#334155"
38
+ },
39
+ "border": {
40
+ "subtle": "#1e293b",
41
+ "strong": "#334155",
42
+ "focus": "#6366f1"
43
+ },
44
+ "text": {
45
+ "primary": "#f8fafc",
46
+ "secondary": "#94a3b8",
47
+ "tertiary": "#64748b",
48
+ "inverse": "#090d16"
49
+ },
50
+ "accent": {
51
+ "primary": "#38bdf8",
52
+ "primary_hover": "#0ea5e9",
53
+ "secondary": "#818cf8",
54
+ "success": "#34d399",
55
+ "warning": "#fbbf24",
56
+ "danger": "#f87171"
57
+ }
58
+ },
59
+ "typography": {
60
+ "fonts": {
61
+ "ui": "Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif",
62
+ "mono": "'Fira Code', 'Geist Mono', Consolas, Monaco, monospace",
63
+ "heading": "Inter, -apple-system, BlinkMacSystemFont, sans-serif"
64
+ },
65
+ "scale": {
66
+ "xs": "0.75rem",
67
+ "sm": "0.875rem",
68
+ "base": "1rem",
69
+ "lg": "1.125rem",
70
+ "xl": "1.25rem",
71
+ "2xl": "1.5rem",
72
+ "3xl": "1.875rem",
73
+ "4xl": "2.25rem"
74
+ },
75
+ "weights": {
76
+ "normal": "400",
77
+ "medium": "500",
78
+ "semibold": "600",
79
+ "bold": "700"
80
+ }
81
+ },
82
+ "spacing": {
83
+ "1": "0.25rem",
84
+ "2": "0.5rem",
85
+ "3": "0.75rem",
86
+ "4": "1rem",
87
+ "6": "1.5rem",
88
+ "8": "2rem",
89
+ "12": "3rem",
90
+ "16": "4rem"
91
+ },
92
+ "radii": {
93
+ "sm": "0.25rem",
94
+ "md": "0.5rem",
95
+ "lg": "0.75rem",
96
+ "xl": "1rem",
97
+ "full": "9999px"
98
+ },
99
+ "shadows": {
100
+ "sm": "0 1px 2px 0 rgba(0, 0, 0, 0.4)",
101
+ "md": "0 4px 6px -1px rgba(0, 0, 0, 0.5), 0 2px 4px -2px rgba(0, 0, 0, 0.5)",
102
+ "lg": "0 10px 15px -3px rgba(0, 0, 0, 0.6), 0 4px 6px -4px rgba(0, 0, 0, 0.6)"
103
+ }
104
+ }
105
+
106
+
107
+ def _slugify(text: str) -> str:
108
+ """Converts a descriptive string to a filesystem-friendly slug."""
109
+ text = text.lower().strip()
110
+ text = re.sub(r"[^\w\s-]", "", text)
111
+ text = re.sub(r"[\s_-]+", "_", text)
112
+ return text[:36].strip("_") or "design"
113
+
114
+
115
+ def _ensure_superdesign_dirs(workspace_path: str = ".") -> Tuple[str, str]:
116
+ """Ensures that superdesign/design_iterations and superdesign/design_system exist."""
117
+ base_dir = os.path.join(workspace_path, "superdesign")
118
+ iterations_dir = os.path.join(base_dir, "design_iterations")
119
+ systems_dir = os.path.join(base_dir, "design_system")
120
+ os.makedirs(iterations_dir, exist_ok=True)
121
+ os.makedirs(systems_dir, exist_ok=True)
122
+ return iterations_dir, systems_dir
123
+
124
+
125
+ def superdesign_generate(
126
+ prompt: str,
127
+ design_type: str = "ui",
128
+ variations: int = 3,
129
+ framework: str = "html",
130
+ workspace_path: str = ".",
131
+ ) -> Dict[str, Any]:
132
+ """Generates structured specifications and guidelines for the LLM to create designs."""
133
+ d_type = (design_type or "ui").lower().strip()
134
+ if d_type not in VALID_DESIGN_TYPES:
135
+ return {
136
+ "success": False,
137
+ "error": f"Invalid design_type '{design_type}'. Must be one of: {sorted(list(VALID_DESIGN_TYPES))}",
138
+ }
139
+
140
+ fw = (framework or "html").lower().strip()
141
+ if fw not in VALID_FRAMEWORKS:
142
+ fw = "html"
143
+
144
+ variations = max(1, min(int(variations or 3), 5))
145
+ iterations_dir, _ = _ensure_superdesign_dirs(workspace_path)
146
+ slug = _slugify(prompt)
147
+
148
+ ext_map = {
149
+ "ui": ".html",
150
+ "wireframe": ".html",
151
+ "component": ".html" if fw == "html" else (".tsx" if fw == "react" else ".vue"),
152
+ "logo": ".svg",
153
+ "icon": ".svg",
154
+ }
155
+ ext = ext_map.get(d_type, ".html")
156
+
157
+ files_to_create = []
158
+ for i in range(1, variations + 1):
159
+ filename = f"{d_type}_{slug}_v{i}{ext}"
160
+ rel_path = os.path.join("superdesign", "design_iterations", filename).replace("\\", "/")
161
+ files_to_create.append({
162
+ "variation": i,
163
+ "filename": filename,
164
+ "file_path": rel_path,
165
+ "full_path": os.path.abspath(os.path.join(iterations_dir, filename)),
166
+ })
167
+
168
+ guidelines = [
169
+ "1. Avoid generic AI aesthetics (neon glow spam, wall-of-emojis, tacky cyberpunk badges).",
170
+ "2. Use curated, accessible color palettes: slate/zinc neutral surfaces (#090d16, #0f172a, #1e293b).",
171
+ "3. Typography: Prioritize modern clean typefaces (Inter, Geist, Fira Code monospace).",
172
+ "4. Layout: Implement responsive mobile-first flexbox/grid with clear visual hierarchy.",
173
+ "5. Self-Contained: Include all CSS and necessary SVG icons inline so each file opens standalone in any browser.",
174
+ ]
175
+ if d_type == "wireframe":
176
+ guidelines.append("6. Wireframe Mode: Strictly monochrome (black, white, greys) with wire-box indicators for imagery.")
177
+ elif d_type in {"logo", "icon"}:
178
+ guidelines.append("6. Vector SVG: Use viewBox='0 0 24 24' (or 100 100), clean paths, stroke-width=2, and semantic layers.")
179
+
180
+ specifications = {
181
+ "design_orchestrator": "Superdesign MCP v1.0 (T-Zero Edition)",
182
+ "prompt": prompt,
183
+ "design_type": d_type,
184
+ "framework": fw,
185
+ "variations_requested": variations,
186
+ "design_system_reference": "superdesign/design_system/tzero_design_system.json",
187
+ "core_guidelines": guidelines,
188
+ "instructions_for_claude": (
189
+ f"Generate {variations} complete, production-ready, beautiful variations of the requested {d_type}. "
190
+ f"Write the output code directly into the target files listed under 'files_to_create'. "
191
+ "Ensure the visual presentation feels high-end, crisp, and completely free of AI slop."
192
+ ),
193
+ }
194
+
195
+ return {
196
+ "success": True,
197
+ "design_type": d_type,
198
+ "framework": fw,
199
+ "variations": variations,
200
+ "files_to_create": files_to_create,
201
+ "specifications": specifications,
202
+ }
203
+
204
+
205
+ def superdesign_iterate(
206
+ design_file: str,
207
+ feedback: str,
208
+ variations: int = 1,
209
+ workspace_path: str = ".",
210
+ ) -> Dict[str, Any]:
211
+ """Generates structured iteration instructions to refine an existing design file."""
212
+ if not design_file or not os.path.exists(design_file):
213
+ return {
214
+ "success": False,
215
+ "error": f"Design file '{design_file}' was not found. Please provide an existing design file path.",
216
+ }
217
+
218
+ variations = max(1, min(int(variations or 1), 5))
219
+ iterations_dir, _ = _ensure_superdesign_dirs(workspace_path)
220
+
221
+ base_name = os.path.basename(design_file)
222
+ name_no_ext, ext = os.path.splitext(base_name)
223
+ # Detect version tag or append _iter
224
+ v_match = re.search(r"_v(\d+)$", name_no_ext)
225
+ current_ver = int(v_match.group(1)) if v_match else 1
226
+
227
+ target_files = []
228
+ for i in range(1, variations + 1):
229
+ next_ver = current_ver + i
230
+ if v_match:
231
+ new_name = re.sub(r"_v\d+$", f"_v{next_ver}", name_no_ext) + ext
232
+ else:
233
+ new_name = f"{name_no_ext}_v{next_ver}{ext}"
234
+ rel_path = os.path.join("superdesign", "design_iterations", new_name).replace("\\", "/")
235
+ target_files.append({
236
+ "variation": i,
237
+ "target_path": rel_path,
238
+ "full_path": os.path.abspath(os.path.join(iterations_dir, new_name)),
239
+ })
240
+
241
+ try:
242
+ with open(design_file, "r", encoding="utf-8", errors="ignore") as f:
243
+ original_code = f.read()
244
+ except Exception as e:
245
+ original_code = f"<!-- Error reading original file: {e} -->"
246
+
247
+ return {
248
+ "success": True,
249
+ "design_file": design_file,
250
+ "feedback": feedback,
251
+ "variations": variations,
252
+ "target_files": target_files,
253
+ "original_code_snippet": original_code[:1200] + ("..." if len(original_code) > 1200 else ""),
254
+ "iteration_instructions": {
255
+ "goal": "Refine the original design incorporating the user feedback while preserving core layout integrity.",
256
+ "feedback_to_apply": feedback,
257
+ "superdesign_principles": [
258
+ "Preserve component consistency and spacing rhythm (4px/8px grid).",
259
+ "Ensure contrast ratios meet WCAG AA standards.",
260
+ "Polish micro-interactions, hover states, and smooth CSS transitions.",
261
+ "Avoid introducing visual clutter or artificial AI tropes.",
262
+ ],
263
+ "execution_note": "Write the improved code into the target files specified in 'target_files'.",
264
+ },
265
+ }
266
+
267
+
268
+ def superdesign_extract_system(
269
+ input_path_or_description: str,
270
+ system_name: str = "custom",
271
+ workspace_path: str = ".",
272
+ ) -> Dict[str, Any]:
273
+ """Extracts or initializes a structured JSON design system with modern tokens."""
274
+ _, systems_dir = _ensure_superdesign_dirs(workspace_path)
275
+ clean_name = _slugify(system_name) or "design_system"
276
+ system_file = os.path.join(systems_dir, f"{clean_name}.json")
277
+
278
+ tokens = json.loads(json.dumps(DEFAULT_DESIGN_SYSTEM))
279
+ tokens["name"] = f"Superdesign System: {system_name.replace('_', ' ').title()}"
280
+ tokens["description"] = f"Extracted design system for: {input_path_or_description}"
281
+ tokens["extracted_at"] = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())
282
+
283
+ with open(system_file, "w", encoding="utf-8") as f:
284
+ json.dump(tokens, f, indent=2, ensure_ascii=False)
285
+
286
+ return {
287
+ "success": True,
288
+ "system_name": clean_name,
289
+ "file_path": system_file.replace("\\", "/"),
290
+ "design_system": tokens,
291
+ "usage_instructions": (
292
+ f"Design system tokens saved to '{system_file}'. "
293
+ "Reference these CSS custom properties in your HTML, React, and Vue components."
294
+ ),
295
+ }
296
+
297
+
298
+ def superdesign_list(workspace_path: str = ".") -> Dict[str, Any]:
299
+ """Enumerates all Superdesign creations and extracted design systems."""
300
+ iterations_dir, systems_dir = _ensure_superdesign_dirs(workspace_path)
301
+
302
+ iterations = []
303
+ if os.path.isdir(iterations_dir):
304
+ for fname in sorted(os.listdir(iterations_dir)):
305
+ full_p = os.path.join(iterations_dir, fname)
306
+ if os.path.isfile(full_p):
307
+ ext = os.path.splitext(fname)[1].lower()
308
+ dtype = "ui"
309
+ if fname.startswith("wireframe_"):
310
+ dtype = "wireframe"
311
+ elif fname.startswith("component_"):
312
+ dtype = "component"
313
+ elif fname.startswith("logo_"):
314
+ dtype = "logo"
315
+ elif fname.startswith("icon_"):
316
+ dtype = "icon"
317
+
318
+ iterations.append({
319
+ "filename": fname,
320
+ "design_type": dtype,
321
+ "extension": ext,
322
+ "relative_path": os.path.join("superdesign", "design_iterations", fname).replace("\\", "/"),
323
+ "size_bytes": os.path.getsize(full_p),
324
+ "modified_time": time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(os.path.getmtime(full_p))),
325
+ })
326
+
327
+ systems = []
328
+ if os.path.isdir(systems_dir):
329
+ for fname in sorted(os.listdir(systems_dir)):
330
+ full_p = os.path.join(systems_dir, fname)
331
+ if os.path.isfile(full_p) and fname.endswith(".json"):
332
+ systems.append({
333
+ "filename": fname,
334
+ "relative_path": os.path.join("superdesign", "design_system", fname).replace("\\", "/"),
335
+ "size_bytes": os.path.getsize(full_p),
336
+ })
337
+
338
+ return {
339
+ "success": True,
340
+ "total_iterations": len(iterations),
341
+ "total_design_systems": len(systems),
342
+ "iterations": iterations,
343
+ "design_systems": systems,
344
+ }
345
+
346
+
347
+ def superdesign_gallery(workspace_path: str = ".") -> Dict[str, Any]:
348
+ """Builds a responsive, interactive HTML gallery previewing all designs in superdesign/."""
349
+ iterations_dir, _ = _ensure_superdesign_dirs(workspace_path)
350
+ gallery_file = os.path.join(workspace_path, "superdesign", "gallery.html")
351
+
352
+ list_data = superdesign_list(workspace_path=workspace_path)
353
+ items = list_data.get("iterations", [])
354
+
355
+ cards_html = []
356
+ for idx, item in enumerate(items):
357
+ fn = html.escape(item["filename"])
358
+ dtype = html.escape(item["design_type"].upper())
359
+ mod = html.escape(item["modified_time"])
360
+ rel_p = html.escape(f"design_iterations/{item['filename']}")
361
+ ext = item["extension"]
362
+
363
+ if ext == ".svg":
364
+ # Read inline SVG for instant preview
365
+ svg_path = os.path.join(iterations_dir, item["filename"])
366
+ try:
367
+ with open(svg_path, "r", encoding="utf-8", errors="ignore") as sf:
368
+ svg_raw = sf.read()
369
+ # Strip xml header if present
370
+ svg_raw = re.sub(r"<\?xml.*?\?>", "", svg_raw).strip()
371
+ except Exception:
372
+ svg_raw = "<div style='color:#ef4444;'>Failed to load SVG</div>"
373
+ preview_content = f"<div class='svg-frame'>{svg_raw}</div>"
374
+ else:
375
+ preview_content = f"<iframe src='{rel_p}' loading='lazy' class='preview-iframe' title='{fn}'></iframe>"
376
+
377
+ card = f"""
378
+ <div class="gallery-card" data-type="{item['design_type']}">
379
+ <div class="card-preview">
380
+ {preview_content}
381
+ <div class="preview-overlay">
382
+ <button class="btn-action" onclick="openModal('{rel_p}', '{fn}')">Preview Full</button>
383
+ </div>
384
+ </div>
385
+ <div class="card-meta">
386
+ <div class="card-header">
387
+ <span class="badge badge-{item['design_type']}">{dtype}</span>
388
+ <span class="card-date">{mod}</span>
389
+ </div>
390
+ <div class="card-title" title="{fn}">{fn}</div>
391
+ <div class="card-footer">
392
+ <button class="btn-copy" onclick="copyPath('{item['relative_path']}', this)">Copy Path</button>
393
+ <a href="{rel_p}" target="_blank" class="btn-link">Open &nearr;</a>
394
+ </div>
395
+ </div>
396
+ </div>
397
+ """
398
+ cards_html.append(card)
399
+
400
+ cards_joined = "\n".join(cards_html) if cards_html else (
401
+ "<div class='empty-state'>"
402
+ "<h3>No Designs Yet</h3>"
403
+ "<p>Run <code>superdesign_generate</code> to create your first clean UI, wireframe, or component.</p>"
404
+ "</div>"
405
+ )
406
+
407
+ gallery_html_content = f"""<!DOCTYPE html>
408
+ <html lang="en">
409
+ <head>
410
+ <meta charset="UTF-8">
411
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
412
+ <title>Superdesign Gallery — T-Zero Design Canvas</title>
413
+ <link rel="preconnect" href="https://fonts.googleapis.com">
414
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
415
+ <link href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;500&family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
416
+ <style>
417
+ :root {{
418
+ --bg: #090d16;
419
+ --surface: #0f172a;
420
+ --surface-elevated: #1e293b;
421
+ --border: #1e293b;
422
+ --border-focus: #38bdf8;
423
+ --text: #f8fafc;
424
+ --text-muted: #94a3b8;
425
+ --accent: #38bdf8;
426
+ --accent-indigo: #818cf8;
427
+ --radius: 10px;
428
+ }}
429
+ * {{ box-sizing: border-box; margin: 0; padding: 0; }}
430
+ body {{
431
+ background: var(--bg);
432
+ color: var(--text);
433
+ font-family: 'Inter', -apple-system, sans-serif;
434
+ min-height: 100vh;
435
+ display: flex;
436
+ flex-direction: column;
437
+ }}
438
+ header {{
439
+ padding: 20px 36px;
440
+ border-bottom: 1px solid var(--border);
441
+ background: rgba(15, 23, 42, 0.85);
442
+ backdrop-filter: blur(16px);
443
+ position: sticky;
444
+ top: 0;
445
+ z-index: 50;
446
+ display: flex;
447
+ justify-content: space-between;
448
+ align-items: center;
449
+ }}
450
+ .brand {{
451
+ display: flex;
452
+ align-items: center;
453
+ gap: 12px;
454
+ }}
455
+ .brand-logo {{
456
+ width: 32px;
457
+ height: 32px;
458
+ background: linear-gradient(135deg, var(--accent), var(--accent-indigo));
459
+ border-radius: 8px;
460
+ display: flex;
461
+ align-items: center;
462
+ justify-content: center;
463
+ font-weight: 700;
464
+ color: #090d16;
465
+ }}
466
+ .brand-title {{
467
+ font-size: 18px;
468
+ font-weight: 700;
469
+ letter-spacing: -0.02em;
470
+ }}
471
+ .filter-bar {{
472
+ display: flex;
473
+ gap: 8px;
474
+ }}
475
+ .filter-btn {{
476
+ background: var(--surface);
477
+ border: 1px solid var(--border);
478
+ color: var(--text-muted);
479
+ padding: 6px 14px;
480
+ border-radius: 6px;
481
+ font-size: 13px;
482
+ font-weight: 500;
483
+ cursor: pointer;
484
+ transition: all 0.15s ease;
485
+ }}
486
+ .filter-btn:hover, .filter-btn.active {{
487
+ background: var(--surface-elevated);
488
+ color: var(--text);
489
+ border-color: var(--accent);
490
+ }}
491
+ main {{
492
+ flex: 1;
493
+ padding: 36px;
494
+ max-width: 1440px;
495
+ margin: 0 auto;
496
+ width: 100%;
497
+ }}
498
+ .gallery-grid {{
499
+ display: grid;
500
+ grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));
501
+ gap: 24px;
502
+ }}
503
+ .gallery-card {{
504
+ background: var(--surface);
505
+ border: 1px solid var(--border);
506
+ border-radius: var(--radius);
507
+ overflow: hidden;
508
+ display: flex;
509
+ flex-direction: column;
510
+ transition: transform 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease;
511
+ }}
512
+ .gallery-card:hover {{
513
+ transform: translateY(-3px);
514
+ border-color: #334155;
515
+ box-shadow: 0 12px 24px -10px rgba(0, 0, 0, 0.6);
516
+ }}
517
+ .card-preview {{
518
+ height: 220px;
519
+ background: #060910;
520
+ position: relative;
521
+ overflow: hidden;
522
+ display: flex;
523
+ align-items: center;
524
+ justify-content: center;
525
+ border-bottom: 1px solid var(--border);
526
+ }}
527
+ .preview-iframe {{
528
+ width: 200%;
529
+ height: 200%;
530
+ transform: scale(0.5);
531
+ transform-origin: top left;
532
+ border: none;
533
+ pointer-events: none;
534
+ }}
535
+ .svg-frame {{
536
+ width: 100%;
537
+ height: 100%;
538
+ display: flex;
539
+ align-items: center;
540
+ justify-content: center;
541
+ padding: 24px;
542
+ }}
543
+ .svg-frame svg {{
544
+ max-width: 100%;
545
+ max-height: 100%;
546
+ }}
547
+ .preview-overlay {{
548
+ position: absolute;
549
+ inset: 0;
550
+ background: rgba(9, 13, 22, 0.7);
551
+ backdrop-filter: blur(4px);
552
+ display: flex;
553
+ align-items: center;
554
+ justify-content: center;
555
+ opacity: 0;
556
+ transition: opacity 0.2s ease;
557
+ }}
558
+ .card-preview:hover .preview-overlay {{
559
+ opacity: 1;
560
+ }}
561
+ .btn-action {{
562
+ background: var(--accent);
563
+ color: #090d16;
564
+ border: none;
565
+ padding: 8px 16px;
566
+ border-radius: 6px;
567
+ font-weight: 600;
568
+ font-size: 13px;
569
+ cursor: pointer;
570
+ }}
571
+ .card-meta {{
572
+ padding: 16px;
573
+ display: flex;
574
+ flex-direction: column;
575
+ gap: 8px;
576
+ }}
577
+ .card-header {{
578
+ display: flex;
579
+ justify-content: space-between;
580
+ align-items: center;
581
+ }}
582
+ .badge {{
583
+ font-size: 11px;
584
+ font-weight: 600;
585
+ padding: 3px 8px;
586
+ border-radius: 4px;
587
+ text-transform: uppercase;
588
+ letter-spacing: 0.05em;
589
+ }}
590
+ .badge-ui {{ background: rgba(56, 189, 248, 0.15); color: #38bdf8; }}
591
+ .badge-wireframe {{ background: rgba(148, 163, 184, 0.15); color: #94a3b8; }}
592
+ .badge-component {{ background: rgba(129, 140, 248, 0.15); color: #818cf8; }}
593
+ .badge-logo, .badge-icon {{ background: rgba(52, 211, 153, 0.15); color: #34d399; }}
594
+ .card-date {{
595
+ font-size: 11px;
596
+ color: var(--text-muted);
597
+ font-family: 'Fira Code', monospace;
598
+ }}
599
+ .card-title {{
600
+ font-size: 14px;
601
+ font-weight: 600;
602
+ overflow: hidden;
603
+ text-overflow: ellipsis;
604
+ white-space: nowrap;
605
+ }}
606
+ .card-footer {{
607
+ display: flex;
608
+ justify-content: space-between;
609
+ align-items: center;
610
+ margin-top: 4px;
611
+ padding-top: 10px;
612
+ border-top: 1px solid var(--border);
613
+ }}
614
+ .btn-copy {{
615
+ background: transparent;
616
+ border: 1px solid var(--border);
617
+ color: var(--text-muted);
618
+ padding: 4px 10px;
619
+ border-radius: 4px;
620
+ font-size: 12px;
621
+ cursor: pointer;
622
+ }}
623
+ .btn-copy:hover {{
624
+ color: var(--text);
625
+ border-color: #334155;
626
+ }}
627
+ .btn-link {{
628
+ color: var(--accent);
629
+ text-decoration: none;
630
+ font-size: 13px;
631
+ font-weight: 500;
632
+ }}
633
+ .empty-state {{
634
+ grid-column: 1 / -1;
635
+ text-align: center;
636
+ padding: 80px 20px;
637
+ color: var(--text-muted);
638
+ }}
639
+ .empty-state h3 {{
640
+ color: var(--text);
641
+ font-size: 20px;
642
+ margin-bottom: 8px;
643
+ }}
644
+ /* Modal */
645
+ .modal-backdrop {{
646
+ position: fixed;
647
+ inset: 0;
648
+ background: rgba(9, 13, 22, 0.85);
649
+ backdrop-filter: blur(8px);
650
+ z-index: 1000;
651
+ display: none;
652
+ align-items: center;
653
+ justify-content: center;
654
+ padding: 24px;
655
+ }}
656
+ .modal-backdrop.open {{ display: flex; }}
657
+ .modal-container {{
658
+ background: var(--surface);
659
+ border: 1px solid var(--border);
660
+ border-radius: var(--radius);
661
+ width: 90vw;
662
+ height: 85vh;
663
+ display: flex;
664
+ flex-direction: column;
665
+ overflow: hidden;
666
+ }}
667
+ .modal-header {{
668
+ padding: 14px 20px;
669
+ border-bottom: 1px solid var(--border);
670
+ display: flex;
671
+ justify-content: space-between;
672
+ align-items: center;
673
+ }}
674
+ .modal-body {{
675
+ flex: 1;
676
+ background: #fff;
677
+ }}
678
+ .modal-body iframe {{
679
+ width: 100%;
680
+ height: 100%;
681
+ border: none;
682
+ }}
683
+ .btn-close {{
684
+ background: none;
685
+ border: none;
686
+ color: var(--text-muted);
687
+ font-size: 22px;
688
+ cursor: pointer;
689
+ }}
690
+ .btn-close:hover {{ color: var(--text); }}
691
+ </style>
692
+ </head>
693
+ <body>
694
+ <header>
695
+ <div class="brand">
696
+ <div class="brand-logo">&Sigma;</div>
697
+ <div class="brand-title">Superdesign Canvas</div>
698
+ </div>
699
+ <div class="filter-bar">
700
+ <button class="filter-btn active" onclick="filterGallery('all')">All</button>
701
+ <button class="filter-btn" onclick="filterGallery('ui')">UI</button>
702
+ <button class="filter-btn" onclick="filterGallery('component')">Components</button>
703
+ <button class="filter-btn" onclick="filterGallery('wireframe')">Wireframes</button>
704
+ <button class="filter-btn" onclick="filterGallery('logo')">Logos &amp; Icons</button>
705
+ </div>
706
+ </header>
707
+ <main>
708
+ <div class="gallery-grid" id="gallery-grid">
709
+ {cards_joined}
710
+ </div>
711
+ </main>
712
+
713
+ <div class="modal-backdrop" id="preview-modal" onclick="closeModal(event)">
714
+ <div class="modal-container" onclick="event.stopPropagation()">
715
+ <div class="modal-header">
716
+ <span id="modal-title" style="font-weight:600;font-size:14px;"></span>
717
+ <button class="btn-close" onclick="closeModalDirect()">&times;</button>
718
+ </div>
719
+ <div class="modal-body">
720
+ <iframe id="modal-frame" src="about:blank"></iframe>
721
+ </div>
722
+ </div>
723
+ </div>
724
+
725
+ <script>
726
+ function filterGallery(type) {{
727
+ document.querySelectorAll('.filter-btn').forEach(btn => btn.classList.remove('active'));
728
+ event.target.classList.add('active');
729
+ const cards = document.querySelectorAll('.gallery-card');
730
+ cards.forEach(card => {{
731
+ if (type === 'all' || card.dataset.type === type || (type === 'logo' && (card.dataset.type === 'logo' || card.dataset.type === 'icon'))) {{
732
+ card.style.display = 'flex';
733
+ }} else {{
734
+ card.style.display = 'none';
735
+ }}
736
+ }});
737
+ }}
738
+ function openModal(src, title) {{
739
+ document.getElementById('modal-title').textContent = title;
740
+ document.getElementById('modal-frame').src = src;
741
+ document.getElementById('preview-modal').classList.add('open');
742
+ }}
743
+ function closeModal(e) {{
744
+ if (e.target.id === 'preview-modal') {{
745
+ closeModalDirect();
746
+ }}
747
+ }}
748
+ function closeModalDirect() {{
749
+ document.getElementById('preview-modal').classList.remove('open');
750
+ document.getElementById('modal-frame').src = 'about:blank';
751
+ }}
752
+ document.addEventListener('keydown', (e) => {{
753
+ if (e.key === 'Escape') closeModalDirect();
754
+ }});
755
+ function copyPath(text, btn) {{
756
+ navigator.clipboard.writeText(text).then(() => {{
757
+ const original = btn.textContent;
758
+ btn.textContent = 'Copied!';
759
+ setTimeout(() => {{ btn.textContent = original; }}, 1500);
760
+ }});
761
+ }}
762
+ </script>
763
+ </body>
764
+ </html>"""
765
+
766
+ with open(gallery_file, "w", encoding="utf-8") as gf:
767
+ gf.write(gallery_html_content)
768
+
769
+ return {
770
+ "success": True,
771
+ "gallery_file": gallery_file.replace("\\", "/"),
772
+ "total_items": len(items),
773
+ "url_hint": f"Open file://{os.path.abspath(gallery_file)} in any browser to inspect all designs.",
774
+ }