@axis-ds/cli 1.7.8 → 1.7.10

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.
package/README.md CHANGED
@@ -38,17 +38,20 @@ axis list
38
38
  - 이미 있는 파일: 내용이 같으면 건너뜀, 다르면 대화형에서는 묻고, `-y` 는 건너뛰며 목록을 알려 주고, `--overwrite` 만 덮어씁니다. 터미널이 아닌 곳(CI · 파이프)에서는 묻지 않고 `-y` 와 같이 건너뜁니다. 출력은 새로 만든 파일 `+`, 덮어쓴 파일 `~ … (덮어씀)`, 같은 내용이라 건너뛴 파일 `=` 입니다. `--overwrite` 는 `registryDependencies` 로 끌려온 파일(예: 고친 `utils.ts`)도 덮어쓰니 출력의 `~` 를 확인하세요.
39
39
  - 쓰기 전에 실제 경로(심볼릭 링크를 따라간 위치)가 프로젝트 디렉터리 안인지 확인하고, 밖이면 쓰지 않습니다. 기존 대상 파일이 심볼릭 링크여도 내용이 같거나 `-y` 로 건너뛰면 쓰지 않으므로 건너뜁니다(예: 앱 디렉터리 안의 공용 `utils.ts`, 또는 모노레포의 다른 패키지처럼 프로젝트 밖의 `utils.ts` 에 링크해 둔 경우). 밖을 가리키는 링크는 `= <경로> (같은 내용이라 건너뜀, 링크 대상이 프로젝트 밖)` 처럼 그 사실을 함께 알립니다(rc 0). 상위 디렉터리(`componentsDir` 등)가 밖을 가리키는 링크면 경로 이탈로 거부합니다. 설치 대상이 디렉터리(또는 디렉터리를 가리키는 링크)이거나 기존 파일을 읽지 못하면 이유를 알리고 아무것도 쓰지 않고 rc 1 입니다. 링크를 실제로 덮어써야 할 때(`--overwrite` · 대화형 예, 링크가 프로젝트 안 · 밖 어디를 가리켜도)만 아무것도 쓰지 않고 rc 1 로 알립니다. 덮어써야 하는 일반 파일이 다른 경로와 하드링크로 이어져 있으면(링크 수 2 이상) 쓰기 전에 그 경로와 이유를 알리고 아무것도 쓰지 않은 채 rc 1 로 끝내며, 쓰기 직전에도 연 파일로 한 번 더 확인합니다(내용이 같거나 `-y` 로 건너뛰는 파일은 영향 없음). 덮어쓰기를 묻는 동안 새로 설치할 파일과 같은 이름의 파일이 생기면 그 파일을 덮어쓰지 않고 경로를 알린 뒤 rc 1 로 끝냅니다. 검사와 쓰기 사이의 동시 경합은 사후 검사로 감지합니다: 쓴 파일의 실제 위치가 프로젝트 밖이면 그 파일을 지우지 않고 경로를 알린 뒤 rc 1 로 끝냅니다(그 위치의 파일은 사용자 것일 수 있어 CLI 가 지우지 않음).
40
40
  - `package.json` 에 없는 의존성은 lockfile 에 맞춘 설치 명령으로 안내만 합니다(설치는 하지 않음). 안내 명령은 복사해 실행하는 셸 명령이라, 레지스트리의 `dependencies` 값이 패키지 이름(선택적 `@범위`) 형태가 아니면(`;` · `$` · 따옴표 등) 그 원격 응답을 형식 불일치로 보고 CLI 포함본을 씁니다.
41
+ - 앱 `package.json` 다음 워크스페이스 루트 `package.json` 의 선언도 「있음」으로 봅니다. 1.7.9 다음 patch 부터(WI-0095) Yarn Plug'n'Play 에서는 루트 선언을 「있음」으로 보지 않고 미선언과 같게 안내 명령에 넣습니다(앱이 루트에만 선언한 패키지를 해석하지 못해 컴포넌트의 import 가 실패함, MCP `axis.install_component` 도 같음).
41
42
  - `axis.config.json` 의 `componentsDir` · `agenticDir` 에 역슬래시(`src\components\ui`)를 적어도 `/` 로 읽습니다.
42
43
  - `axis list` 는 레지스트리 index 의 Core UI · Agentic UI 항목을 보여 줍니다(`--category ui|agentic`).
43
44
 
44
45
  ## 프로젝트 초기화 (`axis init`)
45
46
 
46
47
  - `axis.config.json` 과 `cn()` 을 담은 `utils.ts` 를 만들고, `clsx` · `tailwind-merge` 가 `package.json` 에 없으면 `dependencies` 에 더합니다. 설치는 실행하지 않고 명령만 안내합니다.
48
+ - 1.7.9 다음 patch 부터(WI-0095) Yarn Plug'n'Play 에서는 워크스페이스 루트 선언을 「이미 있음」으로 보지 않습니다(`axis check` 의 dependencies 항목과 같은 경계). 루트에만 선언한 `clsx` · `tailwind-merge` 는 앱이 해석하지 못해 `utils.ts` 의 import 가 실패하므로, 미선언과 같은 범위로 앱 `package.json` 에 더하고 「clsx, tailwind-merge 는 워크스페이스 루트에만 선언돼 Plug'n'Play 에서 앱이 해석하지 못합니다」를 함께 냅니다(종전에는 「이미 있습니다」로 쓰지 않았음). `tailwindcss` 가 루트에만 있으면 「! 필수 의존성 tailwindcss 가 워크스페이스 루트에만 선언돼 Plug'n'Play 에서 앱이 해석하지 못합니다 → 앱 package.json 에 선언하세요」 한 줄을 냅니다(`tailwindcss` 는 쓰지 않고, Tailwind 3 · 4 분기는 루트 선언으로 정함). PnP 가 아닌 워크스페이스(pnpm · npm · yarn node-modules)는 종전대로 루트 선언을 인정합니다. 종료 코드는 그대로입니다.
47
49
  - `axis.config.json` 의 `registry` 는 기본값(`https://axis-design-system.pages.dev/r`)이거나, 이미 있던 config 의 값입니다. 종전 기본값 `https://axis.minu.best/r` 는 Cloudflare 403 이라 바꿨습니다. add · list 는 그 값을 새 기본값으로 바꿔 읽으며 한 줄 알립니다(위 「컴포넌트 추가」, 파일은 고치지 않음). init 을 다시 실행하면 그 값을 새 기본값으로 바꿔 쓰고 「registry 를 새 기본 주소로 갱신」으로 알립니다. 사용자가 지정한 다른 값은 init 도 그대로 둡니다.
48
50
  - `utils.ts` 가 이미 있으면 같은 내용이면 「유지(이미 같은 내용)」(다시 쓰지 않음), 다르면 init 의 utils 로 덮어쓰고 「덮어씀」으로 알립니다(터미널이 아닌 곳에서 `-y` 없이 실행하면 덮어쓰지 않고 rc 1, 아래 「터미널이 아닌 곳에서 실행」). `utils.ts` 쓰기는 `axis add` 와 같은 규칙입니다: 심볼릭 링크면 같은 내용일 때 「유지(이미 같은 내용, 링크)」로 두고, 내용이 다른 링크(프로젝트 안 · 밖) · 깨진 링크 · 디렉터리 · 읽을 수 없는 파일 · 다른 경로와 하드링크로 이어진 파일은 쓰지 않고 그 사실을 알린 뒤 rc 1 입니다. 이 판정은 쓰기 전에 하므로 이때는 `axis.config.json` · `package.json` 도 쓰지 않습니다. 다른 경로와 하드링크로 이어진 `axis.config.json` 을 다시 써야 할 때도 같습니다.
49
51
  - 경로 기본값(`-y` 값 · 대화형 초기값)은 실제 프로젝트를 보고 정합니다(1.6.0 부터). `componentsDir` 는 `src/` 가 있으면 `./src/components/ui`, 없으면 `./components/ui` 이고 `src/` 를 새로 만들지 않습니다. `globalCss` 는 `app/globals.css` · `src/app/globals.css` · `styles/globals.css` · `src/styles/globals.css` · `globals.css` 가운데 실제로 있는 첫 파일, `tailwindConfig` 는 있는 `tailwind.config.{ts,js,mjs,cjs}` 가운데 첫 파일입니다. 찾지 못하면 기본값을 기록하고 그 사실을 한 줄 알립니다. Tailwind 4 안내 제목도 이 경로를 씁니다.
50
52
  - config 가 이미 있으면 출력이 「생성 완료」가 아니라 사실대로 「유지(이미 같은 내용)」 또는 「갱신」입니다. 갱신은 init 이 다루는 키(`$schema` · `componentsDir` · `tailwindConfig` · `globalCss` · `registry`)만 바꾸고, 그 밖의 키(`brand` · `monetDir` · `template` · `agenticDir` 등)는 값과 순서를 그대로 둡니다(1.6.0 부터, 이전에는 빠졌음). 들여쓰기도 기존 파일을 따릅니다. 기존 `componentsDir` 는 그대로 두고, `globalCss` · `tailwindConfig` 는 가리키는 파일이 있으면 그대로, 없으면 찾은 파일로 바꾸고 알립니다(찾지 못하면 그대로 두고 알림). Tailwind 4 이상이면 `tailwindConfig` 를 지우고 알립니다. `registry` 가 종전 기본값이면 위처럼 새 기본값으로 바꿉니다. `AXIS_REGISTRY_URL` 은 config 에 기록하지 않고 add · list 를 실행할 때만 우선합니다.
51
- - 애니메이션 플러그인(`tailwindcss-animate` · `tw-animate-css`)이 `package.json` 에 없으면, Dialog · Select 등의 열고 닫는 애니메이션에 필요하다는 안내 한 줄을 냅니다(Tailwind 3 은 plugins, Tailwind 4 는 `@import "tw-animate-css";`). 1.7.5 부터 선언은 앱 다음 워크스페이스 루트 `package.json` 까지 보고, 이름은 `axis check` 와 같습니다(Tailwind 3 은 `tailwindcss-animate` 만, Tailwind 4 는 `tw-animate-css` · `tailwindcss-animate` 둘 다). 선언과 설치본이 모두 있으면 안내하지 않고, 선언만 있고 설치본이 없으면 「선언돼 있지만 설치되지 않았습니다」와 설치 명령 · 설정 줄을 냅니다. Yarn PnP 는 루트 선언을 인정하지 않고 앱 선언이 있으면 안내하지 않습니다.
53
+ - 애니메이션 플러그인(`tailwindcss-animate` · `tw-animate-css`)이 `package.json` 에 없으면, Dialog · Select 등의 열고 닫는 애니메이션에 필요하다는 안내 한 줄을 냅니다(Tailwind 3 은 plugins, Tailwind 4 는 `@import "tw-animate-css";`). 1.7.5 부터 선언은 앱 다음 워크스페이스 루트 `package.json` 까지 보고, 이름은 `axis check` 와 같습니다(Tailwind 3 은 `tailwindcss-animate` 만, Tailwind 4 는 `tw-animate-css` · `tailwindcss-animate` 둘 다). 선언과 설치본이 모두 있으면 안내하지 않고, 선언만 있고 설치본이 없으면 「선언돼 있지만 설치되지 않았습니다」와 설치 명령 · 설정 줄을 냅니다(1.7.8 다음 patch 부터 npm 워크스페이스 루트 선언이면 설치 명령이 「워크스페이스 루트에서 npm install」, `clsx` · `tailwind-merge` 가 루트에 있을 때의 「설치는 실행하지 않았습니다. 설치: …」 줄도 같음). Yarn PnP 는 루트 선언을 인정하지 않고 앱 선언이 있으면 안내하지 않습니다.
54
+ - 1.7.9 다음 patch 부터(WI-0099) Tailwind 4 는 `axis check` 의 animation 항목과 같은 전역 CSS(`globalCss` 다음 후보, 상대 `@import` 하위 파일 포함)를 먼저 읽고 같은 판정을 씁니다. CSS 의 줄마다 그 줄이 가리키는 패키지(`@import "tw-animate-css"` → `tw-animate-css`, `@plugin "tailwindcss-animate"` → `tailwindcss-animate`)가 선언 · 설치돼 있으면 안내하지 않고, 아니면 「<파일>의 애니메이션 줄을 쓸 수 없습니다(<check 와 같은 사유>)」와 설치 명령을 냅니다. 다른 이름의 패키지만 설치돼 있으면(예: 줄은 `tw-animate-css` 인데 `tailwindcss-animate` 만 설치) 줄을 그 패키지로 바꾸는 대안을 함께 냅니다(종전에는 안내하지 않았고 check 만 WARN). CSS 에 줄이 없는데 패키지가 설치돼 있으면 「설치돼 있지만 <파일>에 애니메이션 줄이 없습니다」로 줄을 넣으라고 안내합니다(종전 침묵). 전역 CSS 파일이 없거나 Tailwind 3 이면 위 종전 판정 그대로입니다. 종료 코드와 쓰는 파일은 바뀌지 않습니다. Yarn PnP 에서 줄의 패키지가 워크스페이스 루트에만 선언된 경우는 WI-0099 에서 종전 그대로 두었고, WI-0095 부터 같은 판정으로 「…(tw-animate-css 가 워크스페이스 루트에만 선언돼 Plug'n'Play 에서 앱이 해석하지 못합니다). 설치하세요: yarn add tw-animate-css」입니다.
52
55
  - `tailwind-merge` 범위와 아래 안내는 프로젝트의 Tailwind 버전(설치본, 없으면 `package.json` 선언)으로 정합니다. 판정하지 못하면 Tailwind 3 으로 봅니다.
53
56
  - Tailwind 4 이상이면 전역 CSS 에 넣을 줄을 안내합니다. CSS 파일은 고치지 않습니다.
54
57
 
@@ -58,9 +61,9 @@ axis list
58
61
  @import "@axis-ds/ui-react/tailwind.css"; /* npm 패키지 컴포넌트를 쓸 때, agentic-ui 도 같은 방식 */
59
62
  ```
60
63
 
61
- - 컴포넌트 패키지 줄은 `package.json` 에 선언된 `@axis-ds/ui-react` · `@axis-ds/agentic-ui` 만큼 냅니다. 선언이 없으면 예시 한 줄만 냅니다(`axis add` 로 복사한 컴포넌트는 프로젝트 소스라 따로 넣을 필요가 없습니다).
64
+ - 컴포넌트 패키지 줄은 `package.json` 에 선언된 `@axis-ds/ui-react` · `@axis-ds/agentic-ui` 만큼 냅니다. 선언이 없으면 예시 한 줄만 냅니다(`axis add` 로 복사한 컴포넌트는 프로젝트 소스라 따로 넣을 필요가 없습니다). 1.7.9 다음 patch 부터(WI-0095) Yarn Plug'n'Play 에서 워크스페이스 루트에만 선언한 패키지는 줄 대신 `axis check` 와 같은 「! <패키지> 가 워크스페이스 루트에만 선언돼 Plug'n'Play 에서 앱이 해석하지 못합니다 → 앱 package.json 에 선언한 뒤 @import "<패키지>/tailwind.css";」를 냅니다(종전에는 줄을 그대로 냈고, 넣으면 빌드가 `Can't resolve`).
62
65
  - create-next-app 기본 `globals.css` 의 `:root` · `@theme inline` · `@media (prefers-color-scheme: dark)` · `body` 블록이 AXIS 와 같은 이름(`--background` · `--foreground` · `--color-background` · `--font-sans` · `--font-mono`)을 다른 값으로 정의하니 지우라는 주의를 함께 냅니다(Quick Start 가이드 「Tailwind CSS 4」와 같은 내용).
63
- - `@axis-ds/tokens` 가 `package.json` 에 없으면 lockfile 에 맞춘 설치 명령(예: `pnpm add "@axis-ds/tokens@^1.4.0"`)을 안내합니다. 토큰 진입점은 1.4.0 부터 있습니다.
66
+ - `@axis-ds/tokens` 가 `package.json` 에 없으면 lockfile 에 맞춘 설치 명령(예: `pnpm add "@axis-ds/tokens@^1.4.0"`)을 안내합니다. 토큰 진입점은 1.4.0 부터 있습니다. 1.7.9 다음 patch 부터(WI-0095) Yarn Plug'n'Play 에서 루트에만 선언했으면 같은 명령에 사유를 붙여 「@axis-ds/tokens 설치(워크스페이스 루트에만 선언돼 Plug'n'Play 에서 앱이 해석하지 못합니다): yarn add …」입니다(종전에는 안내하지 않았음).
64
67
  - `package.json` 에 선언된 `@axis-ds/tokens` · `@axis-ds/ui-react` · `@axis-ds/agentic-ui` 의 버전 조건(`axis check` 와 같은 함수 · 같은 판정). 설치본을 먼저 보고, 없으면 선언 범위를 봅니다:
65
68
  - 설치본: `node_modules/<패키지>/package.json` 의 `version` 이 정확한 버전이면 그것으로 판정합니다. 1.4.0 이상이면 선언이 `^1.3.0` · `1.x` · `catalog:` 여도 안내하지 않고, 미만이면(`1.4.0-beta.1` 포함) 설치본 버전을 보여 주며 `^1.4.0` 으로 올리는 명령을 냅니다(예: `설치본(@axis-ds/tokens 1.3.0, 선언 ^1.4.0)을 올리세요: pnpm add "@axis-ds/tokens@^1.4.0"`). 다만 설치본이 미만이어도 선언 하한을 읽을 수 없으면(`catalog:` · `npm:` · `latest` · `||` 등) 명령을 내지 않고 선언이 가리키는 버전을 1.4.0 이상으로 올린 뒤 다시 설치하라는 줄만 냅니다(선언을 덮어쓰지 않음).
66
69
  - 설치본이 없을 때 선언 범위의 하한이 1.4.0 미만이면(예: `^1.3.0` · `1.x` · `1.3.0 - 1.5.0` · `^1.4.0-beta.1`) 그 패키지들을 `^1.4.0` 으로 올리는 명령(예: `pnpm add "@axis-ds/tokens@^1.4.0"`)을 냅니다. 하이픈 범위는 왼쪽 버전을, 비교자 여러 개(`>=1.2 >=1.4`)는 가장 높은 하한을 봅니다.
@@ -90,7 +93,7 @@ axis theme add ontology
90
93
  - 넣은 import 줄의 출력은 1.6.1 부터 실제 위치 · 분류를 따릅니다. 컴포넌트 `tailwind.css` 는 「컴포넌트 스캔 경로, 위치 무관」, 기본 토큰 CSS 는 브랜드 줄보다 앞에 들어갔을 때만 「브랜드 앞」이고 뒤에 들어가면 옮기라고 경고합니다.
91
94
  - `@axis-ds/tokens` 가 없거나 1.3.0 미만이면 목록 대신 설치 · 업그레이드 안내를 내고 종료 코드 1 로 끝납니다.
92
95
  - 1.7.6 부터 `theme list` · `theme info` 의 안내는 선언 출처를 따릅니다. 앱이나 pnpm · yarn 워크스페이스 루트에 선언돼 있으면 「설치: <pm> install」, npm 워크스페이스 루트에 선언돼 있으면 「설치: 워크스페이스 루트에서 npm install」, 루트 선언이 1.3.0 미만이면 루트 선언을 올리라는 줄, 빌드 전 재설치도 install 입니다. Yarn PnP 에서 앱에 선언이 있으면 설치본을 판정하지 못했다는 한 줄을 냅니다. 선언이 없으면(또는 PnP · 앱 자체 lockfile 이라 루트 선언을 보지 않으면) 종전 추가 명령입니다.
93
- - 같은 1.7.6 부터 `theme add` 는 앱에 선언된 tokens 가 설치되지 않았으면 「설치: <pm> install」을, 설치본이 빌드 전이면 선언 출처(앱 · 루트)와 상관없이 `theme list` 와 같은 재설치 안내(npm 워크스페이스 루트 선언이면 「워크스페이스 루트에서 npm install」)를 더합니다. Yarn PnP 에서 앱에 선언이 있으면 설치 · 재설치 · 업그레이드 줄 대신 `theme list` 와 같은 판정하지 못했다는 한 줄을 냅니다. 루트 선언 미설치의 「설치: <pm> install」 줄은 npm 이어도 앱 디렉터리 명령 그대로입니다.
96
+ - 같은 1.7.6 부터 `theme add` 는 앱에 선언된 tokens 가 설치되지 않았으면 「설치: <pm> install」을, 설치본이 빌드 전이면 선언 출처(앱 · 루트)와 상관없이 `theme list` 와 같은 재설치 안내(npm 워크스페이스 루트 선언이면 「워크스페이스 루트에서 npm install」)를 더합니다. Yarn PnP 에서 앱에 선언이 있으면 설치 · 재설치 · 업그레이드 줄 대신 `theme list` 와 같은 판정하지 못했다는 한 줄을 냅니다. 루트 선언 미설치의 「설치: <pm> install」 줄은 1.7.8 까지 npm 이어도 앱 디렉터리 명령이었고, 1.7.8 다음 patch 부터 npm 워크스페이스 루트 선언이면 「설치: 워크스페이스 루트에서 npm install」입니다(앱 디렉터리의 `npm install` 은 루트에만 선언한 패키지를 설치하지 않음, npm 7 ~ 10 실측). 루트에만 선언한 컴포넌트 패키지가 설치되지 않아 `tailwind.css` 줄을 넣지 않았다는 안내의 설치 구절도 같습니다.
94
97
  - `axis check` 는 `axis.config.json` 의 `brand` 와 CSS 의 브랜드 import 가 맞는지도 봅니다.
95
98
 
96
99
  ## 프로젝트 검증 (`axis check`)
@@ -100,20 +103,22 @@ axis theme add ontology
100
103
  - Tailwind 구성 항목: Tailwind 4 이상(설치본, 없으면 `package.json` 선언으로 판정)은 설정 파일 대신 위 전역 CSS 선택이 고른 파일 하나(상대 `@import` 로 들여온 하위 파일 포함)를 봅니다. Tailwind 3 이하는 `tailwind.config.ts` · `.js` · `.mjs` · `.cjs` 를 찾습니다.
101
104
  - Tailwind 4: `@import "tailwindcss"` 가 있는 CSS 에서 아래 문제가 하나도 없으면 PASS 이고, 하나라도 있으면 WARN 입니다(블록 주석 안은 없는 것으로 봅니다). `@import "tailwindcss"` 가 없으면 그 WARN 하나만 냅니다.
102
105
  1. 토큰 진입점 `@import "@axis-ds/tokens/css/tailwind4";` 이 없음 → 문구에 넣을 import 줄. 진입점이 없으면 `bg-primary` · `rounded-md` 같은 AXIS 매핑이 만들어지지 않습니다. `@axis-ds/tokens/css` · `css/shadcn` · `tailwind`(Tailwind 3 preset)는 진입점으로 치지 않습니다.
103
- 2. `package.json` 에 선언된 `@axis-ds/ui-react` · `@axis-ds/agentic-ui` 의 `tailwind.css` import 가 없음 → 빠진 import 줄. 선언이 없으면(복사 설치) 요구하지 않습니다. 1.7.7 부터는 그 줄이 이 앱에서 해석될 때만 줄을 바로 안내합니다. 앱 `package.json` 선언과, 설치본에 `tailwind.css` 가 있는 워크스페이스 루트 선언은 종전대로 줄을 안내합니다. 해석되지 않는 루트 선언은 먼저 할 일을 안내합니다: Plug'n'Play 에서 루트에만 선언(→ 앱 `package.json` 에 선언한 뒤 줄), 설치본 없음(→ 설치 뒤 줄), 설치본이 1.4.0 미만이거나 버전을 읽지 못함(→ 1.4.0 이상으로 올린 뒤 줄), 1.4.0 이상인데 `tailwind.css` 가 없음(→ 다시 설치 뒤 줄). 앱 디렉터리에 lockfile 이 있으면 루트 선언을 선언으로 보지 않습니다(`axis theme add` 와 같은 판정). 1.7.6 까지는 선언만 보고 줄을 안내해, 그대로 넣으면 빌드가 `Can't resolve` 로 깨질 수 있었습니다. `tailwind.css` 대신 그 패키지를 가리키는 `@source` 를 같은 CSS 에 직접 썼으면(예: `@source "../node_modules/@axis-ds/ui-react/dist";`, 작은따옴표 · 다른 상대 경로 포함) 스캔 경로가 있는 것으로 봅니다. 경로 문자열에 `@axis-ds/<패키지>` 가 들어 있고 그 바로 뒤가 경로 끝 · `/` · `\` 이면(`@axis-ds/ui-react-extra` 같은 다른 이름은 아님) 그 패키지를 가리킨다고 판정합니다(경로가 실제로 있는지는 보지 않음). 주석 안 · `@source not` · `@source inline()` 은 인정하지 않고, brace 확장(`@source "{…/@axis-ds/ui-react,…}/dist"`) · `@import "…" source("…")` 형태도 인정하지 않습니다(WARN 쪽으로 판정).
106
+ 2. `package.json` 에 선언된 `@axis-ds/ui-react` · `@axis-ds/agentic-ui` 의 `tailwind.css` import 가 없음 → 빠진 import 줄. 선언이 없으면(복사 설치) 요구하지 않습니다. 1.7.7 부터는 그 줄이 이 앱에서 해석될 때만 줄을 바로 안내합니다. 앱 `package.json` 선언과, 설치본에 `tailwind.css` 가 있는 워크스페이스 루트 선언은 종전대로 줄을 안내합니다. 해석되지 않는 루트 선언은 먼저 할 일을 안내합니다: Plug'n'Play 에서 루트에만 선언(→ 앱 `package.json` 에 선언한 뒤 줄), 설치본 없음(→ 설치 뒤 줄), 설치본이 1.4.0 미만이거나 버전을 읽지 못함(→ 1.4.0 이상으로 올린 뒤 줄), 1.4.0 이상인데 `tailwind.css` 가 없음(→ 다시 설치 뒤 줄). 앱 디렉터리에 lockfile 이 있으면 루트 선언을 선언으로 보지 않습니다(`axis theme add` 와 같은 판정). 1.7.9 부터 Yarn Plug'n'Play 에서 앱에 선언한 패키지가 `.yarn/cache` zip 안에만 있으면(앱 선언 범위에 맞는 `.yarn/unplugged/*/node_modules/<패키지>` 가 없음) 줄만 넣어도 `tailwind.css` 의 `@source "./dist"` 가 스캔되지 않아 컴포넌트 클래스가 생기지 않으므로, 줄 대신 「Plug'n'Play 루트(.pnp.cjs 가 있는 곳) package.json 의 dependenciesMeta 에 `"<패키지>": { "unplugged": true }` 를 두고 yarn install 뒤 줄」을 안내합니다(앱 `package.json` 의 `dependenciesMeta` 는 Yarn 이 따르지 않음). `workspace:` · `portal:` · `link:` 범위는 설치본이 실제 디렉터리라 종전 판정입니다. 1.7.6 까지는 선언만 보고 줄을 안내해, 그대로 넣으면 빌드가 `Can't resolve` 로 깨질 수 있었습니다. `tailwind.css` 대신 그 패키지를 가리키는 `@source` 를 같은 CSS 에 직접 썼으면(예: `@source "../node_modules/@axis-ds/ui-react/dist";`, 작은따옴표 · 다른 상대 경로 포함) 스캔 경로가 있는 것으로 봅니다. 경로 문자열에 `@axis-ds/<패키지>` 가 들어 있고 그 바로 뒤가 경로 끝 · `/` · `\` 이면(`@axis-ds/ui-react-extra` 같은 다른 이름은 아님) 그 패키지를 가리킨다고 판정합니다(경로가 실제로 있는지는 보지 않음). 주석 안 · `@source not` · `@source inline()` 은 인정하지 않고, brace 확장(`@source "{…/@axis-ds/ui-react,…}/dist"`) · `@import "…" source("…")` 형태도 인정하지 않습니다(WARN 쪽으로 판정).
104
107
  3. 진입점이 있는데 create-next-app 기본 정의가 남음 → 실제로 남은 정의 이름(예: `--font-sans` 만 남았으면 `@theme --font-sans: var(--font-geist-sans)` 만 표시). `--background` · `--foreground` 를 색값(`#ffffff` · `rgb()` · `oklch()` 등)으로 정의, `--color-background: var(--background)` 류, `--font-sans` · `--font-mono: var(--font-geist-*)`, `background` · `color: var(--background)` 류 직접 사용을 봅니다(create-next-app 15.5.28 기본 `globals.css` 실물 기준). AXIS 의 HSL 삼중값(`0 0% 100%`) 재정의나 `hsl(var(--background))` 는 걸리지 않습니다. 표시 앞머리(`:root 색값` · `@theme` · `body`)는 create-next-app 기본 블록 이름이라, 같은 선언이 다른 선택자에 있어도 그 이름으로 표시됩니다.
105
108
  4. 진입점이 있는데 `@axis-ds/tokens` 가 아래 버전 조건에 걸림.
106
- 5. `@axis-ds/ui-react/tailwind.css` · `@axis-ds/agentic-ui/tailwind.css` 를 import 하는데 그 패키지가 아래 버전 조건에 걸림(`tailwind.css` 는 1.4.0 부터 있음). 직접 `@source` 로 스캔하는 패키지는 `tailwind.css` 가 필요 없으므로 이 문제를 만들지 않습니다. 1.7.7 부터는 줄이 이미 있어도 2번의 해석되지 않는 루트 선언(Plug'n'Play 루트 전용 · 설치본 없음 · 설치본에 `tailwind.css` 없음 · 버전을 읽지 못함)이면 버전 조건 대신 「`<패키지>/tailwind.css` import 가 있지만 … 해석되지 않습니다」 WARN 입니다(1.4.0 미만 설치본은 종전 버전 조건 문구, 1.7.6 까지는 버전 조건만 봐서 PASS 일 수 있었음). 1.7.8 부터는 아래 중첩 설치본 판정도 이 자리에 나옵니다.
109
+ 5. `@axis-ds/ui-react/tailwind.css` · `@axis-ds/agentic-ui/tailwind.css` 를 import 하는데 그 패키지가 아래 버전 조건에 걸림(`tailwind.css` 는 1.4.0 부터 있음). 직접 `@source` 로 스캔하는 패키지는 `tailwind.css` 가 필요 없으므로 이 문제를 만들지 않습니다. 1.7.7 부터는 줄이 이미 있어도 2번의 해석되지 않는 루트 선언(Plug'n'Play 루트 전용 · 설치본 없음 · 설치본에 `tailwind.css` 없음 · 버전을 읽지 못함)이면 버전 조건 대신 「`<패키지>/tailwind.css` import 가 있지만 … 해석되지 않습니다」 WARN 입니다(1.4.0 미만 설치본은 종전 버전 조건 문구, 1.7.6 까지는 버전 조건만 봐서 PASS 일 수 있었음). 1.7.8 부터는 아래 중첩 설치본 판정도 이 자리에 나옵니다. 1.7.9 부터 2번의 Plug'n'Play zip 조건(앱 선언 · unplugged 없음)에서는 줄이 있어도 PASS 가 아니라 「`<패키지>/tailwind.css` import 가 있지만 Plug'n'Play 에서 @source "./dist" 가 .yarn/cache zip 안을 가리켜 컴포넌트 클래스가 생성되지 않습니다 → … unplugged … yarn install 하세요」 WARN 입니다(1.7.8 까지는 PASS, 종료 코드는 그대로).
107
110
  - 프로젝트 밖 전역 CSS(1.7.7 부터): 고른 파일이 앱 밖(`globalCss` 가 `../shared/globals.css` 등)이면 그 파일의 `@import "tailwindcss"` 와 컴포넌트 `tailwind.css` 줄을 그 파일 위치 기준으로도 봅니다. 빌드 도구가 패키지 경로를 그 CSS 파일 위치부터 상위 `node_modules` 로 풀기 때문입니다(설치본이 앱 아래에만 있으면 빌드가 `Can't resolve` 로 실패, 공통 상위로 호이스팅하면 성공). 앱에서는 설치본을 찾는데 그 파일 위치에서는 찾지 못하면 「import 가 있지만 이 파일 위치에서 <패키지> 를 찾지 못해 해석되지 않습니다」 WARN 입니다(`tailwindcss` 줄은 문제 목록 맨 앞, 컴포넌트 줄은 5번 자리). 토큰 진입점 줄은 globals.css 항목이 같은 기준으로 알립니다. Plug'n'Play 이거나 앱 위치에서 설치본을 찾지 못하면 이 판정을 하지 않습니다.
108
- - 중첩 설치본(그림자, 1.7.8 부터): 앱 안 CSS(진입 파일 · 상대 `@import` 로 들여온 하위 파일)의 tokens CSS import 줄(`@axis-ds/tokens/css` · `css/shadcn` · `css/tailwind4`, globals.css 항목)과 컴포넌트 `tailwind.css` 줄(위 5번 자리)은 그 줄이 있는 파일 위치부터 Tailwind 4 빌드 도구와 같은 순서로 풉니다. 위로 올라가며 `node_modules/<패키지>` 를 찾고, 먼저 잡힌 설치본에 `exports` 가 있으면 그 `exports`(조건 `style` · `default`)로만 풉니다. 그 설치본이 앱 기준 설치본과 실경로가 다르고(예: `app/node_modules` 에 남은 1.3.0) subpath 를 내보내지 않거나 내보낸 파일이 없으면 빌드가 실패하므로 「import 가 있지만 그 줄이 있는 파일 위치에서 먼저 잡히는 app/node_modules/@axis-ds/ui-react(1.3.0)가 ./tailwind.css 를 내보내지 않아 해석되지 않습니다 → 그 중첩 node_modules 의 @axis-ds/ui-react 를 지우거나 1.4.0 이상으로 맞추세요」 같은 WARN 입니다(이미 1.4.0 이상이면 「다시 설치하세요」). `exports` 도 그 파일도 없는 중첩 디렉터리는 빌드 도구처럼 건너뛰고 상위 설치본으로 봅니다. 앱과 워크스페이스 루트에 설치본이 없고, 그 줄이 있는 파일 위치에서는 풀리지 않는데 같은 전역 CSS 의 다른 파일 위치에서만 풀리면 「설치본이 <경로> 에만 있음」 WARN 입니다. 그림자 파일의 내용은 보지 않고, 프로젝트 밖 전역 CSS · `@import "tailwindcss"` 줄 · Tailwind 3 은 종전대로입니다. 1.7.7 까지는 앱 안 진입 파일의 줄은 앱 기준으로만, 하위 파일의 줄은 처음 만난 설치본(tokens 는 디렉터리, 컴포넌트는 `tailwind.css` 파일)만 봐서 빌드가 실패하는 그림자도 PASS 일 수 있었습니다.
111
+ - 중첩 설치본(그림자, 1.7.8 부터): 앱 안 CSS(진입 파일 · 상대 `@import` 로 들여온 하위 파일)의 tokens CSS import 줄(`@axis-ds/tokens/css` · `css/shadcn` · `css/tailwind4`, globals.css 항목)과 컴포넌트 `tailwind.css` 줄(위 5번 자리)은 그 줄이 있는 파일 위치부터 Tailwind 4 빌드 도구와 같은 순서로 풉니다. 위로 올라가며 `node_modules/<패키지>` 를 찾고, 먼저 잡힌 설치본에 `exports` 가 있으면 그 `exports`(조건 `style` · `default`)로만 풉니다. 그 설치본이 앱 기준 설치본과 실경로가 다르고(예: `app/node_modules` 에 남은 1.3.0) subpath 를 내보내지 않거나 내보낸 파일이 없으면 빌드가 실패하므로 「import 가 있지만 그 줄이 있는 파일 위치에서 먼저 잡히는 app/node_modules/@axis-ds/ui-react(1.3.0)가 ./tailwind.css 를 내보내지 않아 해석되지 않습니다 → 그 중첩 node_modules 의 @axis-ds/ui-react 를 지우거나 1.4.0 이상으로 맞추세요」 같은 WARN 입니다(이미 1.4.0 이상이면 「다시 설치하세요」). `exports` 도 그 파일도 없는 중첩 디렉터리는 빌드 도구처럼 건너뛰고 상위 설치본으로 봅니다. 앱과 워크스페이스 루트에 설치본이 없고, 그 줄이 있는 파일 위치에서는 풀리지 않는데 같은 전역 CSS 의 다른 파일 위치에서만 풀리면 「설치본이 <경로> 에만 있음」 WARN 입니다. 그림자 파일의 내용은 보지 않고, 프로젝트 밖 전역 CSS · `@import "tailwindcss"` 줄은 종전대로입니다. Tailwind 3 의 tokens 줄은 1.7.9 부터 이 가운데 「먼저 잡히는 그림자가 subpath 를 내보내지 않음」만 봅니다(globals.css 항목 설명 참고). 1.7.7 까지는 앱 안 진입 파일의 줄은 앱 기준으로만, 하위 파일의 줄은 처음 만난 설치본(tokens 는 디렉터리, 컴포넌트는 `tailwind.css` 파일)만 봐서 빌드가 실패하는 그림자도 PASS 일 수 있었습니다.
109
112
  - 문제가 여럿이면 위 순서대로 ` / ` 로 이어 한 항목에 냅니다. 끝에는 `package.json` 에 선언된 세 AXIS 패키지 가운데 1.4.0 미만인 것을 `(1.4.0 이상 필요: @axis-ds/tokens ^1.3.0)`, 판정할 수 없는 것을 `(설치된 버전이 1.4.0 이상인지 확인하세요: @axis-ds/agentic-ui catalog:)` 로 한 번 덧붙입니다. 버전은 `axis init` 과 같은 함수로 판정합니다: 설치본(`node_modules/<패키지>/package.json` 의 정확한 `version`)이 있으면 그것으로 보고(`(1.4.0 이상 필요: @axis-ds/ui-react 설치본 1.3.0)`, 1.4.0 이상이면 선언과 관계없이 넣지 않음), 없으면 선언 범위의 하한, 하한도 읽을 수 없으면(`catalog:` · `latest` · `||` 등) 판정 불가입니다. `workspace:` 는 넣지 않습니다.
110
113
  - 문구 예: `Tailwind 4: globals.css에 AXIS 토큰 진입점이 없습니다 → @import "@axis-ds/tokens/css/tailwind4"; / 컴포넌트 스캔 경로(tailwind.css)가 없습니다 → @import "@axis-ds/ui-react/tailwind.css"; (1.4.0 이상 필요: @axis-ds/tokens ^1.3.0 · @axis-ds/ui-react ^1.3.0)`
111
114
  - Tailwind 3: 설정 파일(`.ts` · `.js` · `.mjs` · `.cjs`)이 `@axis-ds/tokens/tailwind` preset 을 `require` · `import` 하면(주석 밖) `tailwind.config.ts에 AXIS 토큰이 설정되어 있습니다 (@axis-ds/tokens/tailwind preset)` 처럼 PASS 이고(1.7.8 부터는 아래 tokens 해석 조건도 맞아야 함), 없으면 WARN 입니다(1.6.0 부터. 이전에는 `--background` · `hsl(var(` 문자열만 있어도 PASS 여서 AXIS 참조가 없는 자체 매핑도 통과했습니다).
112
115
  - Tailwind 3 CommonJS(1.6.1 부터): 설정이 `.cjs` 이거나 `module.exports` 를 쓰고 `.default` 없는 `require("@axis-ds/tokens/tailwind")` 가 있으면, 설치본(없으면 선언 하한. 1.7.8 부터 선언 하한으로 가는 것은 아래 tokens 해석 조건을 통과한 경우뿐) `@axis-ds/tokens` 가 1.7.0 미만일 때 WARN 입니다. 1.6.2 이하의 이 형태는 preset 이 아니라 `{ default }` 를 받아 색 · keyframes 가 빠집니다(1.1.0 부터). `.ts` · `.mjs` 의 `export default` 안 `require` 와 `import` 형태는 Tailwind 가 `.default` 를 꺼내 줘서 이 버전 판정을 하지 않습니다.
113
116
  - Tailwind 3 preset 의 tokens 해석(1.7.8 부터): 위 두 판정 앞에서, preset 을 어떤 모양(`require` · `.default` · `import` · `.ts`)으로 받든 `@axis-ds/tokens` 가 이 앱에서 해석되는지 봅니다. globals.css 항목과 같은 기준이라, 앱 `package.json` 에 선언했으면 설치 여부와 상관없이 종전 판정(미설치는 dependencies 항목이 알림)이고, 선언이 없거나 워크스페이스 루트에만 선언했으면 설치본 디렉터리가 있을 때만 종전 판정입니다. 설치본이 없으면 「tailwind.config.mjs에 AXIS preset 참조가 있지만 @axis-ds/tokens 가 설치되지 않아 해석되지 않습니다 → 설치(…)」, Plug'n'Play 에서 루트에만 선언했으면 「… 워크스페이스 루트에만 선언돼 Plug'n'Play 에서 앱이 해석하지 못합니다(워크스페이스 루트 선언 …) → 앱 package.json 에 @axis-ds/tokens 를 선언하세요」 WARN 입니다(CommonJS bare require 는 바로 위 단락의 종전 문구 「… 1.7.0 이상을 선언하세요」). 1.7.7 까지는 PASS 였고, CommonJS bare require 는 이미 WARN 이었던 경우(미선언 · 미설치, 루트 1.7.0 미만 선언 · 미설치)에 문구만 바뀝니다. 종료 코드는 그대로입니다. 이 레이아웃은 Tailwind 빌드가 `Cannot find module '@axis-ds/tokens/tailwind'` 로 실패합니다. 1.7.0 버전 판정은 종전대로 CommonJS bare require 만 봅니다.
114
- - globals.css 항목: 위 전역 CSS 선택이 고른 CSS 하나(상대 `@import` 로 들여온 하위 파일 포함, Arial 은 진입 파일만)를 봅니다(Tailwind 3 이하도 같음). 고를 파일이 하나도 없으면 FAIL 입니다. 1.6.1 부터 AXIS 근거가 있을 때만 PASS 입니다: `@axis-ds/tokens/css` · `@axis-ds/tokens/css/shadcn` · `@axis-ds/tokens/css/tailwind4` import(블록 주석 밖, 작은따옴표 · `url()` · `layer()` 표기 포함, 문구 끝에 `(@axis-ds/tokens/css/tailwind4 import)` 처럼 경로), `--axis-*` 변수 정의, 또는 루트 레이아웃(`app/layout.tsx` 등)의 `import "@axis-ds/tokens/css"`. 1.7.7 부터 tokens import(CSS · 루트 레이아웃 JS)는 이 앱에서 해석될 때만 근거로 칩니다. 앱 `package.json` 에 `@axis-ds/tokens` 를 선언했으면 설치 여부와 상관없이 종전대로 PASS 이고(미설치는 dependencies 항목이 알림), 선언이 없거나 워크스페이스 루트에만 선언했으면 설치본 디렉터리(`node_modules/@axis-ds/tokens`, 상위 디렉터리 포함)가 있을 때 PASS 입니다. 설치본이 없으면 「<경로> import 가 있지만 @axis-ds/tokens 가 설치되지 않아 해석되지 않습니다 → 설치(…)」, Plug'n'Play 에서 루트에만 선언했으면 「… 워크스페이스 루트에만 선언돼 Plug'n'Play 에서 앱이 해석하지 못합니다 → 앱 package.json 에 선언하세요」 WARN 입니다(1.7.6 까지는 PASS, 종료 코드는 그대로). 고른 파일이 프로젝트 밖이면 Tailwind 구성 항목과 같이 그 파일 위치에서 설치본이 보이는지도 봅니다. `--axis-*` 변수 정의는 이 판정을 거치지 않습니다. 단, 해석되지 않는 tokens import 가 함께 있으면 import 판정을 따라 WARN 입니다. 자체 `--background` · `--primary` 만 있으면 「자체 CSS 변수만 있고 AXIS 토큰이 없습니다」 WARN 입니다(1.6.0 까지는 PASS). Tailwind 3 에서 create-next-app 기본 `body` 의 `font-family: Arial` 이 남아 있으면 PASS 조건을 채워도 WARN 입니다(Tailwind 4 는 tailwind.config 항목의 create-next-app 기본 정의로 냅니다).
117
+ - Tailwind 3 preset 의 exports(1.7.9 부터): 위 해석 판정을 통과해도(앱 선언 포함), 설정 파일 위치부터 위로 올라가며 처음 잡히는 `@axis-ds/tokens` 설치본에 `exports` 가 있는데 `./tailwind` 를 내보내지 않으면 「tailwind.config.mjs에 AXIS preset 참조가 있지만 먼저 잡히는 node_modules/@axis-ds/tokens(1.8.2)가 ./tailwind 를 내보내지 않아 해석되지 않습니다 → 그 node_modules 의 @axis-ds/tokens 를 지우거나 다시 설치하세요」 WARN 입니다. Node 해석기가 거기서 멈춰 빌드가 `ERR_PACKAGE_PATH_NOT_EXPORTED` 로 실패하기 때문입니다(앱 `node_modules` 의 중첩 설치본이 워크스페이스 루트의 정상 설치본을 가리는 경우 포함). 조건부 `exports` 는 `require(...)` 참조면 `require` · `node` · `module-sync` · `default`, `import` 참조면 여기에 `import` 까지 맞는 것으로 봅니다(Tailwind 3.4 가 설정을 `require` 로 읽고 실패하면 jiti 로 다시 읽음, Node 22.22 측정). `exports` 가 없고 `tailwind` 파일도 없는 설치본 디렉터리는 건너뛰거나 판정하지 않고, 내보낸 대상 파일이 없는 경우(dist 를 아직 빌드하지 않은 workspace 링크 등)도 판정하지 않습니다. 발행된 `@axis-ds/tokens` 는 모든 버전이 `./tailwind` 를 내보내므로 손으로 만든 · 손상된 설치본에서만 생깁니다. 종료 코드는 그대로입니다.
118
+ - globals.css 항목: 위 전역 CSS 선택이 고른 CSS 하나(상대 `@import` 로 들여온 하위 파일 포함, Arial 은 진입 파일만)를 봅니다(Tailwind 3 이하도 같음). 고를 파일이 하나도 없으면 FAIL 입니다. 1.6.1 부터 AXIS 근거가 있을 때만 PASS 입니다: `@axis-ds/tokens/css` · `@axis-ds/tokens/css/shadcn` · `@axis-ds/tokens/css/tailwind4` import(블록 주석 밖, 작은따옴표 · `url()` · `layer()` 표기 포함, 문구 끝에 `(@axis-ds/tokens/css/tailwind4 import)` 처럼 경로), `--axis-*` 변수 정의, 또는 루트 레이아웃(`app/layout.tsx` 등)의 `import "@axis-ds/tokens/css"`. 1.7.7 부터 tokens import(CSS · 루트 레이아웃 JS)는 이 앱에서 해석될 때만 근거로 칩니다. 앱 `package.json` 에 `@axis-ds/tokens` 를 선언했으면 설치 여부와 상관없이 종전대로 PASS 이고(미설치는 dependencies 항목이 알림), 선언이 없거나 워크스페이스 루트에만 선언했으면 설치본 디렉터리(`node_modules/@axis-ds/tokens`, 상위 디렉터리 포함)가 있을 때 PASS 입니다. 설치본이 없으면 「<경로> import 가 있지만 @axis-ds/tokens 가 설치되지 않아 해석되지 않습니다 → 설치(…)」, Plug'n'Play 에서 루트에만 선언했으면 「… 워크스페이스 루트에만 선언돼 Plug'n'Play 에서 앱이 해석하지 못합니다 → 앱 package.json 에 선언하세요」 WARN 입니다(1.7.6 까지는 PASS, 종료 코드는 그대로). 고른 파일이 프로젝트 밖이면 Tailwind 구성 항목과 같이 그 파일 위치에서 설치본이 보이는지도 봅니다. Tailwind 3 에서도 1.7.9 부터 앱 안 진입 파일 · 하위 파일의 tokens 줄 위치에서 먼저 잡히는 중첩 설치본이 그 subpath 를 내보내지 않으면(조건 `style` · `default` 가 맞지 않는 경우 포함) 「… 먼저 잡히는 src/styles/node_modules/@axis-ds/tokens(…)가 ./css 를 내보내지 않아 해석되지 않습니다 → 그 중첩 node_modules 의 @axis-ds/tokens 를 지우거나 다시 설치하세요」 WARN 입니다(Next 14 + Tailwind 3 빌드가 `Package path ./css is not exported` 로 실패, 대상 파일만 없는 그림자는 Next 가 상위 설치본으로 풀어 판정하지 않음). `--axis-*` 변수 정의는 이 판정을 거치지 않습니다. 단, 해석되지 않는 tokens import 가 함께 있으면 import 판정을 따라 WARN 입니다. 자체 `--background` · `--primary` 만 있으면 「자체 CSS 변수만 있고 AXIS 토큰이 없습니다」 WARN 입니다(1.6.0 까지는 PASS). Tailwind 3 에서 create-next-app 기본 `body` 의 `font-family: Arial` 이 남아 있으면 PASS 조건을 채워도 WARN 입니다(Tailwind 4 는 tailwind.config 항목의 create-next-app 기본 정의로 냅니다).
115
119
  - dependencies 항목(1.6.1 부터): `tailwindcss` 선언이 없으면 FAIL, `clsx` · `tailwind-merge` 선언이 없으면 WARN(종전과 같음). 여기에 선언된 `tailwindcss` · `clsx` · `tailwind-merge` · `@axis-ds/*` 가 `node_modules` 에 없으면 「선언됐지만 설치되지 않은 의존성」 WARN 과 lockfile 에 맞는 설치 명령을 냅니다. 상위 디렉터리의 `node_modules`(모노레포 호이스팅)도 찾고, Plug'n'Play(`.pnp.cjs`)는 설치본을 읽지 않고 선언 기준입니다. 1.6.0 까지는 선언만 보고 「모두 설치되어 있습니다」였습니다.
116
120
  - 1.7.6 부터 워크스페이스 루트 `package.json` 에 선언한 `@axis-ds/*`(앱에 없는 것)도 설치 확인 대상이고, 설치되지 않았으면 「워크스페이스 루트에 선언돼 있지만 설치되지 않았습니다」 WARN 입니다(종료 코드는 그대로, 1.7.5 까지는 앱 선언만 봐서 PASS).
121
+ - 1.7.8 다음 patch 부터 npm 워크스페이스에서 미설치 묶음에 루트 선언이 있으면 설치 명령이 「→ 워크스페이스 루트에서 npm install」입니다(앱 디렉터리의 `npm install` 은 루트 선언을 설치하지 않음). pnpm · yarn 과 앱 선언만인 묶음은 종전 「→ <pm> install」이고 종료 코드는 그대로입니다.
117
122
  - 1.7.6 부터 Plug'n'Play 는 워크스페이스 루트 선언을 인정하지 않습니다. 앱이 자기 `package.json` 에 없는 패키지를 해석하지 못하기 때문입니다. 루트에만 있는 `tailwindcss` 는 「워크스페이스 루트에만 선언돼 Plug'n'Play 에서 앱이 해석하지 못합니다」 FAIL, `clsx` · `tailwind-merge` · `@axis-ds/*` 는 같은 문구의 WARN 입니다(1.7.5 까지는 PASS). `.pnp.cjs` 는 `.git` 이 있는 층에서 찾기를 멈춥니다. `pnpFallbackMode: all` 설정은 읽지 않습니다.
118
123
  - 해당할 때만 더하는 항목(1.6.0 부터, brand 항목 뒤 이 순서):
119
124
  - `brand.activation`: `brand` 가 있을 때 루트 레이아웃(`app/layout.tsx` · `src/app/layout.tsx` · `pages/_app` 등, 그 레이아웃이 import 하는 같은 디렉터리의 `./providers` 한 단계 포함)에 `data-brand` · `setBrand(` · `defaultBrand=` 가 없으면 WARN 입니다(휴리스틱, `ThemeProvider` 단독은 켜는 코드가 아님). 1.6.1 부터 마크업 `data-brand` 와 `ThemeProvider` 만 있고 `setBrand(` · `defaultBrand=` 가 없으면 설치본(없으면 선언) `@axis-ds/theme` 가 1.7.0 미만이거나 판정할 수 없을 때 WARN 입니다(1.6.2 이하는 마운트 때 속성을 지움). 1.7.6 부터 Plug'n'Play 에서 `@axis-ds/theme` 가 워크스페이스 루트에만 선언돼 있으면 「앱이 해석하지 못합니다」 WARN 입니다(Tailwind 3 CommonJS preset 의 `@axis-ds/tokens` 판정도 같음).
@@ -139,6 +144,7 @@ stdin 이 터미널이 아니면 질문을 띄우지 않습니다(1.7.0 부터).
139
144
  - `axis template init -y` 는 질문을 기본값으로 답하고, 비어 있지 않은 디렉터리도 진행합니다(`template apply -y` 와 같은 뜻). 터미널에서도 같습니다.
140
145
  - 판정은 stdin 이 터미널인지 하나로 합니다. 그래서 `printf '\n' | axis template init dashboard` 처럼 파이프로 응답을 넣던 스크립트도 이제는 묻지 않고 위 표대로 동작합니다. 값은 `--dir` · `-y` 같은 옵션으로 주세요.
141
146
  - `axis template apply` 의 「필요한 의존성」 명령과 `axis template init` 의 다음 단계(`install` · `dev`)는 대상 디렉터리의 lockfile(없으면 `packageManager`)로 매니저를 고르고 범위를 따옴표로 감쌉니다(1.7.2 부터, 1.7.1 까지는 `pnpm` 고정).
147
+ - `axis template apply` · `template init` 이 덮어쓰는 파일 가운데 템플릿 루트의 `package.json` · `axis.config.json` 은 기존 파일과 합칩니다(WI-0088). package.json 은 `packageManager` · `name` · `version` · `workspaces` 등 최상위 필드를 사용자 값으로 두고, `scripts` · `dependencies` · `devDependencies` · `peerDependencies` · `optionalDependencies` 는 키 단위로 합쳐 같은 키만 템플릿 값을 씁니다. axis.config.json 은 같은 키를 템플릿 값으로, 사용자에게만 있는 키는 남깁니다. 충돌 목록 · `--dry-run` 은 이 파일을 「합치기」로 보여 주고, JSON 으로 읽을 수 없는 기존 파일은 종전처럼 덮어쓰며 알립니다. 파일을 쓰는 도중 실패하면 건드린 파일을 되돌리고 rc 1 입니다. 템플릿 경로가 대상 디렉터리 밖(절대 경로 · `..` · 밖을 가리키는 심볼릭 링크 경유)이면 `template apply` · `init` · `diff` 는 아무 파일도 쓰거나 읽지 않고 rc 1 입니다.
142
148
  - Windows Git Bash(mintty)처럼 사람이 앞에 있어도 stdin 이 터미널로 잡히지 않는 환경에서는 질문 없이 위 표대로 동작할 수 있습니다(실측 전). 질문이 뜨지 않으면 `winpty npx axis ...` 로 실행하거나, PowerShell · Windows Terminal 에서 실행하거나, `--dir` · `-y` 같은 옵션으로 값을 주세요.
143
149
 
144
150
  ## 문서
@@ -159,6 +159,9 @@ function dependencyInstallGuide(baseDirInput, name, range) {
159
159
  ...base
160
160
  };
161
161
  }
162
+ function installCommandPhrase(installCommand, rootDeclared) {
163
+ return rootDeclared && packageManagerOf(installCommand) === "npm" ? `\uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uB8E8\uD2B8\uC5D0\uC11C ${installCommand}` : installCommand;
164
+ }
162
165
  function isPlainObject(value) {
163
166
  return typeof value === "object" && value !== null && !Array.isArray(value);
164
167
  }
@@ -369,20 +372,20 @@ function splitPackageSpec(spec) {
369
372
  if (parts.length < n || parts.slice(0, n).some((p) => p === "" || p === "." || p === "..")) return void 0;
370
373
  return { name: parts.slice(0, n).join("/"), rest: parts.slice(n).join("/") };
371
374
  }
372
- function resolveExportTarget(value) {
375
+ function resolveExportTarget(value, conditions = CSS_EXPORT_CONDITIONS) {
373
376
  if (typeof value === "string") return value;
374
377
  if (Array.isArray(value)) {
375
378
  for (const v of value) {
376
- const r = resolveExportTarget(v);
379
+ const r = resolveExportTarget(v, conditions);
377
380
  if (r !== void 0) return r;
378
381
  }
379
382
  return void 0;
380
383
  }
381
384
  if (isPlainObject(value)) {
382
385
  for (const [key, v] of Object.entries(value)) {
383
- if (!CSS_EXPORT_CONDITIONS.has(key)) continue;
386
+ if (!conditions.has(key)) continue;
384
387
  if (v === null) return void 0;
385
- const r = resolveExportTarget(v);
388
+ const r = resolveExportTarget(v, conditions);
386
389
  if (r !== void 0) return r;
387
390
  }
388
391
  }
@@ -391,10 +394,10 @@ function resolveExportTarget(value) {
391
394
  function cssFileCandidates(p) {
392
395
  return [p, `${p}.css`, path.join(p, "index.css")];
393
396
  }
394
- function exportsTarget(exportsField, subpath) {
397
+ function exportsTarget(exportsField, subpath, conditions = CSS_EXPORT_CONDITIONS) {
395
398
  const map = isPlainObject(exportsField) && Object.keys(exportsField).some((k) => k.startsWith(".")) ? exportsField : { ".": exportsField };
396
399
  if (Object.prototype.hasOwnProperty.call(map, subpath)) {
397
- const t = resolveExportTarget(map[subpath]);
400
+ const t = resolveExportTarget(map[subpath], conditions);
398
401
  if (t === void 0) return void 0;
399
402
  return t.includes("*") || !t.startsWith("./") ? "?" : t;
400
403
  }
@@ -402,6 +405,9 @@ function exportsTarget(exportsField, subpath) {
402
405
  return void 0;
403
406
  }
404
407
  function resolveCssPackageImport(fromDir, spec) {
408
+ return resolvePackageSubpath(fromDir, spec, CSS_EXPORT_CONDITIONS, cssFileCandidates);
409
+ }
410
+ function resolvePackageSubpath(fromDir, spec, conditions, candidates) {
405
411
  const parsed = splitPackageSpec(spec);
406
412
  if (parsed === void 0 || parsed.rest === "") return { kind: "unknown" };
407
413
  const subpath = `./${parsed.rest}`;
@@ -418,16 +424,16 @@ function resolveCssPackageImport(fromDir, spec) {
418
424
  }
419
425
  if (manifest !== void 0 && manifest.exports) {
420
426
  const version = exactVersionOf(manifest.version);
421
- const target = exportsTarget(manifest.exports, subpath);
427
+ const target = exportsTarget(manifest.exports, subpath, conditions);
422
428
  if (target === "?") return { kind: "unknown" };
423
429
  if (target === void 0) {
424
430
  return version !== void 0 ? { kind: "not-exported", pkgDir, subpath, version } : { kind: "not-exported", pkgDir, subpath };
425
431
  }
426
- const file = cssFileCandidates(path.join(pkgDir, target)).find(isFile);
432
+ const file = candidates(path.join(pkgDir, target)).find(isFile);
427
433
  if (file !== void 0) return { kind: "resolved", pkgDir, file };
428
434
  return version !== void 0 ? { kind: "target-missing", pkgDir, subpath, target, version } : { kind: "target-missing", pkgDir, subpath, target };
429
435
  }
430
- const bare = cssFileCandidates(path.join(pkgDir, parsed.rest)).find(isFile);
436
+ const bare = candidates(path.join(pkgDir, parsed.rest)).find(isFile);
431
437
  if (bare !== void 0) return { kind: "resolved", pkgDir, file: bare };
432
438
  }
433
439
  const parent = path.dirname(dir);
@@ -478,6 +484,25 @@ function cssPackageLineResolution(baseDir, lineDir, spec, otherDirs = []) {
478
484
  }
479
485
  return { kind: "ok" };
480
486
  }
487
+ var JS_REQUIRE_CONDITIONS = /* @__PURE__ */ new Set(["require", "node", "module-sync", "default"]);
488
+ var JS_IMPORT_CONDITIONS = /* @__PURE__ */ new Set(["import", "node", "module-sync", "default"]);
489
+ function jsFileCandidates(p) {
490
+ return [p, `${p}.js`, `${p}.json`, `${p}.node`, path.join(p, "index.js"), path.join(p, "index.json"), path.join(p, "index.node")];
491
+ }
492
+ function tailwindConfigImportResolution(baseDir, spec, refs) {
493
+ if (isPnpProject(baseDir)) return { kind: "ok" };
494
+ const blocked = (conditions) => {
495
+ const r = resolvePackageSubpath(baseDir, spec, conditions, jsFileCandidates);
496
+ return r.kind === "not-exported" ? r : void 0;
497
+ };
498
+ const viaRequire = refs.require || refs.import ? blocked(JS_REQUIRE_CONDITIONS) : void 0;
499
+ if (refs.require && viaRequire !== void 0) return viaRequire;
500
+ if (refs.import && viaRequire !== void 0) {
501
+ const viaImport = blocked(JS_IMPORT_CONDITIONS);
502
+ if (viaImport !== void 0) return viaImport;
503
+ }
504
+ return { kind: "ok" };
505
+ }
481
506
  function deferredComponentImportReason(d, installCommand) {
482
507
  const line = `@import "${d.name}/tailwind.css";`;
483
508
  const current = d.installedVersion !== void 0 && d.installedVersion !== "?" && (compareExactVersions(d.installedVersion, COMPONENT_TAILWIND_CSS_MIN_VERSION) ?? -1) >= 0;
@@ -507,6 +532,17 @@ function findPnpUnpluggedPackages(baseDirInput, name, range) {
507
532
  }
508
533
  return found;
509
534
  }
535
+ var PNP_REAL_DIR_RANGE = /^(?:workspace|portal|link):/;
536
+ function pnpComponentSourceHidden(baseDirInput, name, range) {
537
+ if (!isPnpProject(baseDirInput)) return false;
538
+ const r = range.trim();
539
+ if (PNP_REAL_DIR_RANGE.test(r)) return false;
540
+ const probe = versionSatisfiesRange("0.0.0", r) === void 0 ? "*" : r;
541
+ return findPnpUnpluggedPackages(baseDirInput, name, probe).length === 0;
542
+ }
543
+ function pnpUnplugSetupPhrase(name) {
544
+ return `Plug'n'Play \uB8E8\uD2B8(.pnp.cjs \uAC00 \uC788\uB294 \uACF3) package.json \uC758 dependenciesMeta \uC5D0 "${name}": { "unplugged": true } \uB97C \uB450\uACE0 yarn install`;
545
+ }
510
546
  function parsePartialVersion(token) {
511
547
  const m = /^v?(\d+|[xX*])(?:\.(\d+|[xX*]))?(?:\.(\d+|[xX*]))?(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/.exec(token.trim());
512
548
  if (!m) return void 0;
@@ -806,6 +842,7 @@ export {
806
842
  PNP_ROOT_ONLY_NOTE,
807
843
  rootDeclarationsAllowed,
808
844
  dependencyInstallGuide,
845
+ installCommandPhrase,
809
846
  isPlainObject,
810
847
  addCommandPrefix,
811
848
  addCommandFor,
@@ -827,8 +864,11 @@ export {
827
864
  tokensCssResolution,
828
865
  outsideCssPackageResolution,
829
866
  cssPackageLineResolution,
867
+ tailwindConfigImportResolution,
830
868
  deferredComponentImportReason,
831
869
  findPnpUnpluggedPackages,
870
+ pnpComponentSourceHidden,
871
+ pnpUnplugSetupPhrase,
832
872
  compareExactVersions,
833
873
  MONET_CATEGORIES,
834
874
  MonetClient,