sh-ui-cli 0.21.2 → 0.22.0
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.
- package/README.md +73 -0
- package/bin/sh-ui.mjs +11 -2
- package/data/changelog/versions.json +13 -0
- package/package.json +1 -1
- package/src/mcp-init.mjs +141 -0
- package/src/mcp.mjs +1 -1
package/README.md
CHANGED
|
@@ -51,6 +51,79 @@ npx sh-ui list
|
|
|
51
51
|
npx sh-ui remove button
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
+
### mcp — AI 에게 sh-ui 를 알려주기 (v0.21.0+)
|
|
55
|
+
|
|
56
|
+
`sh-ui mcp` 는 [Model Context Protocol](https://modelcontextprotocol.io) 서버를 stdio 로 시작한다. IDE-내 AI(Claude Code, Cursor, Windsurf 등) 가 sh-ui 컴포넌트를 자동으로 검색·설치할 수 있게 7개 툴을 노출한다.
|
|
57
|
+
|
|
58
|
+
**한 번만 등록하면 끝** — 빈 폴더에서도 _"다크 모던 sh-ui 로 세팅하고 button 추가해줘"_ 만 말하면 AI 가 알아서 처리.
|
|
59
|
+
|
|
60
|
+
#### 자동 등록 (권장, v0.22.0+)
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
# 프로젝트 루트에서 — IDE 별로 한 줄
|
|
64
|
+
npx sh-ui mcp init --client claude-code # → .mcp.json
|
|
65
|
+
npx sh-ui mcp init --client cursor # → .cursor/mcp.json
|
|
66
|
+
npx sh-ui mcp init --client claude-desktop # → 사용자 전역 (재시작 필요)
|
|
67
|
+
|
|
68
|
+
# 사용자 전역 설정에 등록하려면
|
|
69
|
+
npx sh-ui mcp init --client claude-code --scope user
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
기존 설정 파일이 있으면 다른 MCP 서버 엔트리를 보존하며 `sh-ui` 만 머지·갱신.
|
|
73
|
+
|
|
74
|
+
#### 수동 등록
|
|
75
|
+
|
|
76
|
+
**Claude Code** — `~/.claude/mcp.json` 또는 프로젝트 `.mcp.json`:
|
|
77
|
+
|
|
78
|
+
```json
|
|
79
|
+
{
|
|
80
|
+
"mcpServers": {
|
|
81
|
+
"sh-ui": {
|
|
82
|
+
"command": "npx",
|
|
83
|
+
"args": ["-y", "sh-ui-cli", "mcp"]
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
**Cursor** — `~/.cursor/mcp.json` 또는 `.cursor/mcp.json`:
|
|
90
|
+
|
|
91
|
+
```json
|
|
92
|
+
{
|
|
93
|
+
"mcpServers": {
|
|
94
|
+
"sh-ui": {
|
|
95
|
+
"command": "npx",
|
|
96
|
+
"args": ["-y", "sh-ui-cli", "mcp"]
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
**Claude Desktop** — `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS):
|
|
103
|
+
|
|
104
|
+
```json
|
|
105
|
+
{
|
|
106
|
+
"mcpServers": {
|
|
107
|
+
"sh-ui": {
|
|
108
|
+
"command": "npx",
|
|
109
|
+
"args": ["-y", "sh-ui-cli", "mcp"]
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
#### 노출되는 툴
|
|
116
|
+
|
|
117
|
+
| 툴 | 설명 |
|
|
118
|
+
|---|---|
|
|
119
|
+
| `sh_ui_describe_init` | platform/base/radius/mode 선택지 + 한글 설명 — 자연어 의도("다크 모던") → enum 매핑용 |
|
|
120
|
+
| `sh_ui_init` | `sh-ui.config.json` 생성 (비대화형) |
|
|
121
|
+
| `sh_ui_list_components` | 플랫폼별 전체 컴포넌트 + 요약 + deps |
|
|
122
|
+
| `sh_ui_get_component` | 단일 컴포넌트 메타·소스파일·deps |
|
|
123
|
+
| `sh_ui_add_component` | 컴포넌트 설치 (외부 패키지 자동 설치) |
|
|
124
|
+
| `sh_ui_remove_component` | 삭제 (수정 파일 보호) |
|
|
125
|
+
| `sh_ui_get_changelog` | 변경 내역 조회 |
|
|
126
|
+
|
|
54
127
|
## 지원 플랫폼
|
|
55
128
|
|
|
56
129
|
- **React (Next.js)** — `src/shared/ui/` 또는 `sh-ui.config.json` 에 지정된 경로로 복사
|
package/bin/sh-ui.mjs
CHANGED
|
@@ -14,6 +14,8 @@ const usage = `사용법:
|
|
|
14
14
|
sh-ui list 현재 설치된 컴포넌트 목록 표시
|
|
15
15
|
sh-ui remove <component...> 설치된 컴포넌트 파일 삭제
|
|
16
16
|
sh-ui mcp MCP 서버(stdio) 시작 — IDE-내 AI용
|
|
17
|
+
sh-ui mcp init --client <name> IDE MCP 설정 파일에 sh-ui 엔트리 자동 추가
|
|
18
|
+
(claude-code | cursor | claude-desktop)
|
|
17
19
|
옵션:
|
|
18
20
|
--skip-install (add) 외부 패키지 자동 설치 생략
|
|
19
21
|
--diff (add) 파일을 쓰지 않고 변경 내역만 출력
|
|
@@ -45,8 +47,15 @@ try {
|
|
|
45
47
|
break;
|
|
46
48
|
}
|
|
47
49
|
case "mcp": {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
+
// `sh-ui mcp init ...` → 설정 파일에 엔트리 추가
|
|
51
|
+
// `sh-ui mcp` → MCP 서버 시작
|
|
52
|
+
if (rest[0] === "init") {
|
|
53
|
+
const { mcpInit } = await import("../src/mcp-init.mjs");
|
|
54
|
+
await mcpInit({ cwd: process.cwd(), args: rest.slice(1) });
|
|
55
|
+
} else {
|
|
56
|
+
const { startMcpServer } = await import("../src/mcp.mjs");
|
|
57
|
+
await startMcpServer();
|
|
58
|
+
}
|
|
50
59
|
break;
|
|
51
60
|
}
|
|
52
61
|
case "remove":
|
|
@@ -2,6 +2,19 @@
|
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"$description": "sh-ui 릴리즈 노트 단일 소스. docs(React)와 showcase(Flutter)가 함께 읽는다. 새 릴리즈마다 맨 앞에 추가.",
|
|
4
4
|
"versions": [
|
|
5
|
+
{
|
|
6
|
+
"version": "0.22.0",
|
|
7
|
+
"date": "2026-04-27",
|
|
8
|
+
"title": "sh-ui mcp init — IDE MCP 설정 자동 등록",
|
|
9
|
+
"type": "minor",
|
|
10
|
+
"highlights": [
|
|
11
|
+
"sh-ui mcp init --client <claude-code|cursor|claude-desktop> 추가 — IDE 별 MCP 설정 파일을 자동으로 찾아 sh-ui 엔트리 머지",
|
|
12
|
+
"스코프 분기 — 기본 project(.mcp.json / .cursor/mcp.json), --scope user 로 전역(~/.claude/mcp.json 등) 선택 가능. claude-desktop 은 user 전용(OS 별 경로 자동 분기)",
|
|
13
|
+
"기존 JSON 보존 — 다른 MCP 서버 엔트리·기타 키를 건드리지 않고 sh-ui 만 머지·갱신",
|
|
14
|
+
"수동 JSON 편집 없이 npx sh-ui mcp init --client cursor 한 줄로 끝"
|
|
15
|
+
],
|
|
16
|
+
"url": "https://github.com/sanghyeonKim0201/sh-ui/releases/tag/v0.22.0"
|
|
17
|
+
},
|
|
5
18
|
{
|
|
6
19
|
"version": "0.21.2",
|
|
7
20
|
"date": "2026-04-27",
|
package/package.json
CHANGED
package/src/mcp-init.mjs
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
// sh-ui mcp init — 타깃 IDE 의 MCP 설정 파일에 sh-ui 엔트리를 자동 추가.
|
|
2
|
+
//
|
|
3
|
+
// 지원 클라이언트:
|
|
4
|
+
// claude-code — project: <cwd>/.mcp.json, user: ~/.claude/mcp.json
|
|
5
|
+
// cursor — project: <cwd>/.cursor/mcp.json, user: ~/.cursor/mcp.json
|
|
6
|
+
// claude-desktop — user 만 (OS 별 경로 자동 분기)
|
|
7
|
+
//
|
|
8
|
+
// 동작: 기존 JSON 의 mcpServers.sh-ui 를 머지(있으면 덮어쓰기), 디렉토리 자동 생성.
|
|
9
|
+
|
|
10
|
+
import { readFile, writeFile, mkdir } from "node:fs/promises";
|
|
11
|
+
import { existsSync } from "node:fs";
|
|
12
|
+
import { dirname, resolve, relative } from "node:path";
|
|
13
|
+
import { homedir, platform as osPlatform } from "node:os";
|
|
14
|
+
|
|
15
|
+
const CLIENTS = ["claude-code", "cursor", "claude-desktop"];
|
|
16
|
+
|
|
17
|
+
const SH_UI_ENTRY = {
|
|
18
|
+
command: "npx",
|
|
19
|
+
args: ["-y", "sh-ui-cli", "mcp"],
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/** 클라이언트·스코프별 설정 파일 절대 경로. */
|
|
23
|
+
function resolveConfigPath(client, scope, cwd) {
|
|
24
|
+
const home = homedir();
|
|
25
|
+
if (client === "claude-code") {
|
|
26
|
+
return scope === "user"
|
|
27
|
+
? resolve(home, ".claude", "mcp.json")
|
|
28
|
+
: resolve(cwd, ".mcp.json");
|
|
29
|
+
}
|
|
30
|
+
if (client === "cursor") {
|
|
31
|
+
return scope === "user"
|
|
32
|
+
? resolve(home, ".cursor", "mcp.json")
|
|
33
|
+
: resolve(cwd, ".cursor", "mcp.json");
|
|
34
|
+
}
|
|
35
|
+
if (client === "claude-desktop") {
|
|
36
|
+
if (scope !== "user") {
|
|
37
|
+
throw new Error(
|
|
38
|
+
"claude-desktop 은 user 스코프만 지원합니다. --scope user 또는 --scope 생략.",
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
const os = osPlatform();
|
|
42
|
+
if (os === "darwin") {
|
|
43
|
+
return resolve(
|
|
44
|
+
home,
|
|
45
|
+
"Library",
|
|
46
|
+
"Application Support",
|
|
47
|
+
"Claude",
|
|
48
|
+
"claude_desktop_config.json",
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
if (os === "win32") {
|
|
52
|
+
const appData = process.env.APPDATA ?? resolve(home, "AppData", "Roaming");
|
|
53
|
+
return resolve(appData, "Claude", "claude_desktop_config.json");
|
|
54
|
+
}
|
|
55
|
+
// linux + 기타
|
|
56
|
+
return resolve(home, ".config", "Claude", "claude_desktop_config.json");
|
|
57
|
+
}
|
|
58
|
+
throw new Error(`알 수 없는 클라이언트: ${client}. 허용: ${CLIENTS.join(", ")}`);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** 클라이언트별 기본 스코프. claude-desktop 은 user 강제. */
|
|
62
|
+
function defaultScope(client) {
|
|
63
|
+
return client === "claude-desktop" ? "user" : "project";
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** JSON 읽기 (없으면 빈 객체). 깨진 JSON 은 명시적 에러. */
|
|
67
|
+
async function readJsonOrEmpty(path) {
|
|
68
|
+
if (!existsSync(path)) return {};
|
|
69
|
+
let raw;
|
|
70
|
+
try {
|
|
71
|
+
raw = await readFile(path, "utf8");
|
|
72
|
+
} catch (err) {
|
|
73
|
+
throw new Error(`설정 파일 읽기 실패: ${path}\n ${err.message}`);
|
|
74
|
+
}
|
|
75
|
+
if (raw.trim() === "") return {};
|
|
76
|
+
try {
|
|
77
|
+
return JSON.parse(raw);
|
|
78
|
+
} catch (err) {
|
|
79
|
+
throw new Error(
|
|
80
|
+
`기존 ${path} 가 유효한 JSON 이 아닙니다. 수동으로 고치고 다시 시도하세요.\n ${err.message}`,
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export async function mcpInit({ cwd, args }) {
|
|
86
|
+
const flags = parseFlags(args);
|
|
87
|
+
const client = flags.client;
|
|
88
|
+
if (!client) {
|
|
89
|
+
throw new Error(
|
|
90
|
+
`--client 가 필요합니다. 허용: ${CLIENTS.join(", ")}\n` +
|
|
91
|
+
`예: sh-ui mcp init --client claude-code`,
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
if (!CLIENTS.includes(client)) {
|
|
95
|
+
throw new Error(
|
|
96
|
+
`알 수 없는 클라이언트: '${client}'. 허용: ${CLIENTS.join(", ")}`,
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const scope = flags.scope ?? defaultScope(client);
|
|
101
|
+
if (!["user", "project"].includes(scope)) {
|
|
102
|
+
throw new Error(`--scope 는 'user' 또는 'project' 여야 합니다.`);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const configPath = resolveConfigPath(client, scope, cwd);
|
|
106
|
+
const config = await readJsonOrEmpty(configPath);
|
|
107
|
+
|
|
108
|
+
if (!config.mcpServers || typeof config.mcpServers !== "object") {
|
|
109
|
+
config.mcpServers = {};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const before = config.mcpServers["sh-ui"];
|
|
113
|
+
config.mcpServers["sh-ui"] = SH_UI_ENTRY;
|
|
114
|
+
|
|
115
|
+
await mkdir(dirname(configPath), { recursive: true });
|
|
116
|
+
await writeFile(configPath, JSON.stringify(config, null, 2) + "\n", "utf8");
|
|
117
|
+
|
|
118
|
+
const rel = relative(cwd, configPath);
|
|
119
|
+
const display = rel.startsWith("..") ? configPath : rel;
|
|
120
|
+
const verb = before ? "갱신" : "추가";
|
|
121
|
+
console.log(`✓ sh-ui MCP 엔트리 ${verb} → ${display}`);
|
|
122
|
+
console.log(` client: ${client} (scope: ${scope})`);
|
|
123
|
+
if (client === "claude-code" || client === "cursor") {
|
|
124
|
+
console.log(`\n다음 단계: ${client === "claude-code" ? "Claude Code" : "Cursor"} 를 재시작하면 sh-ui 툴이 활성화됩니다.`);
|
|
125
|
+
} else {
|
|
126
|
+
console.log(`\n다음 단계: Claude Desktop 을 종료 후 재시작하면 sh-ui 툴이 활성화됩니다.`);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/** --key=value / --key value 파싱 */
|
|
131
|
+
function parseFlags(args) {
|
|
132
|
+
const flags = {};
|
|
133
|
+
for (let i = 0; i < args.length; i++) {
|
|
134
|
+
const a = args[i];
|
|
135
|
+
if (!a.startsWith("--")) continue;
|
|
136
|
+
const eq = a.indexOf("=");
|
|
137
|
+
if (eq > -1) flags[a.slice(2, eq)] = a.slice(eq + 1);
|
|
138
|
+
else flags[a.slice(2)] = args[++i];
|
|
139
|
+
}
|
|
140
|
+
return flags;
|
|
141
|
+
}
|
package/src/mcp.mjs
CHANGED