sh-ui-cli 0.56.2 → 0.56.4

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,29 @@
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.56.4",
7
+ "date": "2026-05-04",
8
+ "title": "fix — v0.56.3 next-intl 후속: import 보존 범위를 side-effect 만으로",
9
+ "type": "patch",
10
+ "highlights": [
11
+ "**`RootLayout` 식별자 충돌 해소** — v0.56.3 에서 next-intl 플러그인의 `app/layout.tsx` contentFn 이 기존 모든 import 라인을 보존하다 보니, 원본의 `import { RootLayout } from '@/src/app/layouts/RootLayout'` 까지 남고 새 본체의 `export default async function RootLayout` 와 식별자 충돌. 결과: smoke matrix 가 `TS2440 Import declaration conflicts with local declaration of 'RootLayout'` 로 실패해 v0.56.3 은 npm 미배포 상태. side-effect import (예: `import 'x';`, binding 없음) 만 추출하도록 정규식을 좁혀 globals.css 만 보존."
12
+ ],
13
+ "url": "https://github.com/sanghyeonKim0201/sh-ui/releases/tag/v0.56.4"
14
+ },
15
+ {
16
+ "version": "0.56.3",
17
+ "date": "2026-05-04",
18
+ "title": "fix — monorepo 템플릿 4종 버그 (Tailwind 스캔, globals 임포트, alias, pnpm 감지)",
19
+ "type": "patch",
20
+ "highlights": [
21
+ "**ui-app-template `globals.css` 의 `@source` 경로 한 단 보정** — 5 ups (`../../../../../`) 가 monorepo 깊이 한 단을 빼먹어 `packages/apps/**` 를 스캔하던 문제. 6 ups 로 수정해 실제 `apps/**` 의 사용자 코드를 Tailwind 가 picking up. 결과: 사용자 프로젝트의 utility 클래스가 정상 생성.",
22
+ "**next-intl 플러그인이 `app/layout.tsx` 의 `globals.css` import 를 보존** — content 통째 교체 → contentFn 으로 전환해 기존 `import '@workspace/ui-{app}/globals.css'` 라인을 추출 후 새 본체에 prepend. monorepo + next-intl 조합에서 Tailwind 스타일이 통째로 사라지던 문제 해결.",
23
+ "**ui-app-template `aliases.utils` 를 `@workspace/ui-app-name/lib/utils` 로 변경** — 기존 `@/lib/utils` 는 monorepo 의 `apps/web` 에서 `apps/web/lib/utils` 로 잘못 해석돼 `cn` 임포트가 깨졌다. 워크스페이스 패키지 경로로 바꿔 cross-package 임포트 정상 동작. `ui-app-name` placeholder 는 스캐폴드 시 실제 앱 이름으로 치환됨.",
24
+ "**`detectPackageManager` 가 cwd 부터 root 방향 upward walk** — sub-package (예: `packages/ui/ui-apps/ui-web/`) 에서 호출되면 root 의 `pnpm-lock.yaml` / `pnpm-workspace.yaml` 을 찾도록. 기존엔 cwd 만 보고 npm 폴백해 `EUNSUPPORTEDPROTOCOL — workspace:` 에러로 자동 설치 실패."
25
+ ],
26
+ "url": "https://github.com/sanghyeonKim0201/sh-ui/releases/tag/v0.56.3"
27
+ },
5
28
  {
6
29
  "version": "0.56.2",
7
30
  "date": "2026-05-04",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sh-ui-cli",
3
- "version": "0.56.2",
3
+ "version": "0.56.4",
4
4
  "description": "sh-ui CLI — 프로젝트 스캐폴드(create) + 컴포넌트 추가(add/list/remove) + IDE-내 AI용 MCP 서버",
5
5
  "license": "MIT",
6
6
  "repository": {
package/src/add.mjs CHANGED
@@ -268,16 +268,28 @@ async function addComponent(name, config, cwd, installed, pendingDeps, diffMode,
268
268
  }
269
269
  }
270
270
 
271
- /** lockfile 존재로 패키지 매니저 감지. 없으면 npm. */
271
+ /**
272
+ * lockfile 존재로 패키지 매니저 감지. cwd 부터 root 방향으로 한 단씩 올라가며 탐색 —
273
+ * monorepo 안의 sub-package(예: packages/ui/ui-apps/ui-web/) 에서 호출돼도 root 의
274
+ * pnpm-lock.yaml 을 찾도록. 못 찾으면 npm.
275
+ */
272
276
  function detectPackageManager(cwd) {
273
- if (existsSync(resolve(cwd, "pnpm-lock.yaml"))) return "pnpm";
274
- if (
275
- existsSync(resolve(cwd, "bun.lockb")) ||
276
- existsSync(resolve(cwd, "bun.lock"))
277
- ) {
278
- return "bun";
277
+ let dir = resolve(cwd);
278
+ while (true) {
279
+ if (existsSync(resolve(dir, "pnpm-lock.yaml"))) return "pnpm";
280
+ if (existsSync(resolve(dir, "pnpm-workspace.yaml"))) return "pnpm";
281
+ if (
282
+ existsSync(resolve(dir, "bun.lockb")) ||
283
+ existsSync(resolve(dir, "bun.lock"))
284
+ ) {
285
+ return "bun";
286
+ }
287
+ if (existsSync(resolve(dir, "yarn.lock"))) return "yarn";
288
+ if (existsSync(resolve(dir, "package-lock.json"))) return "npm";
289
+ const parent = dirname(dir);
290
+ if (parent === dir) break; // 루트 도달
291
+ dir = parent;
279
292
  }
280
- if (existsSync(resolve(cwd, "yarn.lock"))) return "yarn";
281
293
  return "npm";
282
294
  }
283
295
 
@@ -40,16 +40,29 @@ export const nextIntlPlugin = {
40
40
  { type: 'move', from: 'app/page.tsx', to: 'app/[locale]/page.tsx' },
41
41
  { type: 'move', from: 'app/error.tsx', to: 'app/[locale]/error.tsx' },
42
42
  {
43
+ // 기본 nextjs-app 템플릿의 app/layout.tsx 는 globals.css 를 side-effect import 한다 —
44
+ // next-intl 도입 시 layout 본체는 [locale]/layout.tsx 로 옮기지만, CSS import 는 root
45
+ // layout 에 살아 있어야 사용자 프로젝트의 Tailwind 스타일이 동작한다. content 통째 교체
46
+ // 대신 contentFn 으로 side-effect import (`import 'x';` 형태, binding 없음) 만 추출해
47
+ // 새 본체 앞에 prepend. 이름 있는 import (예: `import { RootLayout } from ...`) 는 새 본체와
48
+ // 식별자 충돌 가능성이 있어 제외.
43
49
  type: 'replace',
44
50
  path: 'app/layout.tsx',
45
- content: `export default async function RootLayout({
51
+ contentFn: (existing) => {
52
+ const sideEffectImports = existing
53
+ .split('\n')
54
+ .filter((line) => /^\s*import\s+['"][^'"]+['"];?\s*$/.test(line))
55
+ .join('\n');
56
+ const body = `export default async function RootLayout({
46
57
  children,
47
58
  }: {
48
59
  children: React.ReactNode;
49
60
  }) {
50
61
  return children;
51
62
  }
52
- `,
63
+ `;
64
+ return sideEffectImports ? `${sideEffectImports}\n\n${body}` : body;
65
+ },
53
66
  },
54
67
  {
55
68
  type: 'replace',
@@ -12,8 +12,8 @@
12
12
  "utils": "src/lib/utils.ts"
13
13
  },
14
14
  "aliases": {
15
- "components": "@/components",
16
- "utils": "@/lib/utils",
17
- "ui": "@/components"
15
+ "components": "@workspace/ui-app-name/components",
16
+ "utils": "@workspace/ui-app-name/lib/utils",
17
+ "ui": "@workspace/ui-app-name/components"
18
18
  }
19
19
  }
@@ -1,6 +1,6 @@
1
1
  @import 'tailwindcss';
2
2
 
3
- @source "../../../../../apps/**/*.{ts,tsx}";
3
+ @source "../../../../../../apps/**/*.{ts,tsx}";
4
4
  @source "../**/*.{ts,tsx}";
5
5
 
6
6
  @import './tokens.css';