mirror of
https://github.com/shadcn-ui/ui.git
synced 2026-07-01 08:34:12 +00:00
feat(shadcn): add mcp init command
This commit is contained in:
@@ -25,6 +25,10 @@ const TOP_LEVEL_SECTIONS = [
|
||||
name: "Registry",
|
||||
href: "/docs/registry",
|
||||
},
|
||||
{
|
||||
name: "MCP Server",
|
||||
href: "/docs/mcp",
|
||||
},
|
||||
]
|
||||
const EXCLUDED_SECTIONS = ["installation", "dark-mode"]
|
||||
const EXCLUDED_PAGES = ["/docs"]
|
||||
|
||||
@@ -13,6 +13,22 @@ import {
|
||||
PopoverTrigger,
|
||||
} from "@/registry/new-york-v4/ui/popover"
|
||||
|
||||
const TOP_LEVEL_SECTIONS = [
|
||||
{ name: "Get Started", href: "/docs" },
|
||||
{
|
||||
name: "Components",
|
||||
href: "/docs/components",
|
||||
},
|
||||
{
|
||||
name: "Registry",
|
||||
href: "/docs/registry",
|
||||
},
|
||||
{
|
||||
name: "MCP Server",
|
||||
href: "/docs/mcp",
|
||||
},
|
||||
]
|
||||
|
||||
export function MobileNav({
|
||||
tree,
|
||||
items,
|
||||
@@ -79,6 +95,18 @@ export function MobileNav({
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="text-muted-foreground text-sm font-medium">
|
||||
Sections
|
||||
</div>
|
||||
<div className="flex flex-col gap-3">
|
||||
{TOP_LEVEL_SECTIONS.map(({ name, href }) => (
|
||||
<MobileLink key={name} href={href} onOpenChange={setOpen}>
|
||||
{name}
|
||||
</MobileLink>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col gap-8">
|
||||
{tree?.children?.map((group, index) => {
|
||||
if (group.type === "folder") {
|
||||
|
||||
255
apps/v4/content/docs/(root)/mcp.mdx
Normal file
255
apps/v4/content/docs/(root)/mcp.mdx
Normal file
@@ -0,0 +1,255 @@
|
||||
---
|
||||
title: MCP Server
|
||||
description: Use the shadcn MCP server to browse, search, and install components from registries
|
||||
---
|
||||
|
||||
The shadcn MCP (Model Context Protocol) server allows AI assistants to interact with items from registries. You can browse available components, search for specific resources, and install them directly into your project using natural language.
|
||||
|
||||
For example, you can ask an AI assistant to "Build a landing page using components from the @acme registry" or "Find me a login form from the shadcn registry".
|
||||
|
||||
## Quick Start
|
||||
|
||||
<Tabs defaultValue="claude">
|
||||
<TabsList>
|
||||
<TabsTrigger value="claude">Claude Code</TabsTrigger>
|
||||
<TabsTrigger value="cursor">Cursor</TabsTrigger>
|
||||
<TabsTrigger value="vscode">VS Code</TabsTrigger>
|
||||
</TabsList>
|
||||
<TabsContent value="claude" className="mt-4">
|
||||
**Run the following command** in your project:
|
||||
```bash
|
||||
npx shadcn@latest mcp init --client claude
|
||||
```
|
||||
|
||||
**Restart Claude Code** and try the following prompts:
|
||||
- Show me all available components in the shadcn registry
|
||||
- Add the button, dialog and card components to my project
|
||||
- Create a contact form using components from the shadcn registry
|
||||
|
||||
**Note:** You can use `/mcp` command in Claude Code to debug the MCP server.
|
||||
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="cursor" className="mt-4">
|
||||
**Run the following command** in your project:
|
||||
```bash
|
||||
npx shadcn@latest mcp init --client cursor
|
||||
```
|
||||
|
||||
Open **Cursor Settings** and **Enable the MCP server** for shadcn. Then try the following prompts:
|
||||
- Show me all available components in the shadcn registry
|
||||
- Add the button, dialog and card components to my project
|
||||
- Create a contact form using components from the shadcn registry
|
||||
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="vscode" className="mt-4">
|
||||
**Run the following command** in your project:
|
||||
```bash
|
||||
npx shadcn@latest mcp init --client vscode
|
||||
```
|
||||
|
||||
Open `.vscode/mcp.json` and click **Start** next to the shadcn server. Then try the following prompts with GitHub Copilot:
|
||||
- Show me all available components in the shadcn registry
|
||||
- Add the button, dialog and card components to my project
|
||||
- Create a contact form using components from the shadcn registry
|
||||
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
|
||||
## What is MCP?
|
||||
|
||||
[Model Context Protocol (MCP)](https://modelcontextprotocol.io) is an open protocol that enables AI assistants to securely connect to external data sources and tools. With the shadcn MCP server, your AI assistant gains direct access to:
|
||||
|
||||
- **Browse Components** - List all available components, blocks, and templates from any configured registry
|
||||
- **Search Across Registries** - Find specific components by name or functionality across multiple sources
|
||||
- **Install with Natural Language** - Add components using simple conversational prompts like "add a login form"
|
||||
- **Support for Multiple Registries** - Access public registries, private company libraries, and third-party sources
|
||||
|
||||
## How It Works
|
||||
|
||||
The MCP server acts as a bridge between your AI assistant, component registries and the shadcn CLI.
|
||||
|
||||
1. **Registry Connection** - MCP connects to configured registries (shadcn/ui, private registries, third-party sources)
|
||||
2. **Natural Language** - You describe what you need in plain English
|
||||
3. **AI Processing** - The assistant translates your request into registry commands
|
||||
4. **Component Delivery** - Resources are fetched and installed in your project
|
||||
|
||||
### Supported Registries
|
||||
|
||||
The shadcn MCP server works out of the box with any shadcn-compatible registry.
|
||||
|
||||
- **shadcn/ui Registry** - The default registry with all shadcn/ui components
|
||||
- **Private Registries** - Your company's internal component libraries
|
||||
- **Third-Party Registries** - Any registry following the shadcn registry specification
|
||||
- **Namespaced Registries** - Multiple registries configured with `@namespace` syntax
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before using MCP, ensure you have:
|
||||
|
||||
1. **shadcn CLI installed** in your project: (if you don't have it, run `npm install -D shadcn`)
|
||||
|
||||
2. **A valid components.json** file in your project root (created via `npx shadcn@latest init`)
|
||||
|
||||
## Configuration
|
||||
|
||||
### Claude Code
|
||||
|
||||
To use MCP with Claude Code, add the shadcn server to your project's `.mcp.json` configuration file:
|
||||
|
||||
```json title=".mcp.json"
|
||||
{
|
||||
"mcpServers": {
|
||||
"shadcn": {
|
||||
"command": "npx",
|
||||
"args": ["shadcn@latest", "mcp"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
After adding the configuration, restart Claude Code for the changes to take effect. See the [Claude Code MCP documentation](https://docs.anthropic.com/en/docs/claude-code/mcp) for more details.
|
||||
|
||||
### Cursor
|
||||
|
||||
To configure MCP in Cursor, add the shadcn server to your project's `.cursor/mcp.json` configuration file:
|
||||
|
||||
```json title=".cursor/mcp.json"
|
||||
{
|
||||
"mcpServers": {
|
||||
"shadcn": {
|
||||
"command": "npx",
|
||||
"args": ["shadcn@latest", "mcp"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
After adding the configuration, enable the MCP server in Cursor Settings (Restart Cursor if needed). See the [Cursor MCP documentation](https://docs.cursor.com/en/context/mcp#using-mcp-json) for more details.
|
||||
|
||||
### VS Code
|
||||
|
||||
To configure MCP in VS Code with GitHub Copilot, add the shadcn server to your project's `.vscode/mcp.json` configuration file:
|
||||
|
||||
```json title=".vscode/mcp.json"
|
||||
{
|
||||
"mcpServers": {
|
||||
"shadcn": {
|
||||
"command": "npx",
|
||||
"args": ["shadcn@latest", "mcp"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
After adding the configuration, restart VS Code for the changes to take effect. See the [VS Code MCP documentation](https://code.visualstudio.com/docs/copilot/chat/mcp-servers) for more details.
|
||||
|
||||
### Zed
|
||||
|
||||
To configure MCP in Zed, add the shadcn server to your project's `.zed/settings.json` configuration file:
|
||||
|
||||
```json title=".zed/settings.json"
|
||||
{
|
||||
"context_servers": {
|
||||
"shadcn": {
|
||||
"command": "npx",
|
||||
"args": ["shadcn@latest", "mcp"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
After adding the configuration, restart Zed for the changes to take effect. See the [Zed MCP documentation](https://zed.dev/docs/ai/mcp) for more details.
|
||||
|
||||
## Configuring Registries
|
||||
|
||||
The MCP server supports multiple registries through your project's `components.json` configuration. This allows you to access components from various sources including private registries and third-party providers.
|
||||
|
||||
<Callout>
|
||||
**Note:** By default, MCP connects to the shadcn/ui registry. No configuration
|
||||
is needed to access standard shadcn/ui components.
|
||||
</Callout>
|
||||
|
||||
Configure additional registries in your `components.json`:
|
||||
|
||||
```json title="components.json"
|
||||
{
|
||||
"registries": {
|
||||
"@acme": "https://registry.acme.com/{name}.json",
|
||||
"@internal": {
|
||||
"url": "https://internal.company.com/{name}.json",
|
||||
"headers": {
|
||||
"Authorization": "Bearer ${REGISTRY_TOKEN}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Authentication
|
||||
|
||||
For private registries requiring authentication, set environment variables in your `.env.local`:
|
||||
|
||||
```bash title=".env.local"
|
||||
REGISTRY_TOKEN=your_token_here
|
||||
API_KEY=your_api_key_here
|
||||
```
|
||||
|
||||
For more details on registry configuration, see the [Namespaces documentation](/docs/registry/namespace).
|
||||
|
||||
## Example Prompts
|
||||
|
||||
Once MCP is configured, you can use natural language to interact with registries:
|
||||
|
||||
### Browse & Search
|
||||
|
||||
- "Show me all available components in the shadcn registry"
|
||||
- "Find me a login form from the shadcn registry"
|
||||
|
||||
### Install Components
|
||||
|
||||
- "Add the button component to my project"
|
||||
- "Create a login form using shadcn components"
|
||||
|
||||
### Work with Namespaces
|
||||
|
||||
- "Show me components from @acme registry"
|
||||
- "Install @internal/auth-form"
|
||||
- "Build me a landing page using hero, features and testimonials components from the @acme registry"
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### MCP Not Responding
|
||||
|
||||
If the MCP server isn't responding to prompts:
|
||||
|
||||
1. **Check Configuration** - Verify the MCP server is properly configured and enabled in your MCP client
|
||||
2. **Restart MCP Client** - Restart your MCP client after configuration changes
|
||||
3. **Verify Installation** - Ensure `shadcn` is installed in your project
|
||||
4. **Check Network** - Confirm you can access the configured registries
|
||||
|
||||
### Registry Access Issues
|
||||
|
||||
If components aren't loading from registries:
|
||||
|
||||
1. **Check components.json** - Verify registry URLs are correct
|
||||
2. **Test Authentication** - Ensure environment variables are set for private registries
|
||||
3. **Verify Registry** - Confirm the registry is online and accessible
|
||||
4. **Check Namespace** - Ensure namespace syntax is correct (`@namespace/component`)
|
||||
|
||||
### Installation Failures
|
||||
|
||||
If components fail to install:
|
||||
|
||||
1. **Check Project Setup** - Ensure you have a valid `components.json` file
|
||||
2. **Verify Paths** - Confirm the target directories exist
|
||||
3. **Check Permissions** - Ensure write permissions for component directories
|
||||
4. **Review Dependencies** - Check that required dependencies are installed
|
||||
|
||||
## Learn More
|
||||
|
||||
- [Registry Documentation](/docs/registry) - Complete guide to shadcn registries
|
||||
- [Namespaces](/docs/registry/namespace) - Configure multiple registry sources
|
||||
- [Authentication](/docs/registry/authentication) - Secure your private registries
|
||||
- [MCP Specification](https://modelcontextprotocol.io) - Learn about Model Context Protocol
|
||||
85
apps/v4/content/docs/registry/mcp.mdx
Normal file
85
apps/v4/content/docs/registry/mcp.mdx
Normal file
@@ -0,0 +1,85 @@
|
||||
---
|
||||
title: MCP Server
|
||||
description: MCP support for registry developers
|
||||
---
|
||||
|
||||
The [shadcn MCP server](/docs/mcp) works out of the box with any shadcn-compatible registry. You do not need to do anything special to enable MCP support for your registry.
|
||||
|
||||
See the [MCP documentation](/docs/mcp) for more information on how to use the shadcn MCP server.
|
||||
|
||||
## Configuring MCP
|
||||
|
||||
Ask your registry consumers to configure your registry in their `components.json` file and install the shadcn MCP server:
|
||||
|
||||
<Tabs defaultValue="claude">
|
||||
<TabsList>
|
||||
<TabsTrigger value="claude">Claude Code</TabsTrigger>
|
||||
<TabsTrigger value="cursor">Cursor</TabsTrigger>
|
||||
<TabsTrigger value="vscode">VS Code</TabsTrigger>
|
||||
</TabsList>
|
||||
<TabsContent value="claude" className="mt-4">
|
||||
|
||||
**Configure your registry** in your `components.json` file:
|
||||
```json title="components.json"
|
||||
{
|
||||
"registries": {
|
||||
"@acme": "https://acme.com/r/{name}.json"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Run the following command** in your project:
|
||||
```bash
|
||||
npx shadcn@latest mcp init --client claude
|
||||
```
|
||||
|
||||
**Restart Claude Code** and try the following prompts:
|
||||
- Show me all available components in the @acme registry
|
||||
- Create a contact form using components from the @acme registry
|
||||
|
||||
**Note:** You can use `/mcp` command in Claude Code to debug the MCP server.
|
||||
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="cursor" className="mt-4">
|
||||
**Configure your registry** in your `components.json` file:
|
||||
```json title="components.json"
|
||||
{
|
||||
"registries": {
|
||||
"@acme": "https://acme.com/r/{name}.json"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Run the following command** in your project:
|
||||
```bash
|
||||
npx shadcn@latest mcp init --client cursor
|
||||
```
|
||||
|
||||
Open **Cursor Settings** and **Enable the MCP server** for shadcn. Then try the following prompts:
|
||||
- Show me all available components in the @acme registry
|
||||
- Create a contact form using components from the @acme registry
|
||||
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="vscode" className="mt-4">
|
||||
**Configure your registry** in your `components.json` file:
|
||||
```json title="components.json"
|
||||
{
|
||||
"registries": {
|
||||
"@acme": "https://acme.com/r/{name}.json"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Run the following command** in your project:
|
||||
```bash
|
||||
npx shadcn@latest mcp init --client vscode
|
||||
```
|
||||
|
||||
Open `.vscode/mcp.json` and click **Start** next to the shadcn server. Then try the following prompts with GitHub Copilot:
|
||||
- Show me all available components in the @acme registry
|
||||
- Create a contact form using components from the @acme registry
|
||||
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
@@ -6,6 +6,7 @@
|
||||
"namespace",
|
||||
"authentication",
|
||||
"examples",
|
||||
"mcp",
|
||||
"open-in-v0",
|
||||
"registry-json",
|
||||
"registry-item-json"
|
||||
|
||||
@@ -310,7 +310,7 @@ export const mdxComponents = {
|
||||
}: React.ComponentProps<typeof TabsTrigger>) => (
|
||||
<TabsTrigger
|
||||
className={cn(
|
||||
"text-muted-foreground data-[state=active]:text-foreground px-0 text-base data-[state=active]:shadow-none dark:data-[state=active]:border-transparent dark:data-[state=active]:bg-transparent",
|
||||
"text-muted-foreground data-[state=active]:text-foreground data-[state=active]:border-primary dark:data-[state=active]:border-primary rounded-none border-0 border-b-2 border-transparent px-0 pb-3 text-base data-[state=active]:bg-transparent data-[state=active]:shadow-none dark:data-[state=active]:bg-transparent",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
|
||||
@@ -73,6 +73,11 @@ const nextConfig = {
|
||||
destination: "/docs/:path*.md",
|
||||
permanent: true,
|
||||
},
|
||||
{
|
||||
source: "/mcp",
|
||||
destination: "/docs/mcp",
|
||||
permanent: false,
|
||||
},
|
||||
]
|
||||
},
|
||||
rewrites() {
|
||||
|
||||
@@ -1,13 +1,82 @@
|
||||
import { promises as fs } from "fs"
|
||||
import path from "path"
|
||||
import { server } from "@/src/mcp"
|
||||
import { loadEnvFiles } from "@/src/utils/env-loader"
|
||||
import { getConfig } from "@/src/utils/get-config"
|
||||
import { getPackageManager } from "@/src/utils/get-package-manager"
|
||||
import { handleError } from "@/src/utils/handle-error"
|
||||
import { logger } from "@/src/utils/logger"
|
||||
import { spinner } from "@/src/utils/spinner"
|
||||
import { updateDependencies } from "@/src/utils/updaters/update-dependencies"
|
||||
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
||||
import { Command } from "commander"
|
||||
import deepmerge from "deepmerge"
|
||||
import { execa } from "execa"
|
||||
import fsExtra from "fs-extra"
|
||||
import prompts from "prompts"
|
||||
import z from "zod"
|
||||
|
||||
const SHADCN_MCP_VERSION = "beta"
|
||||
|
||||
const CLIENTS = [
|
||||
{
|
||||
name: "claude",
|
||||
label: "Claude Code",
|
||||
configPath: ".mcp.json",
|
||||
config: {
|
||||
mcpServers: {
|
||||
shadcn: {
|
||||
command: "npx",
|
||||
args: [`shadcn@${SHADCN_MCP_VERSION}`, "mcp"],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "cursor",
|
||||
label: "Cursor",
|
||||
configPath: ".cursor/mcp.json",
|
||||
config: {
|
||||
mcpServers: {
|
||||
shadcn: {
|
||||
command: "npx",
|
||||
args: [`shadcn@${SHADCN_MCP_VERSION}`, "mcp"],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "vscode",
|
||||
label: "VS Code",
|
||||
configPath: ".vscode/mcp.json",
|
||||
config: {
|
||||
servers: {
|
||||
shadcn: {
|
||||
command: "npx",
|
||||
args: [`shadcn@${SHADCN_MCP_VERSION}`, "mcp"],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
// {
|
||||
// name: "zed",
|
||||
// label: "Zed Editor",
|
||||
// configPath: ".zed/settings.json",
|
||||
// config: {
|
||||
// context_servers: {
|
||||
// shadcn: {
|
||||
// source: "custom",
|
||||
// command: "npx",
|
||||
// args: [`shadcn@${SHADCN_MCP_VERSION}`, "mcp"],
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
] as const
|
||||
|
||||
export const mcp = new Command()
|
||||
.name("mcp")
|
||||
.description("starts the registry MCP server")
|
||||
.description("MCP server and configuration commands")
|
||||
.option(
|
||||
"-c, --cwd <cwd>",
|
||||
"the working directory. defaults to the current directory.",
|
||||
@@ -23,3 +92,115 @@ export const mcp = new Command()
|
||||
handleError(error)
|
||||
}
|
||||
})
|
||||
|
||||
const mcpInitOptionsSchema = z.object({
|
||||
client: z.enum(["claude", "cursor", "vscode", "zed"]),
|
||||
cwd: z.string(),
|
||||
})
|
||||
|
||||
mcp
|
||||
.command("init")
|
||||
.description("Initialize MCP configuration for your client")
|
||||
.option(
|
||||
"--client <client>",
|
||||
`MCP client (${CLIENTS.map((c) => c.name).join(", ")})`
|
||||
)
|
||||
.action(async (opts, command) => {
|
||||
try {
|
||||
// Get the cwd from parent command
|
||||
const parentOpts = command.parent?.opts() || {}
|
||||
const cwd = parentOpts.cwd || process.cwd()
|
||||
|
||||
let client = opts.client
|
||||
|
||||
if (!client) {
|
||||
const response = await prompts({
|
||||
type: "select",
|
||||
name: "client",
|
||||
message: "Which MCP client are you using?",
|
||||
choices: CLIENTS.map((c) => ({
|
||||
title: c.label,
|
||||
value: c.name,
|
||||
})),
|
||||
})
|
||||
|
||||
if (!response.client) {
|
||||
logger.break()
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
client = response.client
|
||||
}
|
||||
|
||||
const options = mcpInitOptionsSchema.parse({
|
||||
client,
|
||||
cwd,
|
||||
})
|
||||
|
||||
const configSpinner = spinner("Configuring MCP server...").start()
|
||||
const configPath = await runMcpInit(options)
|
||||
configSpinner.succeed("Configuring MCP server.")
|
||||
|
||||
const config = await getConfig(options.cwd)
|
||||
if (config) {
|
||||
await updateDependencies([], ["shadcn"], config, {
|
||||
silent: false,
|
||||
})
|
||||
} else {
|
||||
const packageManager = await getPackageManager(options.cwd)
|
||||
const installCommand = packageManager === "npm" ? "install" : "add"
|
||||
const devFlag = packageManager === "npm" ? "--save-dev" : "-D"
|
||||
|
||||
const installSpinner = spinner("Installing dependencies...").start()
|
||||
await execa(packageManager, [installCommand, devFlag, "shadcn"], {
|
||||
cwd: options.cwd,
|
||||
})
|
||||
installSpinner.succeed("Installing dependencies.")
|
||||
}
|
||||
|
||||
logger.break()
|
||||
logger.success(`Configuration saved to ${configPath}.`)
|
||||
logger.break()
|
||||
} catch (error) {
|
||||
handleError(error)
|
||||
}
|
||||
})
|
||||
|
||||
const overwriteMerge = (_: any[], sourceArray: any[]) => sourceArray
|
||||
|
||||
async function runMcpInit(options: z.infer<typeof mcpInitOptionsSchema>) {
|
||||
const { client, cwd } = options
|
||||
|
||||
const clientInfo = CLIENTS.find((c) => c.name === client)
|
||||
if (!clientInfo) {
|
||||
throw new Error(
|
||||
`Unknown client: ${client}. Available clients: ${CLIENTS.map(
|
||||
(c) => c.name
|
||||
).join(", ")}`
|
||||
)
|
||||
}
|
||||
|
||||
const configPath = path.join(cwd, clientInfo.configPath)
|
||||
|
||||
let existingConfig = {}
|
||||
try {
|
||||
const content = await fs.readFile(configPath, "utf-8")
|
||||
existingConfig = JSON.parse(content)
|
||||
} catch {}
|
||||
|
||||
const mergedConfig = deepmerge(
|
||||
existingConfig,
|
||||
clientInfo.config as Record<string, unknown>,
|
||||
{ arrayMerge: overwriteMerge }
|
||||
)
|
||||
|
||||
const dir = path.dirname(configPath)
|
||||
await fsExtra.ensureDir(dir)
|
||||
await fs.writeFile(
|
||||
configPath,
|
||||
JSON.stringify(mergedConfig, null, 2) + "\n",
|
||||
"utf-8"
|
||||
)
|
||||
|
||||
return clientInfo.configPath
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user