diff --git a/.github/workflows/extraction-pipeline-native.yml b/.github/workflows/extraction-pipeline-native.yml index 8996407..551c478 100644 --- a/.github/workflows/extraction-pipeline-native.yml +++ b/.github/workflows/extraction-pipeline-native.yml @@ -9,9 +9,8 @@ on: - 'packages/native-mcp/scripts/**' - 'packages/native-mcp/src/**' - '.github/workflows/extraction-pipeline-native.yml' - schedule: - # Run daily at 3 AM UTC - - cron: "0 3 * * *" + repository_dispatch: + types: [native-version-bump] workflow_dispatch: inputs: library: diff --git a/.github/workflows/extraction-pipeline.yml b/.github/workflows/extraction-pipeline.yml index 3e496f2..da931a0 100644 --- a/.github/workflows/extraction-pipeline.yml +++ b/.github/workflows/extraction-pipeline.yml @@ -9,9 +9,8 @@ on: - 'packages/react-mcp/scripts/**' - 'packages/react-mcp/src/**' - '.github/workflows/extraction-pipeline.yml' - schedule: - # Run daily at 2 AM UTC - - cron: "0 2 * * *" + repository_dispatch: + types: [react-version-bump] workflow_dispatch: inputs: library: diff --git a/README.md b/README.md index ce7add9..257c018 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Model Context Protocol (MCP) servers for the HeroUI design system. Access HeroUI | Package | Description | Status | Docs | | --- | --- | --- | --- | | `@heroui/react-mcp` | MCP server for web (`@heroui/react`) component docs, examples, and theme data | ✅ Available on npm | [README](packages/react-mcp/README.md) | -| `@heroui/native-mcp` | MCP server for React Native (`@heroui/native`) component docs and tooling | 🚧 In development | [README](packages/native-mcp/README.md) | +| `@heroui/native-mcp` | MCP server for React Native (`@heroui/native`) component docs and tooling | ✅ Available on npm | [README](packages/native-mcp/README.md) | ## Quick Start @@ -23,7 +23,6 @@ npx -y @heroui/react-mcp@latest **For React Native:** ```bash -# Coming soon npx -y @heroui/native-mcp@latest ``` diff --git a/packages/native-mcp/package.json b/packages/native-mcp/package.json index 2279aa3..3b048a9 100644 --- a/packages/native-mcp/package.json +++ b/packages/native-mcp/package.json @@ -60,7 +60,7 @@ "clean": "rm -rf dist dist-api", "prepublishOnly": "pnpm build", "changelog": "conventional-changelog -p angular -i CHANGELOG.md -s --commit-path .", - "release": "bumpp --execute='pnpm run changelog' --all --tag='native-mcp-v%s'", + "release": "bumpp --execute='pnpm run changelog' --all --tag='native-mcp-v%s' --commit='chore(native-mcp): release v%s'", "release:check": "pnpm run lint && pnpm run typecheck && pnpm run build" }, "dependencies": { diff --git a/packages/native-mcp/src/api/routes/components.ts b/packages/native-mcp/src/api/routes/components.ts index baaca1a..4a90cff 100644 --- a/packages/native-mcp/src/api/routes/components.ts +++ b/packages/native-mcp/src/api/routes/components.ts @@ -394,140 +394,4 @@ components.post("/examples", async (c) => { } }); -// Get component source code (bulk) -components.post("/source", async (c) => { - const startTime = Date.now(); - - initAnalytics(c.env); - const analytics = getAnalytics(); - - try { - const body = await c.req.json(); - const componentNames = body.components as string[]; - - if (!componentNames || !Array.isArray(componentNames)) { - return c.json( - { - error: "Invalid request", - details: "components array is required", - }, - 400, - ); - } - - analytics?.trackMcpRequest("api-user", { - method: "POST", - toolName: "get-component-source", - requestSize: componentNames.length, - }); - - const service = await getDataService(c.env); - const results = await service.getComponents(componentNames); - const latestVersion = await service.getLatestVersion(); - - const branch = "alpha"; - const baseUrl = `https://raw.githubusercontent.com/heroui-inc/heroui-native/refs/heads/${branch}`; - - // Fetch source code from GitHub - const sourceResults = await Promise.all( - results.map(async (result) => { - if (!result.data) { - return { - component: result.component, - error: result.error || "Component not found", - }; - } - - // Construct source file path - // Assuming components are in src/components/{component-name}/{component-name}.tsx - const componentPath = result.component - .replace(/([A-Z])/g, "-$1") - .toLowerCase() - .replace(/^-/, ""); - const sourceUrl = `${baseUrl}/src/components/${componentPath}/${componentPath}.tsx`; - - try { - const response = await fetch(sourceUrl); - - if (!response.ok) { - // Try alternate path structure - const altUrl = `${baseUrl}/src/components/${componentPath}/index.tsx`; - const altResponse = await fetch(altUrl); - - if (!altResponse.ok) { - return { - component: result.component, - error: "Source code not available", - }; - } - - const sourceCode = await altResponse.text(); - - return { - component: result.component, - filePath: `src/components/${componentPath}/index.tsx`, - sourceCode, - githubUrl: altUrl - .replace("raw.githubusercontent.com", "github.com") - .replace("/refs/heads/", "/blob/"), - }; - } - - const sourceCode = await response.text(); - - return { - component: result.component, - filePath: `src/components/${componentPath}/${componentPath}.tsx`, - sourceCode, - githubUrl: sourceUrl - .replace("raw.githubusercontent.com", "github.com") - .replace("/refs/heads/", "/blob/"), - }; - } catch (error) { - return { - component: result.component, - error: error instanceof Error ? error.message : "Failed to fetch source code", - }; - } - }), - ); - - const responseTime = Date.now() - startTime; - - analytics?.trackMcpSuccess("api-user", { - method: "POST", - toolName: "get-component-source", - responseTime, - responseSize: JSON.stringify(sourceResults).length, - }); - - // Set cache headers - c.header("Cache-Control", CACHE_CONTROL.LATEST); - - return c.json({ - results: sourceResults, - version: latestVersion || "unknown", - latestVersion: latestVersion || "unknown", - }); - } catch (error) { - const responseTime = Date.now() - startTime; - console.error("Error getting component source:", error); - - analytics?.trackMcpError("api-user", { - method: "POST", - toolName: "get-component-source", - error: error instanceof Error ? error.message : "Unknown error", - responseTime, - }); - - return c.json( - { - error: "Failed to get component source code", - details: error instanceof Error ? error.message : "Unknown error", - }, - 500, - ); - } -}); - export {components}; diff --git a/packages/native-mcp/src/services/component-data-service-r2.ts b/packages/native-mcp/src/services/component-data-service-r2.ts index e500b01..1cd6a6e 100644 --- a/packages/native-mcp/src/services/component-data-service-r2.ts +++ b/packages/native-mcp/src/services/component-data-service-r2.ts @@ -276,28 +276,28 @@ export class ComponentDataServiceR2 { /** * Get version information */ - async getVersionInfo(): Promise { + async getVersionInfo(): Promise> { try { - const data = await this.getFromR2("native/versions.json"); + const data = await this.getFromR2>("native/versions.json"); - return data || null; + return data || {}; } catch (error) { console.error("Error getting version info:", error); - return null; + return {}; } } /** - * Get the latest version + * Get the latest version for a specific package */ - async getLatestVersion(): Promise { + async getLatestVersion(packageName: string = "heroui-native"): Promise { try { const versionInfo = await this.getVersionInfo(); - return versionInfo?.current || null; + return versionInfo[packageName]?.current || null; } catch (error) { - console.error(`Error getting latest version:`, error); + console.error(`Error getting latest version for ${packageName}:`, error); return null; } @@ -320,9 +320,10 @@ export class ComponentDataServiceR2 { if (!response.Contents || response.Contents.length === 0) { // Fallback to metadata if no version files found const versionInfo = await this.getVersionInfo(); + const nativeVersion = versionInfo["heroui-native"]; - if (versionInfo && versionInfo.current) { - return [versionInfo.current, "latest"]; + if (nativeVersion?.current) { + return [nativeVersion.current, "latest"]; } return ["latest"]; @@ -409,15 +410,16 @@ export class ComponentDataServiceR2 { /** * Check version status */ - async checkVersion(currentVersion?: string): Promise<{message: string}> { + async checkVersion(currentVersion?: string, packageName: string = "heroui-native"): Promise<{message: string}> { try { const versionInfo = await this.getVersionInfo(); + const packageVersion = versionInfo[packageName]; - if (!versionInfo) { - return {message: `Unable to get version information`}; + if (!packageVersion) { + return {message: `Unable to get version information for ${packageName}`}; } - const latestVersion = versionInfo.current; + const latestVersion = packageVersion.current; if (!currentVersion) { return {message: `Latest version: ${latestVersion}`}; diff --git a/packages/native-mcp/src/services/theme-service-r2.ts b/packages/native-mcp/src/services/theme-service-r2.ts index a9314c5..0c0400c 100644 --- a/packages/native-mcp/src/services/theme-service-r2.ts +++ b/packages/native-mcp/src/services/theme-service-r2.ts @@ -111,14 +111,29 @@ export class ThemeServiceR2 { } /** - * Get the latest version + * Get the latest version from R2 versions.json */ - async getLatestVersion(): Promise { - const themeSystem = await this.getThemeSystem(); - if (!themeSystem) { + async getLatestVersion(packageName: string = "heroui-native-theme"): Promise { + try { + const response = await this.client.send( + new GetObjectCommand({ + Bucket: this.bucketName, + Key: "native/versions.json", + }), + ); + + if (response.Body) { + const bodyString = await response.Body.transformToString(); + const versionInfo = JSON.parse(bodyString); + + return versionInfo?.[packageName]?.current || null; + } + return null; - } + } catch (error) { + console.error(`Error fetching latest version for ${packageName}:`, error); - return themeSystem.version; + return null; + } } } diff --git a/packages/react-mcp/package.json b/packages/react-mcp/package.json index bdd936b..3b05f4d 100644 --- a/packages/react-mcp/package.json +++ b/packages/react-mcp/package.json @@ -58,7 +58,7 @@ "clean": "rm -rf dist", "prepublishOnly": "pnpm build", "changelog": "conventional-changelog -p angular -i CHANGELOG.md -s --commit-path .", - "release": "bumpp --execute='pnpm run changelog' --all --tag='react-mcp-v%s'", + "release": "bumpp --execute='pnpm run changelog' --all --tag='react-mcp-v%s' --commit='chore(react-mcp): release v%s'", "release:check": "pnpm run lint && pnpm run typecheck && pnpm run build" }, "dependencies": {