@dsmith-dev/init
v0.5.0
Published
dsmith init: draft design tokens (W3C) and component scaffolds from an audit
Maintainers
Readme
@dsmith-dev/init
dsmith init: draft design tokens (W3C) and component scaffolds from an audit.
Docs: https://github.com/project-hh-org/dsmith#readme
쓰기 규칙
dsmith init은 .dsmith/index.json(audit 결과)을 읽어 <out>/(기본 design-system/)에 쓴다.
| 산출 | 모드 | 사용자가 고쳤을 때 |
| --- | --- | --- |
| tokens.json · tokens.css · tokens.ts | managed(재생성) | 한 묶음이다. 셋 중 하나라도 사용자가 고쳤으면 셋 모두 보류(skipped-modified)하고 --force로만 함께 덮어쓴다 |
| components/<Name>.tsx | 새 파일은 create-only, init이 쓴 뒤 손대지 않은 파일은 managed | 손대지 않았으면(파일 해시 == .dsmith/init.json 엔트리) 결정이 바뀔 때 새 기준으로 다시 만든다(updated). 고쳤으면 --force여도 덮어쓰지 않고(skipped-exists), 만든 기준 옵션이 이번 선택과 다르면 경고한다 |
- 스캐폴드를 사용자가 삭제했으면(
.dsmith/init.json에 엔트리가 있는데 파일이 없음) 다시 만들지 않는다.--force로 재생성한다. .dsmith/catalog.json이 있고 이 산출 디렉터리를 담고 있으면 카탈로그의 토큰과 토큰 파일 해시도 새 파일 기준으로 갱신한다(컴포넌트·AGENTS.md는dsmith ai의 일). 카탈로그가 없거나 다른 디렉터리 기준이면다음: dsmith ai를 안내한다..dsmith/init.json에는 세 토큰 파일의 해시와 함께 가장 최근 산출 디렉터리(outDir)·updatedAt이 기록된다.dsmith ai가 이를 우선해 init 산출을 찾는다.--dry-run은.dsmith/포함 어떤 파일도 쓰지 않고 쓸 파일과 diff만 낸다.- 결정 시드: audit의 중복·지역 재정의 컴포넌트와, 구성원이 둘 이상인 색 클러스터가
.dsmith/decisions.json에pending으로 들어간다. 다시 실행하면 구성원이 바뀐pendingtoken-cluster 기록의 선택지를 갱신하고,decided기록은 건드리지 않는다.
토큰 이름
새로 init하는 레포의 토큰 CSS 변수는 모두 --ds- 접두다(--ds-color-blue-400·--ds-space-2·--ds-radius-sm·--ds-text-xs). Tailwind 4는 기본 테마 변수(--color-*·--text-*·--radius-*)를 쓰는데, 접두 없는 tokens.css의 비레이어 :root가 이를 덮으면 기존 bg-blue-400·text-xs·rounded-sm의 값이 레포 전체에서 바뀐다(실제 Tailwind 4.3.3 빌드와 브라우저 계산값으로 확인). 접두가 있으면 겹치지 않는다. Tailwind 유무·버전과 상관없이 한 규칙이다.
tokens.json의 DTCG 경로(color.blue-400)와tokens.ts키, Tailwind 클래스 키(bg-ds-blue-400)는 그대로이고 CSS 변수 이름만 바뀐다. 루트$extensions["dev.dsmith"].cssPrefix: "ds"가 접두를 알리고, 이 확장이 없는tokens.json(이전 산출·외부 DTCG)은--<경로>로 읽는다.- 이미 init한 레포는 이름을 바꾸지 않는다. 형식은 커밋된 init 소유 토큰 파일로 판정한다(
outDir, 다음으로 이전outDir의tokens.json루트cssPrefix, 없으면tokens.css의 첫 변수 이름). 토큰 파일이 없으면.dsmith/init.json의naming, 그것도 없으면ds다..dsmith/가 gitignore된 클론에서도 토큰 파일로 정해진다. 이전 형식(접두 없음)은 같은 입력이면 바이트까지 같은 파일로 다시 만든다(unchanged). Tailwind 4 레포가 이전 형식이면 요약에 충돌 경고가 나온다. - 이전 형식에서 벗어나려면
dsmith migrate --rename-prefix(계획) →--apply. 코드의var(--color-…)참조와 토큰·프리셋 파일을 함께 바꾸고--revert <id>로 되돌릴 수 있다. - 값이 바뀌는 재 init 보류: 이전 init 소유
tokens.css와 비교해 의미 이름(color-blue-400, 접두 제외) 기준으로 값이 바뀌거나 사라지는 토큰이 있고.dsmith/migrations/에status "applied"기록이 있으면(코드가 그 이름을var()로 쓰고 있다는 뜻) 토큰 묶음(과 프리셋)을 보류한다(tokenHold: "renamed", 종료 코드 0).--force로만 덮어쓴다. 적용 기록이 없으면 쓰되 경고만 낸다. 접두만 다른 변경(rename)은 대상이 아니다.
React Native
detect가 프레임워크를 react-native(react-native·expo 의존성)로 판정한 레포에서는 웹 산출을 만들지 않는다. tokens.json·tokens.css, Tailwind 프리셋, 컴포넌트 골격(웹 템플릿이라 skippedScaffolds에 react-native: 웹 스캐폴드 템플릿이라 만들지 않음)을 쓰지 않고, 결과의 tokenSource가 토큰의 출처를 알린다.
| 상황 | 결과 |
| --- | --- |
| 쓰이는 JS 테마가 있음(ds.jsThemes) | 토큰 파일을 하나도 만들지 않는다. tokenSource: { kind: "js-theme", files: ["src/theme.ts"] }. 토큰 수와 커버리지는 그 테마 기준(모드 light/dark 아래 토큰은 치환 후보가 아니라 제외). 요약: 토큰: 기존 JS 테마 사용 — src/theme.ts (색 7 · 간격 4 · 모서리 3 · 글꼴 크기 3) |
| JS 테마가 없음 | design-system/tokens.ts만 쓴다(tokenSource.kind: "init-files"). 형식은 export const colors/spacing/radius/fontSize = { … } as const;, 키는 식별자(blue-400 → blue400, 숫자 키는 그대로 spacing[2]), 길이는 단위 없는 숫자(dp). readJsThemeTokens가 다시 읽으면 초안과 같은 토큰이 나온다. 사람이 고쳤으면 이 한 파일을 보류하고 --force로 덮어쓴다 |
| 이전 init 산출(tokens.css·tokens.json)이 이미 있음 | 지우지도 다시 쓰지도 않고 경고 한 줄: react-native 레포에서는 design-system/tokens.css·tokens.json을 쓰지 않음 — 필요 없으면 지워도 됨 |
- 평행한 토큰 파일을 만들지 않는 이유: 앱의 테마와
design-system/이 함께 있으면 어느 쪽이 정본인지 흐려진다. - 이어서
migrate는 하드코딩 값을colors.blue400·spacing[2]처럼 JS 참조로 바꾸고 필요하면 import를 더한다.tokens.ts가tokens.json없이 있으면 coreloadReplacementTokens가 JS 테마로 읽는다. InitResult.reactNative가true이면 웹 전용 필드(tailwindPreset,tokensLoaded)는null이다.--dry-run은 같은 판단을 하고 쓰지 않는다.
알려진 제한
- migrate 뒤 init을 다시 실행했을 때 토큰 이름·값이 옮겨 가는 것은 위 보류로 막을 뿐, 이전
tokens.json을 잠금 파일로 삼아 이름을 고정하지는 않는다.
옵션
--all: 결정 없이 추천안으로 스캐폴드한다. 대상은duplicate→local-definition후보 순서의 앞에서--top개(기본 10). 이미 DS에 있는 컴포넌트와 이름이 겹치는 항목은 건너뛴다.--top <n>:--all과 함께만 쓴다(1 이상의 정수).--all없이 쓰면 오류.--all이 없으면 결정이 끝난(decided, stale 아님) 항목만 스캐폴드하고 개수 제한은 없다.--out <dir>: 레포 안 상대 경로(..·절대 경로·.dsmith·node_modules불가).--force: 사용자가 고친 토큰 파일 묶음을 덮어쓰고 삭제된 스캐폴드를 다시 만든다. 사용자가 고친 스캐폴드는 덮어쓰지 않는다.
종료 코드
0: 실행 성공. 사용자가 고친 토큰 파일 때문에 일부를 보류한 경우에도 0이며 요약에--force안내가 나온다.1: 오류(audit 결과 없음,--out·--top검증 실패 등). 메시지는 stderr의오류: ….
커버리지 숫자
리포트의 커버리지는 색·간격·모서리·글꼴 크기 속성의 하드코딩 값 중 토큰으로 바꿀 수 있는 비율이다. 정규화하지 못한 값(unknown)과 토큰 대상이 아닌 길이(width·height)는 분모에서 빠지며 그 건수가 리포트에 나온다. 투명도(알파)가 있는 색은 6자리 hex 토큰으로 합쳐지므로 알파가 빠지고, 그 색과 건수를 리포트에 따로 적는다.
리포트에서 두 가지를 구분한다. 추론 토큰(4px 스케일에 걸리지 않는 값을 가장 가까운 스텝으로 모은 간격 토큰)의 members는 토큰 값과 다른 원값을 묶은 목록일 뿐 치환 대상이 아니다. 스케일 밖 값이 거리가 먼 토큰에 대응돼도 "바꿀 수 있음"으로 세지 않는다(매처의 exact·close만 센다).
외부 도구 검증 (2026-11-01)
tokens.json(W3C Design Tokens 2025.10 형식)을 외부 도구로 확인했다.
- Terrazzo
@terrazzo/parser2.10.0: lint 오류·경고 없음 - Style Dictionary 5.7.1:
css/variables출력이tokens.css와 같다(--ds-접두는 플랫폼prefix: "ds"로 같은 이름이 나온다)
같은 날 ai의 npm 카탈로그를 실제 @mui/material 전체 패키지로 돌렸다: 6.5.0은 컴포넌트 130·props 추출 126·deprecated 3, 9.5.0은 130·126·0(각각 약 1초 이내). 자세한 기록은 docs/superpowers/plans/2026-11-01-ds-draft.md 부록 B.7.
