component-mapper 0.1.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.
@@ -0,0 +1,4 @@
1
+ from component_mapper.pipeline import MapperPipeline
2
+ from component_mapper.config import MapperSettings
3
+
4
+ __all__ = ["MapperPipeline", "MapperSettings"]
File without changes
@@ -0,0 +1,72 @@
1
+ import asyncio
2
+ import json
3
+ import logging
4
+ from pathlib import Path
5
+ from component_mapper.models import MappingCacheRecord
6
+
7
+ logger = logging.getLogger(__name__)
8
+
9
+
10
+ class MappingCache:
11
+ def __init__(self, cache_path: str, auto_persist_every: int = 50):
12
+ self._path = Path(cache_path)
13
+ self._store: dict[str, MappingCacheRecord] = {}
14
+ self._lock = asyncio.Lock()
15
+ self._write_count = 0
16
+ self._auto_persist_every = auto_persist_every
17
+
18
+ async def load(self) -> None:
19
+ """Load cache from disk. Silent if file missing."""
20
+ if not self._path.exists():
21
+ logger.debug("No mapping cache at %s — starting fresh", self._path)
22
+ return
23
+ try:
24
+ async with asyncio.Lock():
25
+ data = self._path.read_text()
26
+ records = json.loads(data)
27
+ async with self._lock:
28
+ for key, raw in records.items():
29
+ try:
30
+ self._store[key] = MappingCacheRecord.model_validate(raw)
31
+ except Exception:
32
+ pass
33
+ logger.info(
34
+ "Loaded %d mapping cache records from %s", len(self._store), self._path
35
+ )
36
+ except Exception as exc:
37
+ logger.warning("Failed to load mapping cache: %s", exc)
38
+
39
+ async def get(self, fingerprint_hash: str) -> MappingCacheRecord | None:
40
+ async with self._lock:
41
+ return self._store.get(fingerprint_hash)
42
+
43
+ async def set(self, fingerprint_hash: str, record: MappingCacheRecord) -> None:
44
+ async with self._lock:
45
+ self._store[fingerprint_hash] = record
46
+ self._write_count += 1
47
+ should_persist = self._write_count % self._auto_persist_every == 0
48
+ if should_persist:
49
+ await self.persist()
50
+
51
+ async def persist(self) -> None:
52
+ """Write cache to disk atomically."""
53
+ self._path.parent.mkdir(parents=True, exist_ok=True)
54
+ tmp_path = self._path.with_suffix(".tmp")
55
+ try:
56
+ async with self._lock:
57
+ data = {k: v.model_dump(mode="json") for k, v in self._store.items()}
58
+ tmp_path.write_text(json.dumps(data, indent=2))
59
+ tmp_path.replace(self._path)
60
+ logger.debug("Persisted %d mapping cache records", len(data))
61
+ except Exception as exc:
62
+ logger.warning("Failed to persist mapping cache: %s", exc)
63
+
64
+ async def increment_hit(self, fingerprint_hash: str) -> None:
65
+ async with self._lock:
66
+ record = self._store.get(fingerprint_hash)
67
+ if record:
68
+ record.hit_count += 1
69
+
70
+ @property
71
+ def size(self) -> int:
72
+ return len(self._store)
@@ -0,0 +1,247 @@
1
+ from pydantic import BaseModel, Field
2
+ from pydantic_settings import BaseSettings, SettingsConfigDict
3
+
4
+
5
+ class ModelRoutingConfig(BaseModel):
6
+ complex_model: str = "anthropic/claude-sonnet-4-6"
7
+ standard_model: str = "anthropic/claude-haiku-4-5-20251001"
8
+ fast_model: str = "anthropic/claude-haiku-4-5-20251001"
9
+
10
+ complex_candidate_threshold: int = 3
11
+ complex_prop_count_threshold: int = 8
12
+ fast_max_candidates: int = 1
13
+ fast_max_props: int = 4
14
+
15
+
16
+ class SignatureIndexConfig(BaseModel):
17
+ index_cache_path: str = ".cache/signature_index.json"
18
+ custom_registry_path: str = ".cache/custom_registry.json"
19
+ tfidf_max_features: int = 512
20
+ tfidf_ngram_range: tuple[int, int] = (2, 4)
21
+
22
+ direct_match_threshold: float = 0.85
23
+ candidate_min_threshold: float = 0.40
24
+ max_candidates_per_segment: int = 4
25
+
26
+
27
+ class MappingCacheConfig(BaseModel):
28
+ cache_path: str = ".cache/mapping_cache.json"
29
+ auto_persist_every: int = 50
30
+ min_confidence_to_cache: float = 0.0
31
+
32
+
33
+ class MCPConfig(BaseModel):
34
+ transport: str = "stdio"
35
+ sse_url: str = "http://localhost:7423/sse"
36
+ components_json_path: str = "components.json"
37
+ startup_timeout_seconds: int = 30
38
+
39
+
40
+ class ExternalRegistryConfig(BaseModel):
41
+ """
42
+ An open-source shadcn-compatible registry from https://ui.shadcn.com/docs/directory.
43
+
44
+ name — short identifier used as a component name prefix (e.g. "bundui")
45
+ namespace — shadcn CLI namespace used to install components (e.g. "@bundui")
46
+ url_template — URL with {name} placeholder (e.g. "https://bundui.io/r/{name}.json")
47
+ components — component names to pre-fetch during index rebuild; empty = registry
48
+ is registered for on-demand use but not pre-indexed at startup
49
+ description — human-readable description from the directory listing
50
+ open_source — always True for entries in this list; field kept for future filtering
51
+ """
52
+ name: str
53
+ namespace: str
54
+ url_template: str
55
+ components: list[str] = Field(default_factory=list)
56
+ description: str = ""
57
+ open_source: bool = True
58
+
59
+
60
+ # ---------------------------------------------------------------------------
61
+ # All open-source registries from https://ui.shadcn.com/r/registries.json
62
+ # Source: ui.shadcn.com/docs/directory — all entries are open source by policy.
63
+ #
64
+ # components field is populated only for registries where specific components
65
+ # have been verified to exist (avoids 404 storms during index rebuild).
66
+ # Add component names here as you confirm they are available in that registry.
67
+ # ---------------------------------------------------------------------------
68
+ OPEN_SOURCE_REGISTRIES: list[ExternalRegistryConfig] = [
69
+ ExternalRegistryConfig(name="8bitcn", namespace="@8bitcn", url_template="https://www.8bitcn.com/r/{name}.json", description="8-bit styled retro components. Works with favorite frameworks. Open Source."),
70
+ ExternalRegistryConfig(name="8starlabs-ui", namespace="@8starlabs-ui", url_template="https://ui.8starlabs.com/r/{name}.json", description="Beautifully designed components with niche, high-utility UI elements."),
71
+ ExternalRegistryConfig(name="unlumen-ui", namespace="@unlumen-ui", url_template="https://ui.unlumen.com/r/{name}.json", description="Primitives and components with animation and design focus."),
72
+ ExternalRegistryConfig(name="abui", namespace="@abui", url_template="https://abui.io/r/{name}.json", description="Shadcn-compatible registry of reusable components and utilities."),
73
+ ExternalRegistryConfig(name="arc", namespace="@arc", url_template="https://witharc.co/r/{name}.json", description="Animated, accessible UI built with React and Tailwind CSS."),
74
+ ExternalRegistryConfig(name="aceternity", namespace="@aceternity", url_template="https://ui.aceternity.com/registry/{name}.json", description="Modern component library with Tailwind CSS and Motion for React."),
75
+ ExternalRegistryConfig(name="aevr", namespace="@aevr", url_template="https://ui.aevr.space/r/{name}.json", description="Focused, production-ready components for React/Next.js projects."),
76
+ ExternalRegistryConfig(name="ai-blocks", namespace="@ai-blocks", url_template="https://webllm.org/r/{name}.json", description="AI components for web without server or API keys."),
77
+ ExternalRegistryConfig(name="ai-elements", namespace="@ai-elements", url_template="https://ai-sdk.dev/elements/api/registry/{name}.json", description="Pre-built components for building AI-native applications faster."),
78
+ ExternalRegistryConfig(name="aliimam", namespace="@aliimam", url_template="https://aliimam.in/r/{name}.json", description="Digital experiences connecting and inspiring end-to-end development."),
79
+ ExternalRegistryConfig(name="amplo", namespace="@amplo", url_template="https://amplo.ale.design/r/{name}.json", description="OKLCH-native fill picker with WCAG contrast metrics and accessibility."),
80
+ ExternalRegistryConfig(name="animate-ui", namespace="@animate-ui", url_template="https://animate-ui.com/r/{name}.json", description="Fully animated, open-source React component distribution library."),
81
+ ExternalRegistryConfig(name="assistant-ui", namespace="@assistant-ui", url_template="https://r.assistant-ui.com/{name}.json", description="Radix-style React primitives for AI chat with multiple backend adapters."),
82
+ ExternalRegistryConfig(name="tool-ui", namespace="@tool-ui", url_template="https://www.tool-ui.com/r/{name}.json", description="Open source React components for AI tool calls and assistant outputs."),
83
+ ExternalRegistryConfig(name="better-upload", namespace="@better-upload", url_template="https://better-upload.com/r/{name}.json", description="Simple file uploads for React with S3-compatible service support."),
84
+ ExternalRegistryConfig(name="basecn", namespace="@basecn", url_template="https://basecn.dev/r/{name}.json", description="Beautifully crafted shadcn/ui components powered by Base UI."),
85
+ ExternalRegistryConfig(name="billingsdk", namespace="@billingsdk", url_template="https://billingsdk.com/r/{name}.json", description="Open-source React and Next.js components for SaaS billing and payments."),
86
+ ExternalRegistryConfig(name="blocks-so", namespace="@blocks-so", url_template="https://blocks.so/r/{name}.json", description="Clean, modern application building blocks. Free and Open Source."),
87
+ ExternalRegistryConfig(name="boldkit", namespace="@boldkit", url_template="https://boldkit.dev/r/{name}.json", description="Neubrutalism component library with thick borders and hard shadows."),
88
+ ExternalRegistryConfig(name="bundui", namespace="@bundui", url_template="https://bundui.io/r/{name}.json", description="150+ handcrafted UI components built with Tailwind CSS and shadcn/ui.", components=["pagination"]),
89
+ ExternalRegistryConfig(name="cardcn", namespace="@cardcn", url_template="https://cardcn.dev/r/{name}.json", description="Beautifully-designed shadcn card components collection."),
90
+ ExternalRegistryConfig(name="chamaac", namespace="@chamaac", url_template="https://chamaac.com/r/{name}.json", description="Beautiful, animated components to elevate web projects instantly."),
91
+ ExternalRegistryConfig(name="clerk", namespace="@clerk", url_template="https://clerk.com/r/{name}.json", description="Easiest way to add authentication and user management to applications."),
92
+ ExternalRegistryConfig(name="cognicatch", namespace="@cognicatch", url_template="https://cognicatch.dev/registry/{name}.json", description="Adaptive Error Boundaries and graceful fallback UIs."),
93
+ ExternalRegistryConfig(name="commercn", namespace="@commercn", url_template="https://commercn.com/r/{name}.json", description="Shadcn UI Blocks specifically for Ecommerce websites."),
94
+ ExternalRegistryConfig(name="coss", namespace="@coss", url_template="https://coss.com/ui/r/{name}.json", description="Modern UI component library built on Base UI for developers and AI."),
95
+ ExternalRegistryConfig(name="creative-tim", namespace="@creative-tim", url_template="https://www.creative-tim.com/ui/r/{name}.json", description="Open-source UI components, blocks and AI Agents for integration."),
96
+ ExternalRegistryConfig(name="cult-ui", namespace="@cult-ui", url_template="https://cult-ui.com/r/{name}.json", description="Rare, curated shadcn-compatible components with Framer Motion."),
97
+ ExternalRegistryConfig(name="diceui", namespace="@diceui", url_template="https://diceui.com/r/{name}.json", description="Accessible shadcn/ui components built with React and Tailwind CSS."),
98
+ ExternalRegistryConfig(name="doras-ui", namespace="@doras-ui", url_template="https://ui.doras.to/r/{name}.json", description="Beautiful, reusable component blocks built with React."),
99
+ ExternalRegistryConfig(name="dsikeres1", namespace="@dsikeres1", url_template="https://dsikeres1.github.io/react-date-range-picker/r/{name}.json", description="Headless, composable date and date range picker with zero dependencies."),
100
+ ExternalRegistryConfig(name="elements", namespace="@elements", url_template="https://www.tryelements.dev/r/{name}.json", description="Full-stack shadcn/ui components with auth, monetization, and AI."),
101
+ ExternalRegistryConfig(name="elevenlabs-ui", namespace="@elevenlabs-ui", url_template="https://ui.elevenlabs.io/r/{name}.json", description="Open Source agent and audio components for customization."),
102
+ ExternalRegistryConfig(name="efferd", namespace="@efferd", url_template="https://efferd.com/r/{name}.json", description="Beautifully crafted Shadcn/UI blocks for modern websites."),
103
+ ExternalRegistryConfig(name="einui", namespace="@einui", url_template="https://ui.eindev.ir/r/{name}.json", description="Beautiful, responsive Shadcn components with frosted glass morphism."),
104
+ ExternalRegistryConfig(name="eldoraui", namespace="@eldoraui", url_template="https://eldoraui.site/r/{name}.json", description="Modern UI component library with TypeScript and Framer Motion."),
105
+ ExternalRegistryConfig(name="evilcharts", namespace="@evilcharts", url_template="https://evilcharts.com/r/{name}.json", description="Open-source chart UI website with shadcn and Recharts."),
106
+ ExternalRegistryConfig(name="formcn", namespace="@formcn", url_template="https://formcn.dev/r/{name}.json", description="Build production-ready forms using shadcn components and modern tools."),
107
+ ExternalRegistryConfig(name="gaia", namespace="@gaia", url_template="https://ui.heygaia.io/r/{name}.json", description="Production-ready UI for building beautiful AI assistants."),
108
+ ExternalRegistryConfig(name="gamifykit", namespace="@gamifykit", url_template="https://gamifykit.com/r/{name}.json", description="Fully composable components extending shadcn/ui with gamification patterns."),
109
+ ExternalRegistryConfig(name="glass-ui", namespace="@glass-ui", url_template="https://glass-ui.crenspire.com/r/{name}.json", description="40+ glassmorphic React components with Apple-inspired design."),
110
+ ExternalRegistryConfig(name="glasscn", namespace="@glasscn", url_template="https://glasscn-components.vercel.app/r/{name}.json", description="Shadcn-compatible glassmorphism components inspired by Apple."),
111
+ ExternalRegistryConfig(name="hextaui", namespace="@hextaui", url_template="https://hextaui.com/r/{name}.json", description="Ready-to-use foundation components built on shadcn/ui.", components=["pagination"]),
112
+ ExternalRegistryConfig(name="shadcnhooks", namespace="@shadcnhooks", url_template="https://shadcn-hooks.com/r/{name}.json", description="Comprehensive React Hooks Collection built with Shadcn."),
113
+ ExternalRegistryConfig(name="indiacn", namespace="@indiacn", url_template="https://indiacn.in/r/{name}.json", description="UX4G 2.0 design system for India with accessible components."),
114
+ ExternalRegistryConfig(name="intentui", namespace="@intentui", url_template="https://intentui.com/r/{name}", description="Accessible React component library to copy and customize."),
115
+ ExternalRegistryConfig(name="kibo-ui", namespace="@kibo-ui", url_template="https://www.kibo-ui.com/r/{name}.json", description="Composable, accessible, open source components for shadcn/ui."),
116
+ ExternalRegistryConfig(name="kanpeki", namespace="@kanpeki", url_template="https://kanpeki.vercel.app/r/{name}.json", description="Perfect-designed components built on React Aria and Motion."),
117
+ ExternalRegistryConfig(name="kokonutui", namespace="@kokonutui", url_template="https://kokonutui.com/r/{name}.json", description="Stunning components with Tailwind CSS, shadcn/ui and Motion."),
118
+ ExternalRegistryConfig(name="launchui", namespace="@launchui", url_template="https://www.launchuicomponents.com/r/{name}.json", description="Landing page components and templates with React and Shadcn/ui."),
119
+ ExternalRegistryConfig(name="limeplay", namespace="@limeplay", url_template="https://limeplay.winoffrg.dev/r/{name}.json", description="Modern UI Library for building media players in React."),
120
+ ExternalRegistryConfig(name="loading-ui", namespace="@loading-ui", url_template="https://loading-ui.com/r/{name}.json", description="Spinners, loaders, and animations for modern web apps."),
121
+ ExternalRegistryConfig(name="lucide-animated", namespace="@lucide-animated", url_template="https://lucide-animated.com/r/{name}.json", description="Open-source smooth animated lucide icons collection."),
122
+ ExternalRegistryConfig(name="lytenyte", namespace="@lytenyte", url_template="https://www.1771technologies.com/r/{name}.json", description="High performance, lightweight React data grid with Shadcn theming."),
123
+ ExternalRegistryConfig(name="magicui", namespace="@magicui", url_template="https://magicui.design/r/{name}", description="150+ free animated components and effects for design engineers."),
124
+ ExternalRegistryConfig(name="manifest", namespace="@manifest", url_template="https://ui.manifest.build/r/{name}.json", description="Agentic UI toolkit for building MCP Apps with open-source components."),
125
+ ExternalRegistryConfig(name="mapcn", namespace="@mapcn", url_template="https://mapcn.dev/r/{name}.json", description="Customizable map components for React built on MapLibre."),
126
+ ExternalRegistryConfig(name="moleculeui", namespace="@moleculeui", url_template="https://www.moleculeui.design/r/{name}.json", description="Modern React component library focused on intuitive interactions."),
127
+ ExternalRegistryConfig(name="motion-primitives",namespace="@motion-primitives",url_template="https://motion-primitives.com/c/{name}.json", description="Beautifully designed motions components for copy-paste use."),
128
+ ExternalRegistryConfig(name="nordaun", namespace="@nordaun", url_template="https://ui.nordaun.com/r/{name}.json", description="Simple components for extraordinary creations."),
129
+ ExternalRegistryConfig(name="ncdai", namespace="@ncdai", url_template="https://chanhdai.com/r/{name}.json", description="Pixel-perfect, uniquely crafted components collection."),
130
+ ExternalRegistryConfig(name="nuqs", namespace="@nuqs", url_template="https://nuqs.dev/r/{name}.json", description="Custom parsers and utilities for type-safe URL state management."),
131
+ ExternalRegistryConfig(name="neobrutalism", namespace="@neobrutalism", url_template="https://www.neobrutalism.dev/r/{name}.json", description="Neobrutalism-styled components based on shadcn/ui."),
132
+ ExternalRegistryConfig(name="nessra-ui", namespace="@nessra-ui", url_template="https://nessra-ui.vercel.app/r/{name}.json", description="Beautiful, accessible components with Tailwind CSS v4 and Radix."),
133
+ ExternalRegistryConfig(name="openstatus", namespace="@openstatus", url_template="https://openstatus.dev/r/{name}.json", description="Hand-crafted, accessible components for beautiful status pages."),
134
+ ExternalRegistryConfig(name="optics", namespace="@optics", url_template="https://optics.agusmayol.com.ar/r/{name}.json", description="Design system with re-styled components, utilities, and hooks."),
135
+ ExternalRegistryConfig(name="oui", namespace="@oui", url_template="https://oui.mw10013.workers.dev/r/{name}.json", description="React Aria Components with shadcn characteristics."),
136
+ ExternalRegistryConfig(name="pacekit", namespace="@pacekit", url_template="https://ui.pacekit.dev/r/{name}.json", description="UI blocks for real apps and dashboards from early ideas to production."),
137
+ ExternalRegistryConfig(name="pacekit-gsap", namespace="@pacekit-gsap", url_template="https://gsap.pacekit.dev/r/{name}.json", description="Animated GSAP components for smooth interaction and rich detail."),
138
+ ExternalRegistryConfig(name="plate", namespace="@plate", url_template="https://platejs.org/r/{name}.json", description="AI-powered rich text editor for React."),
139
+ ExternalRegistryConfig(name="prompt-kit", namespace="@prompt-kit", url_template="https://www.prompt-kit.com/c/{name}.json", description="Core building blocks for AI apps with accessible components."),
140
+ ExternalRegistryConfig(name="prosekit", namespace="@prosekit", url_template="https://prosekit.dev/r/{name}.json", description="Powerful flexible rich text editor for multiple frameworks."),
141
+ ExternalRegistryConfig(name="react-aria", namespace="@react-aria", url_template="https://react-aria.adobe.com/registry/{name}.json", description="Customizable components with adaptive interactions and accessibility."),
142
+ ExternalRegistryConfig(name="react-bits", namespace="@react-bits", url_template="https://reactbits.dev/r/{name}.json", description="Animated, interactive, customizable React components for websites."),
143
+ ExternalRegistryConfig(name="retroui", namespace="@retroui", url_template="https://retroui.dev/r/{name}.json", description="Neobrutalism styled React and TailwindCSS library for bold apps."),
144
+ ExternalRegistryConfig(name="reui", namespace="@reui", url_template="https://reui.io/r/{name}.json", description="Free library of 1,000+ components and patterns for shadcn."),
145
+ ExternalRegistryConfig(name="scrollxui", namespace="@scrollxui", url_template="https://www.scrollxui.dev/registry/{name}.json", description="Animated, interactive, customizable component library for ShadCN."),
146
+ ExternalRegistryConfig(name="spell", namespace="@spell", url_template="https://spell.sh/r/{name}.json", description="Beautiful, sophisticated UI components for modern React applications."),
147
+ ExternalRegistryConfig(name="square-ui", namespace="@square-ui", url_template="https://square.lndev.me/registry/{name}.json", description="Beautifully crafted open-source layouts built with shadcn/ui."),
148
+ ExternalRegistryConfig(name="roiui", namespace="@roiui", url_template="https://roiui.com/r/{name}.json", description="UI components and blocks built with Base UI primitives."),
149
+ ExternalRegistryConfig(name="satoriui", namespace="@satoriui", url_template="https://satoriui.site/r/{name}.json", description="Comprehensive high-fidelity interaction components with motion."),
150
+ ExternalRegistryConfig(name="solaceui", namespace="@solaceui", url_template="https://www.solaceui.com/r/{name}.json", description="Production-ready sections and templates for Next.js and Motion."),
151
+ ExternalRegistryConfig(name="shadcnblocks", namespace="@shadcnblocks", url_template="https://shadcnblocks.com/r/{name}.json", description="1429 blocks, 1189 variants, 14 templates, themes and admin patterns."),
152
+ ExternalRegistryConfig(name="shadcndesign", namespace="@shadcndesign", url_template="https://shadcndesign-free.vercel.app/r/{name}.json", description="Growing collection of high-quality blocks and themes for shadcn/ui."),
153
+ ExternalRegistryConfig(name="shadcnmaps", namespace="@shadcnmaps", url_template="https://shadcnmaps.com/r/{name}.json", description="Beautiful map components powered by pure SVG."),
154
+ ExternalRegistryConfig(name="shadcnstore", namespace="@shadcnstore", url_template="https://shadcnstore.com/r/{name}.json", description="Growing collection of shadcn/ui components, blocks, and templates."),
155
+ ExternalRegistryConfig(name="shadcn-studio", namespace="@shadcn-studio", url_template="https://shadcnstudio.com/r/{name}.json", description="Open-source shadcn/ui components with powerful theme generator."),
156
+ ExternalRegistryConfig(name="shadcn-editor", namespace="@shadcn-editor", url_template="https://raw.githubusercontent.com/htmujahid/shadcn-editor/refs/heads/main/public/r/{name}.json", description="Accessible, customizable rich text editor with Lexical and Shadcn."),
157
+ ExternalRegistryConfig(name="shadcnuikit", namespace="@shadcnuikit", url_template="https://shadcnuikit.com/r/{name}.json", description="Admin dashboards, website templates, and real-world examples."),
158
+ ExternalRegistryConfig(name="shadcncraft", namespace="@shadcncraft", url_template="https://shadcncraft.com/r/{name}.json", description="Polished shadcn/ui components built to production standards."),
159
+ ExternalRegistryConfig(name="shark", namespace="@shark", url_template="https://shark.vini.one/r/{name}.json", description="Shadcn/ui-style components built on Ark UI."),
160
+ ExternalRegistryConfig(name="smoothui", namespace="@smoothui", url_template="https://smoothui.dev/r/{name}.json", description="Motion components with Framer Motion and TailwindCSS animations."),
161
+ ExternalRegistryConfig(name="spectrumui", namespace="@spectrumui", url_template="https://ui.spectrumhq.in/r/{name}.json", description="Modern component library with elegant, responsive components."),
162
+ ExternalRegistryConfig(name="supabase", namespace="@supabase", url_template="https://supabase.com/ui/r/{name}.json", description="React components and blocks connecting front-end to Supabase back-end."),
163
+ ExternalRegistryConfig(name="tailark", namespace="@tailark", url_template="https://tailark.com/r/{name}.json", description="Shadcn blocks designed for building modern marketing websites."),
164
+ ExternalRegistryConfig(name="taki", namespace="@taki", url_template="https://taki-ui.com/r/{name}.json", description="Accessible components built with React Aria and Shadcn tokens."),
165
+ ExternalRegistryConfig(name="thegridcn", namespace="@thegridcn", url_template="https://thegridcn.com/r/{name}.json", description="Tron-inspired shadcn/ui theme with sci-fi components."),
166
+ ExternalRegistryConfig(name="uitripled", namespace="@uitripled", url_template="https://ui.tripled.work/r/{name}.json", description="Production-ready UI components and blocks with Framer Motion."),
167
+ ExternalRegistryConfig(name="utilcn", namespace="@utilcn", url_template="https://utilcn.dev/r/{name}.json", description="Fullstack registry items for big features and ChatGPT apps."),
168
+ ExternalRegistryConfig(name="pureui", namespace="@pureui", url_template="https://pure.kam-ui.com/r/{name}.json", description="Refined, animated, accessible components with Base UI and Motion."),
169
+ ExternalRegistryConfig(name="tailwind-builder", namespace="@tailwind-builder", url_template="https://tailwindbuilder.ai/r/{name}.json", description="Free UI blocks and AI tools for forms, tables, and charts."),
170
+ ExternalRegistryConfig(name="tailwind-admin", namespace="@tailwind-admin", url_template="https://tailwind-admin.com/r/{name}.json", description="Free tailwind admin dashboard templates and UI-blocks."),
171
+ ExternalRegistryConfig(name="forgeui", namespace="@forgeui", url_template="https://forgeui.in/r/{name}.json", description="Beautifully designed, accessible, customizable open-source components."),
172
+ ExternalRegistryConfig(name="skiper-ui", namespace="@skiper-ui", url_template="https://skiper-ui.com/registry/{name}.json", description="Uncommon components for Next.js with shadcn CLI 3.0."),
173
+ ExternalRegistryConfig(name="animbits", namespace="@animbits", url_template="https://animbits.dev/r/{name}.json", description="Animated UI components using Framer Motion with general-purpose effects."),
174
+ ExternalRegistryConfig(name="shadcn-space", namespace="@shadcn-space", url_template="https://shadcnspace.com/r/{name}.json", description="Extra-ordinary, customizable shadcn/ui components and themes."),
175
+ ExternalRegistryConfig(name="icons-animated", namespace="@icons-animated", url_template="https://icons.lndev.me/r/{name}.json", description="Open-source animated icons (Tabler, Phosphor) for projects."),
176
+ ExternalRegistryConfig(name="heroicons-animated",namespace="@heroicons-animated",url_template="https://www.heroicons-animated.com/r/{name}.json", description="316 beautifully animated heroicons for projects."),
177
+ ExternalRegistryConfig(name="devl", namespace="@devl", url_template="https://devl.dev/r/{name}.json", description="Hand-crafted layouts and UI primitives for shipping fast."),
178
+ ExternalRegistryConfig(name="beste-ui", namespace="@beste-ui", url_template="https://ui.beste.co/r/{name}.json", description="Production-ready UI blocks for landing pages and dashboards."),
179
+ ExternalRegistryConfig(name="tokenui", namespace="@tokenui", url_template="https://www.tokenui.dev/r/{name}.json", description="Beautiful, interactive documentation components for design tokens."),
180
+ ExternalRegistryConfig(name="lumiui", namespace="@lumiui", url_template="https://www.lumiui.dev/r/{name}.json", description="Composable React components with Base UI and Tailwind CSS."),
181
+ ExternalRegistryConfig(name="uselayouts", namespace="@uselayouts", url_template="https://uselayouts.com/r/{name}.json", description="Premium animated React components and micro-interactions."),
182
+ ExternalRegistryConfig(name="joyco", namespace="@joyco", url_template="https://registry.joyco.studio/r/{name}.json", description="Components including MobileMenu, ChatUI, and HLSVideoPlayer."),
183
+ ExternalRegistryConfig(name="gooseui", namespace="@gooseui", url_template="https://gooseui.pro/r/{name}.json", description="Open source with animated components and custom notifications."),
184
+ ExternalRegistryConfig(name="baselayer", namespace="@baselayer", url_template="https://www.baselayer.dev/r/{name}.json", description="Components built on React Aria and Tailwind CSS."),
185
+ ExternalRegistryConfig(name="jolyui", namespace="@jolyui", url_template="https://www.jolyui.dev/r/{name}.json", description="Modern React component library with TypeScript and Tailwind."),
186
+ ExternalRegistryConfig(name="fab-ui", namespace="@fab-ui", url_template="https://fab-ui.com/r/{name}.json", description="Beautifully designed UI components for modern web applications."),
187
+ ExternalRegistryConfig(name="asanshay", namespace="@asanshay", url_template="https://ds.asanshay.com/r/{name}.json", description="Clean, beautiful, simple UI primitives and AI elements."),
188
+ ExternalRegistryConfig(name="typedora-ui", namespace="@typedora-ui", url_template="https://typedora-ui.netlify.app/r/{name}.json", description="Next-generation extension layer for shadcn/ui with type-safety."),
189
+ ExternalRegistryConfig(name="sona-ui", namespace="@sona-ui", url_template="https://sona-ui.vercel.app/r/{name}.json", description="Modern UI library with React and TailwindCSS for web applications."),
190
+ ExternalRegistryConfig(name="pixelact-ui", namespace="@pixelact-ui", url_template="https://pixelactui.com/r/{name}.json", description="Playful pixel art style components built on shadcn."),
191
+ ExternalRegistryConfig(name="emerald-ui", namespace="@emerald-ui", url_template="https://emerald-ui.com/r/{name}.json", description="Components with Motion, GSAP, Tailwind CSS and shadcn/ui."),
192
+ ExternalRegistryConfig(name="componentry", namespace="@componentry", url_template="https://componentry.fun/r/{name}.json", description="Beautiful, interactive React and Tailwind components for UIs."),
193
+ ExternalRegistryConfig(name="fluid", namespace="@fluid", url_template="https://www.fluidfunctionalism.com/r/{name}.json", description="Fluid components for functional clarity with spring animations."),
194
+ ExternalRegistryConfig(name="gammaui", namespace="@gammaui", url_template="https://www.gammaui.com/r/{name}.json", description="Landing page components with React, Tailwind CSS and Motion."),
195
+ ExternalRegistryConfig(name="tailgrids", namespace="@tailgrids", url_template="https://tailgrids.com/docs/r/{name}.json", description="React UI Components powered by Tailwind CSS."),
196
+ ExternalRegistryConfig(name="nexus-ui", namespace="@nexus-ui", url_template="https://nexus-ui.dev/r/{name}.json", description="Open-source primitives for building AI interfaces with chat."),
197
+ ExternalRegistryConfig(name="sabraman", namespace="@sabraman", url_template="https://sabraman.ru/r/{name}.json", description="Legacy skeuomorphic UI components and blocks for shadcn."),
198
+ ExternalRegistryConfig(name="odysseyui", namespace="@odysseyui", url_template="https://www.odysseyui.com/r/{name}.json", description="Design-focused component library for Next.js built for speed."),
199
+ ExternalRegistryConfig(name="openpolicy", namespace="@openpolicy", url_template="https://www.openpolicy.sh/r/{name}.json", description="Open-source components for terms, privacy and cookie banners."),
200
+ ExternalRegistryConfig(name="mksingh", namespace="@mksingh", url_template="https://mksingh.dev/r/{name}.json", description="Personal registry of production-ready ShadCN components."),
201
+ ExternalRegistryConfig(name="flowkit-ui", namespace="@flowkit-ui", url_template="https://flowkit-ui.vzkiss.com/r/{name}.json", description="Opinionated, accessible components on Base UI."),
202
+ ExternalRegistryConfig(name="termcn", namespace="@termcn", url_template="https://termcn.vercel.app/r/{name}.json", description="Beautiful terminal UIs made simple. Customizable React components."),
203
+ ExternalRegistryConfig(name="remocn", namespace="@remocn", url_template="https://www.remocn.dev/r/{name}.json", description="Production-ready components for Remotion with text animations."),
204
+ ExternalRegistryConfig(name="aicanvas", namespace="@aicanvas", url_template="https://aicanvas.me/r/{name}.json", description="54 animated React components with AI reproduction prompts."),
205
+ ExternalRegistryConfig(name="delta", namespace="@delta", url_template="https://deltacomponents.dev/r/{name}.json", description="Shadcn registry for AI interfaces with chat and media."),
206
+ ExternalRegistryConfig(name="evilbuttons", namespace="@evilbuttons", url_template="https://evilbuttons.radiumcoders.com/r/{name}.json", description="Animated button collection built with Motion for interactive feedback."),
207
+ ExternalRegistryConfig(name="stepper", namespace="@stepper", url_template="https://francozeta-stepper.vercel.app/{name}.json", description="Modern, accessible, composable Stepper for React."),
208
+ ExternalRegistryConfig(name="framecn", namespace="@framecn", url_template="https://framecn.vercel.app/r/{name}.json", description="Beautiful videos made simple. Customizable video React components."),
209
+ ExternalRegistryConfig(name="ui-layouts", namespace="@ui-layouts", url_template="https://ui-layouts.com/r/{name}.json", description="Components, effects, tools and blocks for modern interfaces."),
210
+ ExternalRegistryConfig(name="uicapsule", namespace="@uicapsule", url_template="https://uicapsule.com/r/{name}.json", description="Curated components at intersection of AI/UI and design experiments."),
211
+ ]
212
+
213
+
214
+ class RegistryConfig(BaseModel):
215
+ shadcn_registry_base_url: str = "https://ui.shadcn.com/r"
216
+ custom_registry_base_url: str = ""
217
+ fetch_timeout_seconds: int = 10
218
+ max_concurrent_fetches: int = 10
219
+ http_cache_ttl_hours: int = 24
220
+ # All open-source registries from the Shadcn community directory.
221
+ # Registries with an empty components list are registered for on-demand use
222
+ # but not pre-fetched during index rebuild (avoids unnecessary network requests).
223
+ external_registries: list[ExternalRegistryConfig] = Field(
224
+ default_factory=lambda: OPEN_SOURCE_REGISTRIES
225
+ )
226
+
227
+
228
+ class LiteLLMConfig(BaseModel):
229
+ batch_size: int = 15
230
+ max_concurrent_batches: int = 4
231
+ timeout_seconds: int = 60
232
+ config_path: str = "" # path to litellm_config.json; empty = no file
233
+ api_key_env: str = "LLM_API_KEY" # env var name for the universal API key
234
+
235
+
236
+ class MapperSettings(BaseSettings):
237
+ model_config = SettingsConfigDict(env_file=".env", env_prefix="MAPPER_")
238
+
239
+ mcp: MCPConfig = MCPConfig()
240
+ registry: RegistryConfig = RegistryConfig()
241
+ signature_index: SignatureIndexConfig = SignatureIndexConfig()
242
+ mapping_cache: MappingCacheConfig = MappingCacheConfig()
243
+ model_routing: ModelRoutingConfig = ModelRoutingConfig()
244
+ litellm: LiteLLMConfig = LiteLLMConfig()
245
+
246
+ astro_project_root: str = "./output/astro"
247
+ generate_collection_schemas: bool = True
File without changes
@@ -0,0 +1,182 @@
1
+ import asyncio
2
+ import json
3
+ import logging
4
+ import aiohttp
5
+ from component_mapper.config import MCPConfig
6
+
7
+ logger = logging.getLogger(__name__)
8
+
9
+
10
+ class MCPConnectionError(Exception):
11
+ pass
12
+
13
+
14
+ class MCPInstallError(Exception):
15
+ pass
16
+
17
+
18
+ class OfficialMCPClient:
19
+ def __init__(self, config: MCPConfig):
20
+ self.config = config
21
+ self._connected = False
22
+ self._proc: asyncio.subprocess.Process | None = None
23
+ self._session: aiohttp.ClientSession | None = None
24
+ self._request_id = 0
25
+ self.calls_made = 0
26
+
27
+ async def connect(self) -> None:
28
+ """Establish MCP connection. Logs warning instead of raising if unavailable."""
29
+ try:
30
+ if self.config.transport == "stdio":
31
+ await self._connect_stdio()
32
+ else:
33
+ await self._connect_sse()
34
+ self._connected = True
35
+ logger.info("MCP client connected via %s", self.config.transport)
36
+ except Exception as exc:
37
+ logger.warning(
38
+ "MCP unavailable (%s) — pipeline will use cached index only", exc
39
+ )
40
+ self._connected = False
41
+
42
+ async def _connect_stdio(self) -> None:
43
+ self._proc = await asyncio.wait_for(
44
+ asyncio.create_subprocess_exec(
45
+ "npx",
46
+ "shadcn",
47
+ "mcp",
48
+ stdin=asyncio.subprocess.PIPE,
49
+ stdout=asyncio.subprocess.PIPE,
50
+ stderr=asyncio.subprocess.PIPE,
51
+ ),
52
+ timeout=self.config.startup_timeout_seconds,
53
+ )
54
+ # Send JSON-RPC initialize
55
+ await self._send_jsonrpc(
56
+ {
57
+ "jsonrpc": "2.0",
58
+ "id": self._next_id(),
59
+ "method": "initialize",
60
+ "params": {
61
+ "protocolVersion": "2024-11-05",
62
+ "capabilities": {},
63
+ "clientInfo": {"name": "component-mapper", "version": "0.1.0"},
64
+ },
65
+ }
66
+ )
67
+ resp = await self._read_jsonrpc()
68
+ if "error" in resp:
69
+ raise MCPConnectionError(f"MCP initialize failed: {resp['error']}")
70
+
71
+ async def _connect_sse(self) -> None:
72
+ self._session = aiohttp.ClientSession()
73
+ # Verify connectivity
74
+ async with self._session.get(
75
+ self.config.sse_url,
76
+ timeout=aiohttp.ClientTimeout(total=self.config.startup_timeout_seconds),
77
+ ) as resp:
78
+ if resp.status >= 400:
79
+ raise MCPConnectionError(f"SSE endpoint returned {resp.status}")
80
+
81
+ def _next_id(self) -> int:
82
+ self._request_id += 1
83
+ return self._request_id
84
+
85
+ async def _send_jsonrpc(self, payload: dict) -> None:
86
+ if self._proc and self._proc.stdin:
87
+ data = json.dumps(payload) + "\n"
88
+ self._proc.stdin.write(data.encode())
89
+ await self._proc.stdin.drain()
90
+
91
+ async def _read_jsonrpc(self) -> dict:
92
+ if self._proc and self._proc.stdout:
93
+ line = await asyncio.wait_for(self._proc.stdout.readline(), timeout=30)
94
+ return json.loads(line.decode().strip())
95
+ return {}
96
+
97
+ async def _call_tool(self, tool_name: str, arguments: dict) -> dict:
98
+ self.calls_made += 1
99
+ if self.config.transport == "stdio":
100
+ await self._send_jsonrpc(
101
+ {
102
+ "jsonrpc": "2.0",
103
+ "id": self._next_id(),
104
+ "method": "tools/call",
105
+ "params": {"name": tool_name, "arguments": arguments},
106
+ }
107
+ )
108
+ return await self._read_jsonrpc()
109
+ elif self._session:
110
+ async with self._session.post(
111
+ self.config.sse_url.replace("/sse", "/call"),
112
+ json={"tool": tool_name, "arguments": arguments},
113
+ timeout=aiohttp.ClientTimeout(total=60),
114
+ ) as resp:
115
+ return await resp.json()
116
+ return {}
117
+
118
+ async def list_components(self) -> list[str]:
119
+ """List all available shadcn component names. Called once at startup."""
120
+ if not self._connected:
121
+ logger.debug("MCP not connected, returning empty component list")
122
+ return []
123
+ try:
124
+ resp = await self._call_tool("list_components", {})
125
+ result = resp.get("result", {})
126
+ content = result.get("content", [])
127
+ if isinstance(content, list):
128
+ for item in content:
129
+ if isinstance(item, dict) and "text" in item:
130
+ try:
131
+ data = json.loads(item["text"])
132
+ if isinstance(data, list):
133
+ return [str(c) for c in data]
134
+ if isinstance(data, dict) and "components" in data:
135
+ return [str(c) for c in data["components"]]
136
+ except (json.JSONDecodeError, TypeError):
137
+ pass
138
+ logger.warning("Unexpected list_components response shape")
139
+ return []
140
+ except Exception as exc:
141
+ logger.warning("list_components failed: %s", exc)
142
+ return []
143
+
144
+ async def install_components(self, names: list[str]) -> dict[str, bool]:
145
+ """Install components via MCP. Called once at end of pipeline run."""
146
+ if not self._connected or not names:
147
+ return {n: False for n in names}
148
+ try:
149
+ resp = await self._call_tool("install_components", {"components": names})
150
+ result = resp.get("result", {})
151
+ content = result.get("content", [])
152
+ results: dict[str, bool] = {}
153
+ for item in content:
154
+ if isinstance(item, dict) and "text" in item:
155
+ try:
156
+ data = json.loads(item["text"])
157
+ if isinstance(data, dict):
158
+ results.update({k: bool(v) for k, v in data.items()})
159
+ except (json.JSONDecodeError, TypeError):
160
+ pass
161
+ # Default missing keys to True (assume success)
162
+ for name in names:
163
+ if name not in results:
164
+ results[name] = True
165
+ logger.info("Installed %d components via MCP", sum(results.values()))
166
+ return results
167
+ except Exception as exc:
168
+ raise MCPInstallError(f"install_components failed: {exc}") from exc
169
+
170
+ async def disconnect(self) -> None:
171
+ if self._proc:
172
+ try:
173
+ self._proc.stdin.close()
174
+ await self._proc.wait()
175
+ except Exception:
176
+ pass
177
+ self._proc = None
178
+ if self._session:
179
+ await self._session.close()
180
+ self._session = None
181
+ self._connected = False
182
+ logger.debug("MCP client disconnected")