sh-ui-cli 0.21.0 → 0.21.2

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.
@@ -2,6 +2,30 @@
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.21.2",
7
+ "date": "2026-04-27",
8
+ "title": "@base-ui-components/react → @base-ui/react 마이그레이션",
9
+ "type": "patch",
10
+ "highlights": [
11
+ "Base UI 패키지명 변경에 대응 — @base-ui-components/react (deprecated, RC만 존재) → @base-ui/react ^1.4.1 (stable). 17개 컴포넌트 + docs 듀얼 카피 + registry.json + peer-versions.json 일괄 갱신",
12
+ "deprecation 워닝 제거 — 신규 사용자가 sh-ui add 시 deprecated 패키지 경고 없이 stable 1.4.1 자동 설치",
13
+ "submodule 경로(@base-ui/react/dialog 등)는 동일하므로 사용자 코드 호환성 유지"
14
+ ],
15
+ "url": "https://github.com/sanghyeonKim0201/sh-ui/releases/tag/v0.21.2"
16
+ },
17
+ {
18
+ "version": "0.21.1",
19
+ "date": "2026-04-27",
20
+ "title": "외부 패키지 자동 설치 버전 해석",
21
+ "type": "patch",
22
+ "highlights": [
23
+ "registry/react/peer-versions.json — registry.json deps 의 패키지명을 실제 버전 범위로 매핑하는 단일 출처 추가",
24
+ "sh-ui add 가 npm install <name>@<range> 로 호출 — RC 만 있는 패키지(@base-ui-components/react 등) 자동 설치 시 latest 못 찾아 ETARGET 으로 실패하던 사전 이슈 수정",
25
+ "패키지명에 이미 @version 이 포함돼 있거나 peer-versions 맵에 없는 경우는 그대로 통과 (Flutter·기타 platform 호환)"
26
+ ],
27
+ "url": "https://github.com/sanghyeonKim0201/sh-ui/releases/tag/v0.21.1"
28
+ },
5
29
  {
6
30
  "version": "0.21.0",
7
31
  "date": "2026-04-27",
@@ -1,5 +1,5 @@
1
1
  import * as React from "react";
2
- import { Accordion as BaseAccordion } from "@base-ui-components/react/accordion";
2
+ import { Accordion as BaseAccordion } from "@base-ui/react/accordion";
3
3
  import "./styles.css";
4
4
 
5
5
  function cx(...args: (string | undefined | false)[]) {
@@ -1,5 +1,5 @@
1
1
  import * as React from "react";
2
- import { Avatar as BaseAvatar } from "@base-ui-components/react/avatar";
2
+ import { Avatar as BaseAvatar } from "@base-ui/react/avatar";
3
3
  import "./styles.css";
4
4
 
5
5
  type WithStringClassName<T> = Omit<T, "className"> & { className?: string };
@@ -1,6 +1,6 @@
1
1
  import * as React from "react";
2
- import { Checkbox as BaseCheckbox } from "@base-ui-components/react/checkbox";
3
- import { CheckboxGroup as BaseCheckboxGroup } from "@base-ui-components/react/checkbox-group";
2
+ import { Checkbox as BaseCheckbox } from "@base-ui/react/checkbox";
3
+ import { CheckboxGroup as BaseCheckboxGroup } from "@base-ui/react/checkbox-group";
4
4
  import "./styles.css";
5
5
 
6
6
  function cx(...args: (string | undefined | false)[]) {
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
 
3
3
  import * as React from "react";
4
- import { Combobox as BaseCombobox } from "@base-ui-components/react/combobox";
4
+ import { Combobox as BaseCombobox } from "@base-ui/react/combobox";
5
5
  import "./styles.css";
6
6
 
7
7
  type WithStringClassName<T> = Omit<T, "className"> & { className?: string };
@@ -1,5 +1,5 @@
1
1
  import * as React from "react";
2
- import { ContextMenu as BaseContextMenu } from "@base-ui-components/react/context-menu";
2
+ import { ContextMenu as BaseContextMenu } from "@base-ui/react/context-menu";
3
3
  import "./styles.css";
4
4
 
5
5
  type WithStringClassName<T> = Omit<T, "className"> & { className?: string };
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
 
3
3
  import * as React from "react";
4
- import { Popover as BasePopover } from "@base-ui-components/react/popover";
4
+ import { Popover as BasePopover } from "@base-ui/react/popover";
5
5
  import "./styles.css";
6
6
 
7
7
  /* ───────── Helpers ───────── */
@@ -1,5 +1,5 @@
1
1
  import * as React from "react";
2
- import { Dialog as BaseDialog } from "@base-ui-components/react/dialog";
2
+ import { Dialog as BaseDialog } from "@base-ui/react/dialog";
3
3
  import "./styles.css";
4
4
 
5
5
  type WithStringClassName<T> = Omit<T, "className"> & { className?: string };
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
 
3
3
  import * as React from "react";
4
- import { Menu as BaseMenu } from "@base-ui-components/react/menu";
4
+ import { Menu as BaseMenu } from "@base-ui/react/menu";
5
5
  import "./styles.css";
6
6
 
7
7
  type WithStringClassName<T> = Omit<T, "className"> & { className?: string };
@@ -1,5 +1,5 @@
1
1
  import * as React from "react";
2
- import { Menubar as BaseMenubar } from "@base-ui-components/react/menubar";
2
+ import { Menubar as BaseMenubar } from "@base-ui/react/menubar";
3
3
  import "./styles.css";
4
4
 
5
5
  type WithStringClassName<T> = Omit<T, "className"> & { className?: string };
@@ -1,5 +1,5 @@
1
1
  import * as React from "react";
2
- import { Popover as BasePopover } from "@base-ui-components/react/popover";
2
+ import { Popover as BasePopover } from "@base-ui/react/popover";
3
3
  import "./styles.css";
4
4
 
5
5
  type WithStringClassName<T> = Omit<T, "className"> & { className?: string };
@@ -1,6 +1,6 @@
1
1
  import * as React from "react";
2
- import { Radio as BaseRadio } from "@base-ui-components/react/radio";
3
- import { RadioGroup as BaseRadioGroup } from "@base-ui-components/react/radio-group";
2
+ import { Radio as BaseRadio } from "@base-ui/react/radio";
3
+ import { RadioGroup as BaseRadioGroup } from "@base-ui/react/radio-group";
4
4
  import "./styles.css";
5
5
 
6
6
  function cx(...args: (string | undefined | false)[]) {
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
 
3
3
  import * as React from "react";
4
- import { Select as BaseSelect } from "@base-ui-components/react/select";
4
+ import { Select as BaseSelect } from "@base-ui/react/select";
5
5
  import "./styles.css";
6
6
 
7
7
  function cx(...args: (string | undefined | false)[]) {
@@ -1,5 +1,5 @@
1
1
  import * as React from "react";
2
- import { Switch as BaseSwitch } from "@base-ui-components/react/switch";
2
+ import { Switch as BaseSwitch } from "@base-ui/react/switch";
3
3
  import "./styles.css";
4
4
 
5
5
  function cx(...args: (string | undefined | false)[]) {
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
 
3
3
  import * as React from "react";
4
- import { Tabs as BaseTabs } from "@base-ui-components/react/tabs";
4
+ import { Tabs as BaseTabs } from "@base-ui/react/tabs";
5
5
  import "./styles.css";
6
6
 
7
7
  function cx(...args: (string | undefined | false)[]) {
@@ -1,8 +1,8 @@
1
1
  "use client";
2
2
 
3
3
  import * as React from "react";
4
- import { Toggle as BaseToggle } from "@base-ui-components/react/toggle";
5
- import { ToggleGroup as BaseToggleGroup } from "@base-ui-components/react/toggle-group";
4
+ import { Toggle as BaseToggle } from "@base-ui/react/toggle";
5
+ import { ToggleGroup as BaseToggleGroup } from "@base-ui/react/toggle-group";
6
6
  import "./styles.css";
7
7
 
8
8
  function cx(...args: (string | undefined | false)[]) {
@@ -1,5 +1,5 @@
1
1
  import * as React from "react";
2
- import { Tooltip as BaseTooltip } from "@base-ui-components/react/tooltip";
2
+ import { Tooltip as BaseTooltip } from "@base-ui/react/tooltip";
3
3
  import "./styles.css";
4
4
 
5
5
  type WithStringClassName<T> = Omit<T, "className"> & { className?: string };
@@ -0,0 +1,10 @@
1
+ {
2
+ "$description": "registry.json 의 dependencies 에 등장하는 npm 패키지의 버전 범위. CLI 가 add 시 npm install <name>@<range> 로 호출하기 위함.",
3
+ "versions": {
4
+ "@base-ui/react": "^1.4.1",
5
+ "@tanstack/react-form": "^1.29.1",
6
+ "lucide-react": "^1.11.0",
7
+ "react-hook-form": "^7.74.0",
8
+ "shiki": "^4.0.2"
9
+ }
10
+ }
@@ -171,7 +171,7 @@
171
171
  }
172
172
  ],
173
173
  "dependencies": [
174
- "@base-ui-components/react"
174
+ "@base-ui/react"
175
175
  ],
176
176
  "registryDependencies": []
177
177
  },
@@ -369,7 +369,7 @@
369
369
  }
370
370
  ],
371
371
  "dependencies": [
372
- "@base-ui-components/react"
372
+ "@base-ui/react"
373
373
  ],
374
374
  "registryDependencies": []
375
375
  },
@@ -387,7 +387,7 @@
387
387
  }
388
388
  ],
389
389
  "dependencies": [
390
- "@base-ui-components/react"
390
+ "@base-ui/react"
391
391
  ],
392
392
  "registryDependencies": []
393
393
  },
@@ -405,7 +405,7 @@
405
405
  }
406
406
  ],
407
407
  "dependencies": [
408
- "@base-ui-components/react"
408
+ "@base-ui/react"
409
409
  ],
410
410
  "registryDependencies": []
411
411
  },
@@ -423,7 +423,7 @@
423
423
  }
424
424
  ],
425
425
  "dependencies": [
426
- "@base-ui-components/react"
426
+ "@base-ui/react"
427
427
  ],
428
428
  "registryDependencies": []
429
429
  },
@@ -441,7 +441,7 @@
441
441
  }
442
442
  ],
443
443
  "dependencies": [
444
- "@base-ui-components/react"
444
+ "@base-ui/react"
445
445
  ],
446
446
  "registryDependencies": []
447
447
  },
@@ -459,7 +459,7 @@
459
459
  }
460
460
  ],
461
461
  "dependencies": [
462
- "@base-ui-components/react"
462
+ "@base-ui/react"
463
463
  ],
464
464
  "registryDependencies": []
465
465
  },
@@ -477,7 +477,7 @@
477
477
  }
478
478
  ],
479
479
  "dependencies": [
480
- "@base-ui-components/react"
480
+ "@base-ui/react"
481
481
  ],
482
482
  "registryDependencies": [
483
483
  "dropdown-menu"
@@ -497,7 +497,7 @@
497
497
  }
498
498
  ],
499
499
  "dependencies": [
500
- "@base-ui-components/react"
500
+ "@base-ui/react"
501
501
  ],
502
502
  "registryDependencies": []
503
503
  },
@@ -547,7 +547,7 @@
547
547
  }
548
548
  ],
549
549
  "dependencies": [
550
- "@base-ui-components/react"
550
+ "@base-ui/react"
551
551
  ],
552
552
  "registryDependencies": []
553
553
  },
@@ -641,7 +641,7 @@
641
641
  }
642
642
  ],
643
643
  "dependencies": [
644
- "@base-ui-components/react"
644
+ "@base-ui/react"
645
645
  ],
646
646
  "registryDependencies": []
647
647
  },
@@ -659,7 +659,7 @@
659
659
  }
660
660
  ],
661
661
  "dependencies": [
662
- "@base-ui-components/react"
662
+ "@base-ui/react"
663
663
  ],
664
664
  "registryDependencies": []
665
665
  },
@@ -677,7 +677,7 @@
677
677
  }
678
678
  ],
679
679
  "dependencies": [
680
- "@base-ui-components/react"
680
+ "@base-ui/react"
681
681
  ],
682
682
  "registryDependencies": []
683
683
  },
@@ -695,7 +695,7 @@
695
695
  }
696
696
  ],
697
697
  "dependencies": [
698
- "@base-ui-components/react"
698
+ "@base-ui/react"
699
699
  ],
700
700
  "registryDependencies": []
701
701
  },
@@ -745,7 +745,7 @@
745
745
  }
746
746
  ],
747
747
  "dependencies": [
748
- "@base-ui-components/react"
748
+ "@base-ui/react"
749
749
  ],
750
750
  "registryDependencies": []
751
751
  },
@@ -779,7 +779,7 @@
779
779
  }
780
780
  ],
781
781
  "dependencies": [
782
- "@base-ui-components/react"
782
+ "@base-ui/react"
783
783
  ],
784
784
  "registryDependencies": []
785
785
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sh-ui-cli",
3
- "version": "0.21.0",
3
+ "version": "0.21.2",
4
4
  "description": "sh-ui CLI — 디자인 시스템 컴포넌트를 프로젝트로 복사하는 CLI (sh-ui init / add / list / remove)",
5
5
  "license": "MIT",
6
6
  "repository": {
package/src/add.mjs CHANGED
@@ -4,7 +4,30 @@ import { dirname, resolve, relative } from "node:path";
4
4
  import { pathToFileURL } from "node:url";
5
5
  import { spawn } from "node:child_process";
6
6
  import { formatUnifiedDiff } from "./diff.mjs";
7
- import { getRegistryRoot, getTokensRoot } from "./paths.mjs";
7
+ import { getRegistryRoot, getTokensRoot, getPeerVersionsPath } from "./paths.mjs";
8
+
9
+ /**
10
+ * `dependencies` 에 적힌 패키지명을 peer-versions.json 의 버전 범위와 결합.
11
+ * 패키지 자체에 이미 `@version` 이 붙어 있거나 맵에 없으면 그대로 둔다.
12
+ *
13
+ * 왜: registry.json 은 deps 를 패키지명만 적어 두고, 실제 호환 버전은
14
+ * peer-versions.json 가 단일 출처로 관리한다. 이게 없으면 npm install 이
15
+ * latest 태그를 찾는데, RC 만 있는 패키지(@base-ui-components/react 등)
16
+ * 에서 ETARGET 으로 실패한다.
17
+ */
18
+ async function resolveDepVersions(deps, platform) {
19
+ let map = {};
20
+ try {
21
+ const data = JSON.parse(await readFile(getPeerVersionsPath(platform), "utf8"));
22
+ map = data.versions ?? {};
23
+ } catch {
24
+ // peer-versions.json 이 없는 platform 은 그대로 패스 (Flutter 등)
25
+ }
26
+ return deps.map((d) => {
27
+ if (d.includes("@", 1)) return d; // 이미 name@range 형식
28
+ return map[d] ? `${d}@${map[d]}` : d;
29
+ });
30
+ }
8
31
 
9
32
  // tokens/build.mjs 는 모노레포·출고 모드에 따라 위치가 달라서 동적 import.
10
33
  async function loadTokensBuilder() {
@@ -209,22 +232,24 @@ export async function add({ cwd, names, skipInstall = false, diffMode = false })
209
232
  return;
210
233
  }
211
234
 
235
+ const versioned = await resolveDepVersions(missing, config.platform);
236
+
212
237
  if (skipInstall) {
213
238
  const pm = detectPackageManager(cwd);
214
239
  const addCmd = pm === "npm" ? "install" : "add";
215
240
  console.log(
216
- `\n ⚠ 외부 패키지 필요. 다음을 실행하세요:\n ${pm} ${addCmd} ${missing.join(" ")}`,
241
+ `\n ⚠ 외부 패키지 필요. 다음을 실행하세요:\n ${pm} ${addCmd} ${versioned.join(" ")}`,
217
242
  );
218
243
  return;
219
244
  }
220
245
 
221
246
  const pm = detectPackageManager(cwd);
222
247
  try {
223
- await runInstall(pm, missing, cwd);
248
+ await runInstall(pm, versioned, cwd);
224
249
  } catch (err) {
225
250
  const addCmd = pm === "npm" ? "install" : "add";
226
251
  console.error(
227
- `\n✗ 자동 설치 실패 (${err.message}). 수동으로 실행하세요:\n ${pm} ${addCmd} ${missing.join(" ")}`,
252
+ `\n✗ 자동 설치 실패 (${err.message}). 수동으로 실행하세요:\n ${pm} ${addCmd} ${versioned.join(" ")}`,
228
253
  );
229
254
  throw err;
230
255
  }
package/src/mcp.mjs CHANGED
@@ -102,7 +102,7 @@ function resolveCwd(input) {
102
102
 
103
103
  export async function startMcpServer() {
104
104
  const server = new McpServer(
105
- { name: "sh-ui", version: "0.21.0" },
105
+ { name: "sh-ui", version: "0.21.2" },
106
106
  { capabilities: { tools: {} } },
107
107
  );
108
108
 
package/src/paths.mjs CHANGED
@@ -33,6 +33,13 @@ export function getTokensRoot() {
33
33
  : resolve(MONOREPO_PACKAGES, "tokens");
34
34
  }
35
35
 
36
+ /** registry.json deps 에 등장하는 npm 패키지의 버전 범위 맵 */
37
+ export function getPeerVersionsPath(platform) {
38
+ return isBundled
39
+ ? resolve(BUNDLED_DATA, "registry", platform, "peer-versions.json")
40
+ : resolve(MONOREPO_PACKAGES, "registry", platform, "peer-versions.json");
41
+ }
42
+
36
43
  /** llms 요약 JSON (platform별) */
37
44
  export function getSummariesPath(platform) {
38
45
  return isBundled