shadcn --yes 를 줬는데도 「덮어쓸까요?」가 뜬다
커스텀 레지스트리로 팔레트를 심다 막힌 프롬프트, 그리고 내가 만들어둔 components.json 이 가린 진짜 문제
여러 프로젝트에 흩어진 공용 컴포넌트를 한 곳에 모으고, 새 프로젝트에서 명령 한 줄로 가져다 쓰게 만들고 있었다. shadcn 커스텀 레지스트리를 쓰면 된다.
npx shadcn@latest add ~/git/danny-ds/registry/button.json
컴포넌트 쪽은 완벽했다. confirm-modal 하나를 설치했더니 그게 의존하는 store·스크롤잠금·모달스택까지 파일 4개가 정확히 따라왔다.
그다음 색 팔레트를 심으려는데 거기서 멈췄다.
? The file globals.css already exists. Would you like to overwrite? › (y/N)
--yes 를 줬는데도 물어본다.
--yes 가 안 걸리는 물음이 따로 있다
처음엔 플래그를 잘못 줬나 싶었다. 아니었다. 이건 덮어쓰기라서 묻는 것이고, --yes 는 의존 설치 같은 다른 물음에만 걸린다.
그런데 문제는 물음 자체가 아니라 누가 답하느냐였다. 이 명령을 치는 건 사람이 아니라 클로드 코드다. 대화형 프롬프트에는 답할 수단이 없다. 그리고 설령 답할 수 있어도 「y」는 위험하다 — 받는 쪽 globals.css 에 원래 있던 설정이 통째로 날아간다.
갈림길은 둘이었다.
- 파일로 보낸다 — 내용을 그대로 옮길 수 있다. 대신 덮어쓰기라 묻고, 남의 설정을 지운다.
- 변수만 보낸다 — shadcn 이 기존 CSS 에 병합해준다. 대신
@keyframes처럼 변수로 표현 못 하는 건 못 보낸다.
당시 globals.css 안에는 확인 대화상자가 쓰는 등장 효과 @keyframes 두 개가 있었다. 그것 때문에 파일로 보낼 수밖에 없다고 생각했다.
막힌 이유가 진짜 원인이 아니었다
효과 하나 때문에 시스템 전체 목적이 막혀 있었다는 걸 뒤늦게 봤다.
그 확인 대화상자만 CSS 키프레임을 쓰고 있었고, 같은 레포의 다른 모달은 이미 「한 프레임 뒤에 클래스를 바꾸는」 방식으로 등장 효과를 내고 있었다. 방식이 두 벌이었던 것이다. 키프레임을 거기 둬야 할 이유는 없었다.
- 확인 대화상자를 다른 모달과 같은 방식으로 통일하고
@keyframes를 걷어냈다 - 팔레트는 변수만 보내게 바꿨다 → 되묻지 않고, 받는 쪽 기존 설정이 살아남는다
- 나중에 애니메이션을 본격적으로 만들 때는 아예 별도 CSS 파일로 뺐다. 새 파일이라 덮어쓰기를 묻지 않는다
검증하다 두 개를 더 잡았다. 하나는 순환 참조로, --app-font-sans: var(--app-font-sans) 가 자동으로 만들어져서 글꼴이 통째로 죽을 뻔했다. 다른 하나는 여러 줄에 걸친 글꼴 스택이 파싱에서 빠지는 것이었다. 둘 다 심어놓고 색만 나오고 글꼴은 안 나오는 종류라, 설치를 실제로 한 번 해보지 않았으면 몰랐다.
내가 손으로 만들어둔 components.json 이 사각지대였다
여기까지 하고 「이제 자동으로 심어진다」고 문서에 적었다. 며칠 뒤 다른 프로젝트에서 어떻게 참조할지 고민해봤냐는 질문을 받고, 진짜 새 프로젝트를 하나 만들어 내가 쓴 문서대로 그대로 따라 해봤다.
첫 명령부터 막혔다.
? You need to create a components.json file to add components. Proceed? › (Y/n)
앞서 고친 프롬프트보다 한 단계 앞에 또 있었다. 왜 못 봤나 — 내 시험용 폴더는 components.json 을 내가 손으로 만들어놓고 시작했기 때문이다. 실제 사용자에게는 그게 없다.
우회로로 초기화 명령(init)을 써봤더니 더 나쁜 게 나왔다. 그 명령이 자기 기본 버튼 button.tsx 를 만들어 두는데, 내 것은 Button.tsx 였다.
button.tsx inode=37362294
Button.tsx inode=37362294 ← 같은 파일이다
맥 파일시스템은 대소문자를 구분하지 않는다. 그런데 배포 서버(리눅스)는 구분한다. 맥에서는 하나가 다른 하나를 삼키고, 리눅스에서는 둘이 공존한다. 「내 컴퓨터에선 되는데 배포하면 깨진다」의 교과서적인 형태다.
결론은 초기화 명령을 아예 쓰지 않고 설정 파일을 직접 넣는 것이었다. 그러면 되묻는 질문 없이 전 과정이 끝난다. 확인하는 김에 내가 쓴 안내 하나가 틀린 것도 드러났다 — 「이 한 줄을 손으로 넣어라」라고 적어놨는데 도구가 알아서 넣어주고 있었다.
정리
- 자동화 경로에 대화형 프롬프트가 하나라도 있으면 거기서 끝난다. 사람이면 엔터 한 번인 것이 기계에게는 벽이다
- 「덮어쓴다」는 편의가 아니라 남의 것을 지우는 동작이다. 병합할 수 있으면 병합한다
- 설치가 되는지를 시험하려면 아무것도 없는 상태에서 문서 첫 줄부터 그대로 쳐야 한다. 조건을 하나 미리 만족시켜 놓으면 그만큼 안 보인다