sh-ui-cli 0.78.0 → 0.79.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.
@@ -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.79.0",
7
+ "date": "2026-05-12",
8
+ "title": "no-restricted toLocaleDateString — SSR hydration mismatch 회귀 가드",
9
+ "type": "minor",
10
+ "highlights": [
11
+ "**ESLint `no-restricted-syntax` 룰 추가** — 인자 0개의 `.toLocaleDateString()` / `.toLocaleString()` / `.toLocaleTimeString()` 호출을 error 로 차단. Node 기본 로케일(en-US) 과 브라우저 로케일(ko-KR) 이 달라 SSR 출력이 hydrate 시 mismatch 나던 함정의 회귀 가드.",
12
+ "**대체 경로 안내가 에러 메시지에 박힘** — `@/src/shared/lib/formatDate` 의 `formatDate` / `formatDateTime` (default `ko-KR`), next-intl locale 추종이면 `useFormatDate` 훅, 숫자는 `formatPrice`. AST selector 가 `arguments.length === 0` 만 매칭하므로 의도된 locale 명시 호출 (`toLocaleDateString('ko-KR', { ... })`) 은 통과.",
13
+ "**적용 범위** — monorepo `@workspace/eslint-config/base` (next.js · react-internal 등 모든 워크스페이스 config 가 상속) + `nextjs-standalone` 의 fsd / flat / mes arch 오버레이 3종.",
14
+ "**템플릿 CLAUDE.md 추가** — `nextjs-standalone` / `monorepo` 시작 템플릿에 `CLAUDE.md` 신규. 날짜·숫자 포맷 컨벤션 + sh-ui 컴포넌트 우선 + 토큰 사용 원칙 명시. AI 에이전트가 코드 작성 시점에 컨텍스트로 읽고 미리 피할 수 있게."
15
+ ],
16
+ "url": "https://github.com/sanghyeonKim0201/sh-ui/releases/tag/v0.79.0"
17
+ },
5
18
  {
6
19
  "version": "0.78.0",
7
20
  "date": "2026-05-12",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sh-ui-cli",
3
- "version": "0.78.0",
3
+ "version": "0.79.0",
4
4
  "description": "sh-ui CLI — 프로젝트 스캐폴드(create) + 컴포넌트 추가(add/list/remove) + IDE-내 AI용 MCP 서버",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -0,0 +1,40 @@
1
+ # 프로젝트 작업 규칙
2
+
3
+ sh-ui CLI 가 스캐폴드한 monorepo (Turborepo + pnpm workspace). AI 에이전트
4
+ (Claude / Cursor / Codex 등) 가 이 파일을 컨텍스트로 읽고 아래 규칙을 따른다.
5
+
6
+ ## 구조
7
+
8
+ - `apps/<name>/` — Next.js 앱. 라우트 + 비즈니스 로직.
9
+ - `packages/ui/ui-core/` — 모든 앱이 공유하는 sh-ui 컴포넌트 / 훅 / 유틸 SoT.
10
+ 컴포넌트 추가는 여기에 한 번만.
11
+ - `packages/ui/ui-apps/ui-<name>/` — 앱별 토큰 (color/spacing/font) 만 보관.
12
+ 컴포넌트는 두지 않음 (v0.65+ `tokens-only` 마커).
13
+ - `packages/eslint-config/` · `packages/typescript-config/` — 공용 설정.
14
+
15
+ ## 날짜 / 숫자 포맷
16
+
17
+ - raw `Date.prototype.toLocaleDateString()` / `toLocaleString()` / `toLocaleTimeString()`
18
+ 호출 **금지** — SSR(Node) 와 브라우저의 기본 로케일이 달라 hydration mismatch 의
19
+ 원인. ESLint `no-restricted-syntax` 룰이 인자 0개의 호출을 막는다
20
+ (`@workspace/eslint-config/base` 에 정의).
21
+ - 대신 `@/src/shared/lib/formatDate` 의 `formatDate(date)` / `formatDateTime(date)`
22
+ 사용 (default locale `ko-KR`, 서버·클라이언트 동일 출력 보장).
23
+ - next-intl locale 추종이 필요하면 `@/src/shared/hooks/useFormatDate` 훅 사용.
24
+ - 동일 원칙이 숫자에도 적용 — raw `Number.prototype.toLocaleString()` 금지,
25
+ `formatPrice` 사용.
26
+ - 인자가 명시된 호출 (`toLocaleDateString('ko-KR', { ... })`) 은 의도된 사용이므로
27
+ 허용. 다만 SSR 출력 결정성을 위해서는 util 경유가 안전.
28
+
29
+ ## 새 앱 추가
30
+
31
+ `sh_ui_add_app` MCP 툴 또는 `npx sh-ui-cli add app <name>` — `apps/<name>/` +
32
+ `packages/ui/ui-apps/ui-<name>/` 를 한 번에 만든다. 앱별로 다른 톤 가능 (예:
33
+ marketing = rose, admin = emerald). 컴포넌트는 `ui-core` 단일 SoT 라 두 앱이
34
+ 자동 공유.
35
+
36
+ ## 토큰 사용
37
+
38
+ - 색상 / 간격 / 폰트 크기는 항상 토큰 변수 경유 (`var(--space-3)`, `bg-fg`,
39
+ `text-fg-muted` 등). 매직 px / hex 직접 하드코딩 금지.
40
+ - 토큰 정의부는 `packages/ui/ui-apps/ui-<name>/src/styles/tokens.css`.
@@ -18,6 +18,15 @@ export const config = [
18
18
  "warn",
19
19
  { argsIgnorePattern: "^_", varsIgnorePattern: "^_" },
20
20
  ],
21
+ "no-restricted-syntax": [
22
+ "error",
23
+ {
24
+ selector:
25
+ "CallExpression[arguments.length=0][callee.type='MemberExpression'][callee.property.name=/^toLocale(Date|Time)?String$/]",
26
+ message:
27
+ "Argument-less .toLocaleDateString() / .toLocaleString() / .toLocaleTimeString() causes SSR hydration mismatch (Node default locale ≠ browser locale). Use `formatDate` from `@/src/shared/lib/formatDate`, or the `useFormatDate` hook for i18n-aware locale (numbers: `formatPrice`).",
28
+ },
29
+ ],
21
30
  },
22
31
  },
23
32
  {
@@ -0,0 +1,30 @@
1
+ # 프로젝트 작업 규칙
2
+
3
+ sh-ui CLI 가 스캐폴드한 Next.js standalone 프로젝트. AI 에이전트 (Claude / Cursor /
4
+ Codex 등) 가 이 파일을 컨텍스트로 읽고 아래 규칙을 따른다.
5
+
6
+ ## 날짜 / 숫자 포맷
7
+
8
+ - raw `Date.prototype.toLocaleDateString()` / `toLocaleString()` / `toLocaleTimeString()`
9
+ 호출 **금지** — SSR(Node) 와 브라우저의 기본 로케일이 달라 hydration mismatch 의
10
+ 원인. ESLint `no-restricted-syntax` 룰이 인자 0개의 호출을 막는다.
11
+ - 대신 `@/src/shared/lib/formatDate` 의 `formatDate(date)` / `formatDateTime(date)`
12
+ 사용 (default locale `ko-KR`, 서버·클라이언트 동일 출력 보장).
13
+ - next-intl locale 추종이 필요하면 `@/src/shared/hooks/useFormatDate` 훅 사용.
14
+ - 동일 원칙이 숫자에도 적용 — raw `Number.prototype.toLocaleString()` 금지,
15
+ `@/src/shared/lib/formatPrice` 의 `formatPrice` 사용.
16
+ - 인자가 명시된 호출 (`toLocaleDateString('ko-KR', { ... })`) 은 의도된 사용이므로
17
+ 허용. 다만 SSR 출력 결정성을 위해서는 util 경유가 안전.
18
+
19
+ ## sh-ui 컴포넌트 우선
20
+
21
+ - shadcn/ui 류 외부 라이브러리 대신 이 프로젝트의 `components/ui/*` (sh-ui 레지스트리)
22
+ 사용. Base UI (`@base-ui-components/react`) 위에 빌드되어 있음.
23
+ - 새 컴포넌트가 필요하면 `npx sh-ui-cli add <name>` 또는 sh-ui MCP 의
24
+ `sh_ui_add_component` 사용.
25
+
26
+ ## 토큰 사용
27
+
28
+ - 색상 / 간격 / 폰트 크기는 항상 토큰 변수 경유 (`var(--space-3)`, `bg-fg`,
29
+ `text-fg-muted` 등). 매직 px / hex 직접 하드코딩 금지.
30
+ - 토큰 정의부는 `app/globals.css` 또는 `src/shared/styles/tokens.css`.
@@ -27,6 +27,15 @@ export default [
27
27
  "warn",
28
28
  { argsIgnorePattern: "^_", varsIgnorePattern: "^_" },
29
29
  ],
30
+ "no-restricted-syntax": [
31
+ "error",
32
+ {
33
+ selector:
34
+ "CallExpression[arguments.length=0][callee.type='MemberExpression'][callee.property.name=/^toLocale(Date|Time)?String$/]",
35
+ message:
36
+ "Argument-less .toLocaleDateString() / .toLocaleString() / .toLocaleTimeString() causes SSR hydration mismatch (Node default locale ≠ browser locale). Use `formatDate` from `lib/utils/formatDate`, or the `useFormatDate` hook for i18n-aware locale (numbers: `formatPrice`).",
37
+ },
38
+ ],
30
39
  },
31
40
  },
32
41
 
@@ -27,6 +27,15 @@ export default [
27
27
  "warn",
28
28
  { argsIgnorePattern: "^_", varsIgnorePattern: "^_" },
29
29
  ],
30
+ "no-restricted-syntax": [
31
+ "error",
32
+ {
33
+ selector:
34
+ "CallExpression[arguments.length=0][callee.type='MemberExpression'][callee.property.name=/^toLocale(Date|Time)?String$/]",
35
+ message:
36
+ "Argument-less .toLocaleDateString() / .toLocaleString() / .toLocaleTimeString() causes SSR hydration mismatch (Node default locale ≠ browser locale). Use `formatDate` from `src/lib/utils/formatDate`, or the `useFormatDate` hook for i18n-aware locale (numbers: `formatPrice`).",
37
+ },
38
+ ],
30
39
  },
31
40
  },
32
41
 
@@ -27,6 +27,15 @@ export default [
27
27
  "warn",
28
28
  { argsIgnorePattern: "^_", varsIgnorePattern: "^_" },
29
29
  ],
30
+ "no-restricted-syntax": [
31
+ "error",
32
+ {
33
+ selector:
34
+ "CallExpression[arguments.length=0][callee.type='MemberExpression'][callee.property.name=/^toLocale(Date|Time)?String$/]",
35
+ message:
36
+ "Argument-less .toLocaleDateString() / .toLocaleString() / .toLocaleTimeString() causes SSR hydration mismatch (Node default locale ≠ browser locale). Use `formatDate` from `@/src/shared/lib/formatDate`, or the `useFormatDate` hook for i18n-aware locale (numbers: `formatPrice`).",
37
+ },
38
+ ],
30
39
  },
31
40
  },
32
41