@axis-ds/cli 1.7.5 → 1.7.6

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
@@ -89,6 +89,8 @@ axis theme add ontology
89
89
  - 브랜드 CSS 는 `[data-brand="<brand>"]` 선택자로 적용되므로 루트 레이아웃의 `<html data-brand>` 나 `ThemeProvider` 의 `setBrand` 가 있어야 화면이 바뀝니다. 코드는 고치지 않고, 레이아웃에서 찾지 못하면 두 방법의 예시를 냅니다(`defaultBrand` 는 `@axis-ds/theme` 1.6.2 이하에서 `setBrand(undefined)` 로 끈 상태가 새로고침 뒤 유지되지 않아 예시에 쓰지 않습니다). 마크업 `data-brand` 와 `ThemeProvider` 를 함께 쓰는 레이아웃이면 theme 1.7.0 이상이 필요하다고 한 줄 더 알립니다(1.6.1 부터). Tailwind 3 이면 preset · content 가 빠졌을 때 넣을 줄도 안내합니다(설정 파일은 고치지 않음). preset 안내는 1.6.1 부터 CommonJS 에서 모든 tokens 버전에 되는 `require("@axis-ds/tokens/tailwind").default` 입니다(1.6.0 의 `.default` 없는 형태는 tokens 1.6.2 이하에서 preset 이 빠짐).
90
90
  - 넣은 import 줄의 출력은 1.6.1 부터 실제 위치 · 분류를 따릅니다. 컴포넌트 `tailwind.css` 는 「컴포넌트 스캔 경로, 위치 무관」, 기본 토큰 CSS 는 브랜드 줄보다 앞에 들어갔을 때만 「브랜드 앞」이고 뒤에 들어가면 옮기라고 경고합니다.
91
91
  - `@axis-ds/tokens` 가 없거나 1.3.0 미만이면 목록 대신 설치 · 업그레이드 안내를 내고 종료 코드 1 로 끝납니다.
92
+ - 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 이어도 앱 디렉터리 명령 그대로입니다.
92
94
  - `axis check` 는 `axis.config.json` 의 `brand` 와 CSS 의 브랜드 import 가 맞는지도 봅니다.
93
95
 
94
96
  ## 프로젝트 검증 (`axis check`)
@@ -106,10 +108,12 @@ axis theme add ontology
106
108
  - Tailwind 3 CommonJS(1.6.1 부터): 설정이 `.cjs` 이거나 `module.exports` 를 쓰고 `.default` 없는 `require("@axis-ds/tokens/tailwind")` 가 있으면, 설치본(없으면 선언 하한) `@axis-ds/tokens` 가 1.7.0 미만일 때 WARN 입니다. 1.6.2 이하의 이 형태는 preset 이 아니라 `{ default }` 를 받아 색 · keyframes 가 빠집니다(1.1.0 부터). `.ts` · `.mjs` 의 `export default` 안 `require` 와 `import` 형태는 Tailwind 가 `.default` 를 꺼내 줘서 PASS 입니다.
107
109
  - globals.css 항목: 같은 후보에서 처음 찾은 CSS 하나를 봅니다. 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"`. 자체 `--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 기본 정의로 냅니다).
108
110
  - 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 까지는 선언만 보고 「모두 설치되어 있습니다」였습니다.
111
+ - 1.7.6 부터 워크스페이스 루트 `package.json` 에 선언한 `@axis-ds/*`(앱에 없는 것)도 설치 확인 대상이고, 설치되지 않았으면 「워크스페이스 루트에 선언돼 있지만 설치되지 않았습니다」 WARN 입니다(종료 코드는 그대로, 1.7.5 까지는 앱 선언만 봐서 PASS).
112
+ - 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` 설정은 읽지 않습니다.
109
113
  - 해당할 때만 더하는 항목(1.6.0 부터, brand 항목 뒤 이 순서):
110
- - `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 이하는 마운트 때 속성을 지움).
114
+ - `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` 판정도 같음).
111
115
  - `tailwind.content`: Tailwind 3 설정 파일이 있고 `componentsDir` 나 선언된 `@axis-ds/ui-react` · `@axis-ds/agentic-ui` 가 있을 때, `content` 의 문자열 glob 이 그 경로를 덮지 않으면 FAIL 입니다(그 경로의 클래스가 생성되지 않음). `content` 를 정적으로 다 읽지 못하면(변수 · 펼침) WARN 입니다. 패키지 경로는 프로젝트 디렉터리부터 상위로 찾은 설치본 위치 기준이라, npm workspaces · pnpm hoisted 처럼 루트에만 설치된 앱은 `../../node_modules/@axis-ds/ui-react/dist/**/*.{js,mjs}` 를 안내합니다(1.7.1 부터, 설치본이 없거나 Plug'n'Play 면 `./node_modules/...`). `**` 는 `../` 를 넘지 않는 것으로, 절대경로 glob 은 실제 위치와 비교해 판정합니다. 1.7.4 부터 pnpm 기본 레이아웃처럼 앱 설치본이 링크이면 실경로가 같은 상위 설치본(`../../node_modules/...`)과 `.pnpm` 스토어 실경로를 상대 경로로 쓴 glob 도 인정하고, 실경로가 다른 상위 설치본을 가리키면 FAIL 문구에 그 이유를 붙입니다. 상위 경로는 Tailwind 3 가 빌드를 실행한 디렉터리 기준으로 풀리므로 모노레포 루트에서 빌드하면 `content: { relative: true, files: [...] }` 를 쓰세요(판정은 프로젝트 디렉터리에서 빌드한다고 보고 함).
112
- - `animation`: `@axis-ds/ui-react` 선언이나 `componentsDir` 의 `animate-in` 류 클래스가 있을 때 애니메이션 플러그인(Tailwind 3 `tailwindcss-animate` 선언 + 설치본 + `plugins` 배열 참조, Tailwind 4 `@import "tw-animate-css"`)이 없으면 WARN 입니다. 1.6.1 부터 Tailwind 3 은 `plugins` 배열 안의 `require("tailwindcss-animate")` 나 그 패키지를 받은 식별자(`import animate from` · `const animate = require(...)`)만 인정합니다(import 만 있거나 다른 곳의 같은 문자열은 아님). 배열을 정적으로 다 읽지 못하면(펼침 · 단축 속성) 「확인하지 못함」 WARN 입니다.
116
+ - `animation`: `@axis-ds/ui-react` 선언이나 `componentsDir` 의 `animate-in` 류 클래스가 있을 때 애니메이션 플러그인(Tailwind 3 `tailwindcss-animate` 선언 + 설치본 + `plugins` 배열 참조, Tailwind 4 `@import "tw-animate-css"`)이 없으면 WARN 입니다. 1.6.1 부터 Tailwind 3 은 `plugins` 배열 안의 `require("tailwindcss-animate")` 나 그 패키지를 받은 식별자(`import animate from` · `const animate = require(...)`)만 인정합니다(import 만 있거나 다른 곳의 같은 문자열은 아님). 배열을 정적으로 다 읽지 못하면(펼침 · 단축 속성) 「확인하지 못함」 WARN 입니다. 1.7.6 부터 Tailwind 4 는 CSS 의 줄마다 그 줄의 패키지(`tw-animate-css` · `tailwindcss-animate`)가 선언 · 설치돼 있어야 PASS 이고, 줄은 있는데 선언이나 설치본이 없으면 「애니메이션 플러그인을 쓸 수 없습니다」 WARN 입니다(1.7.5 까지는 줄만 보고 PASS, 실제 빌드는 실패). Plug'n'Play 에서는 플러그인 선언을 앱 `package.json` 에서만 봅니다.
113
117
  - FAIL 이 하나라도 있으면 종료 코드 1 로 끝납니다. WARN 만 있으면 0 입니다(1.3.0 부터, 이전에는 결과와 관계없이 0).
114
118
  - MCP `axis.check_project` 도 같은 항목 · 문구를 냅니다.
115
119
 
@@ -109,14 +109,56 @@ function workspaceRootPackage(baseDirInput) {
109
109
  return void 0;
110
110
  }
111
111
  }
112
- function declaredDependency(baseDir, pkg, name, rootPkg) {
112
+ function declaredDependency(baseDir, pkg, name, rootPkg, options = {}) {
113
113
  if (pkg === void 0) return void 0;
114
114
  const own = hasDependency(pkg, name);
115
115
  if (own !== void 0) return { range: own, source: "app" };
116
+ if (options.appOnlyInPnp && isPnpProject(baseDir)) return void 0;
116
117
  const root = rootPkg === void 0 ? workspaceRootPackage(baseDir) : rootPkg ?? void 0;
117
118
  const fromRoot = root !== void 0 ? hasDependency(root, name) : void 0;
118
119
  return fromRoot !== void 0 ? { range: fromRoot, source: "root" } : void 0;
119
120
  }
121
+ function pnpRootOnlyDependency(baseDir, pkg, name, rootPkg) {
122
+ if (pkg === void 0 || hasDependency(pkg, name) !== void 0 || !isPnpProject(baseDir)) return void 0;
123
+ const found = declaredDependency(baseDir, pkg, name, rootPkg);
124
+ return found?.source === "root" ? found : void 0;
125
+ }
126
+ var PNP_ROOT_ONLY_NOTE = "\uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uB8E8\uD2B8\uC5D0\uB9CC \uC120\uC5B8\uB3FC Plug'n'Play \uC5D0\uC11C \uC571\uC774 \uD574\uC11D\uD558\uC9C0 \uBABB\uD569\uB2C8\uB2E4";
127
+ var APP_LOCKFILES = ["package-lock.json", "pnpm-lock.yaml", "yarn.lock", "bun.lockb", "bun.lock"];
128
+ function hasAppLockfile(baseDirInput) {
129
+ const baseDir = path.resolve(baseDirInput);
130
+ return APP_LOCKFILES.some((f) => existsSync(path.join(baseDir, f)));
131
+ }
132
+ function rootDeclarationsAllowed(baseDir, pkg) {
133
+ return pkg !== void 0 && !isPnpProject(baseDir) && !hasAppLockfile(baseDir);
134
+ }
135
+ function readPackageJsonAt(dir) {
136
+ try {
137
+ const parsed = JSON.parse(readFileSync(path.join(dir, "package.json"), "utf8"));
138
+ return isPlainObject(parsed) ? parsed : void 0;
139
+ } catch {
140
+ return void 0;
141
+ }
142
+ }
143
+ function dependencyInstallGuide(baseDirInput, name, range) {
144
+ const baseDir = resolveBaseDir(baseDirInput);
145
+ const installCommand = detectInstallCommand(baseDir);
146
+ const base = { installCommand, addCommand: addCommandFor(installCommand, { [name]: range }) };
147
+ const pkg = readPackageJsonAt(baseDir);
148
+ if (pkg === void 0) return { kind: "add", ...base };
149
+ const own = hasDependency(pkg, name);
150
+ if (isPnpProject(baseDir)) return own !== void 0 ? { kind: "pnp", source: "app", range: own, ...base } : { kind: "add", ...base };
151
+ if (own !== void 0) return { kind: "install", source: "app", range: own, ...base };
152
+ if (!rootDeclarationsAllowed(baseDir, pkg)) return { kind: "add", ...base };
153
+ const declared = declaredDependency(baseDir, pkg, name);
154
+ if (declared?.source !== "root") return { kind: "add", ...base };
155
+ return {
156
+ kind: packageManagerOf(installCommand) === "npm" ? "install-at-root" : "install",
157
+ source: "root",
158
+ range: declared.range,
159
+ ...base
160
+ };
161
+ }
120
162
  function isPlainObject(value) {
121
163
  return typeof value === "object" && value !== null && !Array.isArray(value);
122
164
  }
@@ -247,6 +289,7 @@ function isPnpProject(baseDirInput) {
247
289
  let dir = resolveBaseDir(baseDirInput);
248
290
  for (; ; ) {
249
291
  if (isFile(path.join(dir, ".pnp.cjs")) || isFile(path.join(dir, ".pnp.js"))) return true;
292
+ if (existsSync(path.join(dir, ".git"))) return false;
250
293
  const parent = path.dirname(dir);
251
294
  if (parent === dir) return false;
252
295
  dir = parent;
@@ -453,6 +496,10 @@ export {
453
496
  hasDependency,
454
497
  workspaceRootPackage,
455
498
  declaredDependency,
499
+ pnpRootOnlyDependency,
500
+ PNP_ROOT_ONLY_NOTE,
501
+ rootDeclarationsAllowed,
502
+ dependencyInstallGuide,
456
503
  isPlainObject,
457
504
  addCommandPrefix,
458
505
  addCommandFor,
package/dist/index.js CHANGED
@@ -2,23 +2,27 @@
2
2
  import {
3
3
  GLOBAL_CSS_CANDIDATES,
4
4
  MonetClient,
5
+ PNP_ROOT_ONLY_NOTE,
5
6
  ROOT_LAYOUT_FILES,
6
7
  addCommandFor,
7
8
  addCommandPrefix,
8
9
  compareExactVersions,
9
10
  declaredDependency,
11
+ dependencyInstallGuide,
10
12
  detectInstallCommand,
11
13
  detectProjectPaths,
12
14
  findInstalledPackage,
13
15
  hasDependency,
14
16
  isPlainObject,
15
17
  isPnpProject,
18
+ pnpRootOnlyDependency,
16
19
  projectFileExists,
17
20
  resolveBaseDir,
21
+ rootDeclarationsAllowed,
18
22
  runScriptCommand,
19
23
  workspaceRootPackage,
20
24
  workspaceRunCommand
21
- } from "./chunk-YYSEFWYD.js";
25
+ } from "./chunk-I3HWV7Y5.js";
22
26
  import {
23
27
  V0Client
24
28
  } from "./chunk-2PNCUPCG.js";
@@ -1929,6 +1933,9 @@ import { basename, dirname, extname, isAbsolute, join, relative, resolve, sep }
1929
1933
  function declaredRange(baseDir, pkg, name) {
1930
1934
  return declaredDependency(baseDir, pkg, name)?.range;
1931
1935
  }
1936
+ function declaredRangeForCheck(baseDir, pkg, name) {
1937
+ return declaredDependency(baseDir, pkg, name, void 0, { appOnlyInPnp: true })?.range;
1938
+ }
1932
1939
  function isPlainObject2(value) {
1933
1940
  return typeof value === "object" && value !== null && !Array.isArray(value);
1934
1941
  }
@@ -2306,7 +2313,7 @@ function hasBareCjsPresetRequire(code) {
2306
2313
  function isCommonJsConfig(file, source) {
2307
2314
  return extname(file) === ".cjs" || /\bmodule\.exports\b/.test(source);
2308
2315
  }
2309
- function packageVersionGate(baseDirInput, pkg, name, min) {
2316
+ function packageVersionGate(baseDirInput, pkg, name, min, options = {}) {
2310
2317
  const baseDir = resolveBaseDir(baseDirInput);
2311
2318
  if (!isPnpProject(baseDir)) {
2312
2319
  const installed = findInstalledPackage(baseDir, name)?.version;
@@ -2315,7 +2322,11 @@ function packageVersionGate(baseDirInput, pkg, name, min) {
2315
2322
  if (cmp !== void 0) return { status: cmp >= 0 ? "ok" : "below", source: "installed", value: installed };
2316
2323
  }
2317
2324
  }
2318
- const declared = pkg ? declaredRange(baseDir, pkg, name) : void 0;
2325
+ const declared = pkg ? declaredDependency(baseDir, pkg, name, void 0, options)?.range : void 0;
2326
+ if (declared === void 0 && options.appOnlyInPnp) {
2327
+ const rootOnly = pnpRootOnlyDependency(baseDir, pkg, name);
2328
+ if (rootOnly !== void 0) return { status: "unresolved", source: "declared", value: rootOnly.range };
2329
+ }
2319
2330
  if (declared !== void 0) {
2320
2331
  const atLeast = rangeLowerAtLeast(declared, min);
2321
2332
  if (atLeast !== void 0) return { status: atLeast ? "ok" : "below", source: "declared", value: declared };
@@ -2324,6 +2335,7 @@ function packageVersionGate(baseDirInput, pkg, name, min) {
2324
2335
  return { status: "unknown", source: "none" };
2325
2336
  }
2326
2337
  function versionGateLabel(gate) {
2338
+ if (gate.status === "unresolved") return `\uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uB8E8\uD2B8 \uC120\uC5B8 ${gate.value}`;
2327
2339
  if (gate.source === "installed") return `\uC124\uCE58\uBCF8 ${gate.value}`;
2328
2340
  if (gate.source === "declared") return `\uC120\uC5B8 ${gate.value}`;
2329
2341
  return "\uC124\uCE58\uBCF8 \xB7 \uC120\uC5B8 \uC5C6\uC74C";
@@ -2405,7 +2417,14 @@ function checkTailwindSetup(baseDirInput) {
2405
2417
  if (hasTokensPresetReference(content)) {
2406
2418
  const code = stripJsComments(content);
2407
2419
  if (isCommonJsConfig(file, code) && hasBareCjsPresetRequire(code)) {
2408
- const gate = packageVersionGate(baseDir, pkg, "@axis-ds/tokens", TOKENS_CJS_PRESET_FIXED_VERSION);
2420
+ const gate = packageVersionGate(baseDir, pkg, "@axis-ds/tokens", TOKENS_CJS_PRESET_FIXED_VERSION, { appOnlyInPnp: true });
2421
+ if (gate.status === "unresolved") {
2422
+ return {
2423
+ name: "tailwind.config",
2424
+ severity: "warn",
2425
+ message: `${file}\uC5D0 AXIS preset \uCC38\uC870\uAC00 \uC788\uC9C0\uB9CC @axis-ds/tokens \uAC00 ${PNP_ROOT_ONLY_NOTE}(${versionGateLabel(gate)}) \u2192 \uC571 package.json \uC5D0 @axis-ds/tokens ${TOKENS_CJS_PRESET_FIXED_VERSION} \uC774\uC0C1\uC744 \uC120\uC5B8\uD558\uC138\uC694`
2426
+ };
2427
+ }
2409
2428
  if (gate.status !== "ok") {
2410
2429
  const why = gate.status === "below" ? `@axis-ds/tokens ${versionGateLabel(gate)} \uC5D0\uC11C\uB294 CommonJS \uC758 require("${TOKENS_TAILWIND3_PRESET}") \uAC00 preset \uC774 \uC544\uB2C8\uB77C { default } \uB97C \uB3CC\uB824\uC918 \uC0C9 \xB7 keyframes \uAC00 \uC801\uC6A9\uB418\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4` : `@axis-ds/tokens \uBC84\uC804\uC744 \uD655\uC778\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4(${versionGateLabel(gate)}). ${TOKENS_CJS_PRESET_FIXED_VERSION} \uBBF8\uB9CC\uC774\uBA74 CommonJS \uC758 require("${TOKENS_TAILWIND3_PRESET}") \uB85C\uB294 preset \uC774 \uC801\uC6A9\uB418\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4`;
2411
2430
  return {
@@ -2751,30 +2770,56 @@ function checkAnimationPlugin(baseDirInput) {
2751
2770
  if (!declared && !copied) return null;
2752
2771
  const by = declared ? "@axis-ds/ui-react \uC120\uC5B8" : "componentsDir \uC758 animate-in \uB958 \uD074\uB798\uC2A4";
2753
2772
  const tailwind = detectTailwind(baseDir, pkg);
2773
+ const pnp = isPnpProject(baseDir);
2774
+ const pluginProblem = (name) => {
2775
+ if (declaredRangeForCheck(baseDir, pkg, name) === void 0) {
2776
+ return pnpRootOnlyDependency(baseDir, pkg, name) !== void 0 ? `${name} \uAC00 ${PNP_ROOT_ONLY_NOTE}` : `${name} \uC120\uC5B8 \uC5C6\uC74C`;
2777
+ }
2778
+ if (!pnp && findInstalledPackage(baseDir, name) === void 0) return `${name} \uBBF8\uC124\uCE58(\uC120\uC5B8\uB9CC \uC788\uC74C)`;
2779
+ return void 0;
2780
+ };
2754
2781
  if (tailwind.major !== void 0 && tailwind.major >= 4) {
2755
2782
  const file = TAILWIND_CSS_CANDIDATES.find((c) => existsSync(join(baseDir, c)));
2756
2783
  const css = file !== void 0 ? stripCssComments(readFileSync(join(baseDir, file), "utf8")) : "";
2757
- const ok = new RegExp(`@import\\s+(?:url\\(\\s*)?["']${ANIMATION_PLUGIN_TAILWIND4}["']`).test(css) || new RegExp(`@plugin\\s+["']${ANIMATION_PLUGIN_TAILWIND3}["']`).test(css);
2758
- return ok ? { name: "animation", severity: "pass", message: `${file}\uC5D0 \uC560\uB2C8\uBA54\uC774\uC158 \uD50C\uB7EC\uADF8\uC778\uC774 \uC788\uC2B5\uB2C8\uB2E4` } : {
2784
+ const lines = [];
2785
+ if (new RegExp(`@import\\s+(?:url\\(\\s*)?["']${ANIMATION_PLUGIN_TAILWIND4}["']`).test(css)) lines.push(ANIMATION_PLUGIN_TAILWIND4);
2786
+ if (new RegExp(`@plugin\\s+["']${ANIMATION_PLUGIN_TAILWIND3}["']`).test(css)) lines.push(ANIMATION_PLUGIN_TAILWIND3);
2787
+ if (lines.length === 0) {
2788
+ return {
2789
+ name: "animation",
2790
+ severity: "warn",
2791
+ message: `\uC560\uB2C8\uBA54\uC774\uC158 \uD50C\uB7EC\uADF8\uC778\uC774 \uC5C6\uC2B5\uB2C8\uB2E4(${by}): Dialog \xB7 Select \uB4F1\uC758 \uC5F4\uACE0 \uB2EB\uB294 \uC560\uB2C8\uBA54\uC774\uC158\uC774 \uB3D9\uC791\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4 \u2192 ${ANIMATION_PLUGIN_TAILWIND4} \uC124\uCE58 \uB4A4 @import "${ANIMATION_PLUGIN_TAILWIND4}";`
2792
+ };
2793
+ }
2794
+ const problems = lines.map((name) => ({ name, why: pluginProblem(name) })).filter((x) => x.why !== void 0);
2795
+ if (problems.length === 0) return { name: "animation", severity: "pass", message: `${file}\uC5D0 \uC560\uB2C8\uBA54\uC774\uC158 \uD50C\uB7EC\uADF8\uC778\uC774 \uC788\uC2B5\uB2C8\uB2E4` };
2796
+ return {
2759
2797
  name: "animation",
2760
2798
  severity: "warn",
2761
- message: `\uC560\uB2C8\uBA54\uC774\uC158 \uD50C\uB7EC\uADF8\uC778\uC774 \uC5C6\uC2B5\uB2C8\uB2E4(${by}): Dialog \xB7 Select \uB4F1\uC758 \uC5F4\uACE0 \uB2EB\uB294 \uC560\uB2C8\uBA54\uC774\uC158\uC774 \uB3D9\uC791\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4 \u2192 ${ANIMATION_PLUGIN_TAILWIND4} \uC124\uCE58 \uB4A4 @import "${ANIMATION_PLUGIN_TAILWIND4}";`
2799
+ message: `${file}\uC758 \uC560\uB2C8\uBA54\uC774\uC158 \uD50C\uB7EC\uADF8\uC778\uC744 \uC4F8 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4(${by}, ${problems.map((x) => x.why).join(" \xB7 ")}): Dialog \xB7 Select \uB4F1\uC758 \uC5F4\uACE0 \uB2EB\uB294 \uC560\uB2C8\uBA54\uC774\uC158\uC774 \uB3D9\uC791\uD558\uC9C0 \uC54A\uACE0 \uBE4C\uB4DC\uAC00 \uC2E4\uD328\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4 \u2192 ${problems.map((x) => x.name).join(" \xB7 ")} \uB97C package.json \uC5D0 \uC120\uC5B8 \xB7 \uC124\uCE58\uD558\uC138\uC694`
2762
2800
  };
2763
2801
  }
2764
2802
  const configFile = TAILWIND_CONFIG_FILES.find((f) => existsSync(join(baseDir, f)));
2765
2803
  const source = configFile !== void 0 ? stripJsComments(readFileSync(join(baseDir, configFile), "utf8")) : "";
2766
2804
  const plugins = configFile !== void 0 ? readAnimationPluginUse(source) : "absent";
2767
- const pluginDeclared = declaredRange(baseDir, pkg, ANIMATION_PLUGIN_TAILWIND3) !== void 0;
2768
- const pluginInstalled = pluginDeclared && (isPnpProject(baseDir) || findInstalledPackage(baseDir, ANIMATION_PLUGIN_TAILWIND3) !== void 0);
2769
- if (plugins === "found" && pluginDeclared && pluginInstalled) {
2805
+ const pluginReason = pluginProblem(ANIMATION_PLUGIN_TAILWIND3);
2806
+ if (plugins === "found" && pluginReason === void 0) {
2770
2807
  return { name: "animation", severity: "pass", message: `${configFile}\uC758 plugins \uC5D0 ${ANIMATION_PLUGIN_TAILWIND3} \uAC00 \uC788\uC2B5\uB2C8\uB2E4` };
2771
2808
  }
2772
2809
  const cfg = configFile ?? "tailwind.config";
2810
+ const configReason = plugins === "dynamic" ? `${cfg} plugins \uB97C \uC815\uC801\uC73C\uB85C \uB2E4 \uC77D\uC9C0 \uBABB\uD574 \uD655\uC778\uD558\uC9C0 \uBABB\uD568` : plugins !== "found" ? `${cfg} plugins \uC5D0 \uC5C6\uC74C` : void 0;
2811
+ if (pluginReason !== void 0 && pnpRootOnlyDependency(baseDir, pkg, ANIMATION_PLUGIN_TAILWIND3) !== void 0) {
2812
+ const extra = configReason !== void 0 ? `, ${configReason}` : "";
2813
+ const plug = configReason !== void 0 ? ` \xB7 plugins \uC5D0 require("${ANIMATION_PLUGIN_TAILWIND3}")` : "";
2814
+ return {
2815
+ name: "animation",
2816
+ severity: "warn",
2817
+ message: `\uC560\uB2C8\uBA54\uC774\uC158 \uD50C\uB7EC\uADF8\uC778 ${ANIMATION_PLUGIN_TAILWIND3} \uAC00 ${PNP_ROOT_ONLY_NOTE}(${by}${extra}): Dialog \xB7 Select \uB4F1\uC758 \uC5F4\uACE0 \uB2EB\uB294 \uC560\uB2C8\uBA54\uC774\uC158\uC774 \uB3D9\uC791\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4 \u2192 \uC571 package.json \uC5D0 ${ANIMATION_PLUGIN_TAILWIND3} \uB97C \uC120\uC5B8\uD558\uC138\uC694${plug}`
2818
+ };
2819
+ }
2773
2820
  const reasons = [];
2774
- if (!pluginDeclared) reasons.push(`${ANIMATION_PLUGIN_TAILWIND3} \uC120\uC5B8 \uC5C6\uC74C`);
2775
- else if (!pluginInstalled) reasons.push(`${ANIMATION_PLUGIN_TAILWIND3} \uBBF8\uC124\uCE58(\uC120\uC5B8\uB9CC \uC788\uC74C)`);
2776
- if (plugins === "dynamic") reasons.push(`${cfg} plugins \uB97C \uC815\uC801\uC73C\uB85C \uB2E4 \uC77D\uC9C0 \uBABB\uD574 \uD655\uC778\uD558\uC9C0 \uBABB\uD568`);
2777
- else if (plugins !== "found") reasons.push(`${cfg} plugins \uC5D0 \uC5C6\uC74C`);
2821
+ if (pluginReason !== void 0) reasons.push(pluginReason);
2822
+ if (configReason !== void 0) reasons.push(configReason);
2778
2823
  return {
2779
2824
  name: "animation",
2780
2825
  severity: "warn",
@@ -3439,7 +3484,11 @@ function inspectBrandActivation(baseDir) {
3439
3484
  if (typeof brand !== "string" || brand.trim() === "") return null;
3440
3485
  const location = findBrandActivation(baseDir);
3441
3486
  if (!location.markupWithProvider) return { brand, ...location };
3442
- return { brand, ...location, theme: packageVersionGate(baseDir, readProjectPackageJson(baseDir), THEME_PACKAGE, THEME_MARKUP_BRAND_MIN_VERSION) };
3487
+ return {
3488
+ brand,
3489
+ ...location,
3490
+ theme: packageVersionGate(baseDir, readProjectPackageJson(baseDir), THEME_PACKAGE, THEME_MARKUP_BRAND_MIN_VERSION, { appOnlyInPnp: true })
3491
+ };
3443
3492
  }
3444
3493
  var THEME_PACKAGE = "@axis-ds/theme";
3445
3494
  function readProjectPackageJson(baseDir) {
@@ -3512,25 +3561,43 @@ function checkDependencies(baseDirInput) {
3512
3561
  return { name: "dependencies", severity: "fail", message: "package.json \uC744 \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4(JSON \uD655\uC778)" };
3513
3562
  }
3514
3563
  const rootPkg = workspaceRootPackage(baseDir) ?? null;
3515
- const declared = (d) => declaredDependency(baseDir, pkg, d, rootPkg);
3564
+ const pnp = isPnpProject(baseDir);
3565
+ const declared = (d) => declaredDependency(baseDir, pkg, d, rootPkg, { appOnlyInPnp: true });
3566
+ const pnpRootOnly = (d) => pnpRootOnlyDependency(baseDir, pkg, d, rootPkg) !== void 0;
3516
3567
  const fromRoot = (d) => declared(d)?.source === "root";
3517
- const missingRequired = REQUIRED_DEPENDENCIES.filter((d) => declared(d) === void 0);
3518
- if (missingRequired.length > 0) {
3519
- return { name: "dependencies", severity: "fail", message: `\uD544\uC218 \uC758\uC874\uC131 \uB204\uB77D: ${missingRequired.join(", ")}` };
3520
- }
3521
- const missingRecommended = RECOMMENDED_DEPENDENCIES.filter((d) => declared(d) === void 0);
3522
- const rootDeclared = [...REQUIRED_DEPENDENCIES, ...RECOMMENDED_DEPENDENCIES].filter((d) => fromRoot(d));
3568
+ const missingRequired = REQUIRED_DEPENDENCIES.filter((d) => declared(d) === void 0 && !pnpRootOnly(d));
3569
+ const pnpRootRequired = REQUIRED_DEPENDENCIES.filter((d) => pnpRootOnly(d));
3570
+ if (missingRequired.length > 0 || pnpRootRequired.length > 0) {
3571
+ const fails = [];
3572
+ if (missingRequired.length > 0) fails.push(`\uD544\uC218 \uC758\uC874\uC131 \uB204\uB77D: ${missingRequired.join(", ")}`);
3573
+ if (pnpRootRequired.length > 0) fails.push(`\uD544\uC218 \uC758\uC874\uC131 ${pnpRootRequired.join(", ")} \uAC00 ${PNP_ROOT_ONLY_NOTE} \u2192 \uC571 package.json \uC5D0 \uC120\uC5B8\uD558\uC138\uC694`);
3574
+ return { name: "dependencies", severity: "fail", message: fails.join(" / ") };
3575
+ }
3576
+ const missingRecommended = RECOMMENDED_DEPENDENCIES.filter((d) => declared(d) === void 0 && !pnpRootOnly(d));
3577
+ const pnpRootRecommended = RECOMMENDED_DEPENDENCIES.filter((d) => pnpRootOnly(d));
3578
+ const appAxis = declaredAxisPackages(pkg);
3579
+ const rootOnlyAxis = rootPkg !== null ? declaredAxisPackages(rootPkg).filter((d) => !appAxis.includes(d)) : [];
3580
+ const rootAxis = pnp ? [] : rootOnlyAxis;
3581
+ const pnpRootAxis = pnp ? rootOnlyAxis : [];
3582
+ const rootDeclared = [...[...REQUIRED_DEPENDENCIES, ...RECOMMENDED_DEPENDENCIES].filter((d) => fromRoot(d)), ...rootAxis];
3523
3583
  const rootNote = rootDeclared.length > 0 ? `\uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uB8E8\uD2B8\uC5D0 \uC120\uC5B8: ${rootDeclared.join(", ")}` : void 0;
3524
3584
  const targets = [
3525
3585
  ...[...REQUIRED_DEPENDENCIES, ...RECOMMENDED_DEPENDENCIES].filter((d) => declared(d) !== void 0),
3526
- ...declaredAxisPackages(pkg)
3586
+ ...appAxis,
3587
+ ...rootAxis
3527
3588
  ];
3528
- const pnp = isPnpProject(baseDir);
3529
3589
  const notInstalled = pnp ? [] : targets.filter((d) => findInstalledPackage(baseDir, d) === void 0);
3590
+ const notInstalledRoot = notInstalled.filter((d) => rootAxis.includes(d));
3591
+ const notInstalledOther = notInstalled.filter((d) => !rootAxis.includes(d));
3530
3592
  const problems = [];
3531
3593
  if (missingRecommended.length > 0) problems.push(`\uAD8C\uC7A5 \uC758\uC874\uC131 \uB204\uB77D: ${missingRecommended.join(", ")}`);
3532
- if (notInstalled.length > 0) {
3533
- problems.push(`\uC120\uC5B8\uB410\uC9C0\uB9CC \uC124\uCE58\uB418\uC9C0 \uC54A\uC740 \uC758\uC874\uC131: ${notInstalled.join(", ")} \u2192 ${detectInstallCommand(baseDir)}`);
3594
+ if (pnpRootRecommended.length > 0) problems.push(`\uAD8C\uC7A5 \uC758\uC874\uC131 ${pnpRootRecommended.join(", ")} \uAC00 ${PNP_ROOT_ONLY_NOTE} \u2192 \uC571 package.json \uC5D0 \uC120\uC5B8\uD558\uC138\uC694`);
3595
+ if (pnpRootAxis.length > 0) problems.push(`${pnpRootAxis.join(", ")} \uAC00 ${PNP_ROOT_ONLY_NOTE} \u2192 \uC571 package.json \uC5D0 \uC120\uC5B8\uD558\uC138\uC694`);
3596
+ if (notInstalledOther.length > 0) {
3597
+ problems.push(`\uC120\uC5B8\uB410\uC9C0\uB9CC \uC124\uCE58\uB418\uC9C0 \uC54A\uC740 \uC758\uC874\uC131: ${notInstalledOther.join(", ")} \u2192 ${detectInstallCommand(baseDir)}`);
3598
+ }
3599
+ if (notInstalledRoot.length > 0) {
3600
+ problems.push(`\uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uB8E8\uD2B8\uC5D0 \uC120\uC5B8\uB3FC \uC788\uC9C0\uB9CC \uC124\uCE58\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4: ${notInstalledRoot.join(", ")} \u2192 ${detectInstallCommand(baseDir)}`);
3534
3601
  }
3535
3602
  if (problems.length > 0) {
3536
3603
  return { name: "dependencies", severity: "warn", message: problems.join(" / ") + (rootNote ? ` (${rootNote})` : "") };
@@ -3669,6 +3736,13 @@ function brandCheckResult(check) {
3669
3736
  }
3670
3737
  }
3671
3738
  function brandActivationResult(check) {
3739
+ if (check.found && check.theme?.status === "unresolved") {
3740
+ return {
3741
+ name: "brand.activation",
3742
+ severity: "warn",
3743
+ message: `${check.found}\uC758 <html data-brand> \uB97C ThemeProvider \uC640 \uD568\uAED8 \uC4F0\uB294\uB370 @axis-ds/theme \uAC00 ${PNP_ROOT_ONLY_NOTE}(${versionGateLabel(check.theme)}) \u2192 \uC571 package.json \uC5D0 @axis-ds/theme ${THEME_MARKUP_BRAND_MIN_VERSION} \uC774\uC0C1\uC744 \uC120\uC5B8\uD558\uAC70\uB098 setBrand("${check.brand}")`
3744
+ };
3745
+ }
3672
3746
  if (check.found && check.theme && check.theme.status !== "ok") {
3673
3747
  const label = versionGateLabel(check.theme);
3674
3748
  const why = check.theme.status === "below" ? `@axis-ds/theme ${label} \uC758 ThemeProvider \uAC00 \uB9C8\uC6B4\uD2B8 \uB54C \uC9C0\uC6C1\uB2C8\uB2E4` : `@axis-ds/theme \uBC84\uC804\uC744 \uD655\uC778\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4(${label}). ${THEME_MARKUP_BRAND_MIN_VERSION} \uBBF8\uB9CC\uC774\uBA74 ThemeProvider \uAC00 \uB9C8\uC6B4\uD2B8 \uB54C \uC9C0\uC6C1\uB2C8\uB2E4`;
@@ -3808,7 +3882,6 @@ var TOKENS_DEPENDENCY_RANGE = `^${TOKENS_DEPENDENCY_MIN_VERSION}`;
3808
3882
  var TAILWIND3_BASE_IMPORTS = [`${TOKENS_PACKAGE}/css`, `${TOKENS_PACKAGE}/css/shadcn`];
3809
3883
  var THEME_MIN_VERSION = "1.3.0";
3810
3884
  var COMPONENT_TAILWIND_CSS_MIN_VERSION = "1.4.0";
3811
- var APP_LOCKFILES = ["package-lock.json", "pnpm-lock.yaml", "yarn.lock", "bun.lockb", "bun.lock"];
3812
3885
  function readText(file) {
3813
3886
  return existsSync3(file) ? readFileSync4(file, "utf8") : null;
3814
3887
  }
@@ -3928,6 +4001,7 @@ function planThemeAdd(baseDirInput, brand) {
3928
4001
  unverifiedBrand: false,
3929
4002
  configChanged: false,
3930
4003
  installCommand: detectInstallCommand(baseDir),
4004
+ tokensGuide: dependencyInstallGuide(baseDir, TOKENS_PACKAGE, TOKENS_DEPENDENCY_RANGE),
3931
4005
  writes: []
3932
4006
  };
3933
4007
  const configFile = path11.join(baseDir, AXIS_CONFIG_FILE);
@@ -3981,8 +4055,7 @@ function planThemeAdd(baseDirInput, brand) {
3981
4055
  return plan;
3982
4056
  }
3983
4057
  }
3984
- const rootDeclarationsAllowed = pkg !== void 0 && !isPnpProject(baseDir) && !APP_LOCKFILES.some((f) => existsSync3(path11.join(baseDir, f)));
3985
- const rootPkg = rootDeclarationsAllowed ? workspaceRootPackage(baseDir) ?? null : null;
4058
+ const rootPkg = rootDeclarationsAllowed(baseDir, pkg) ? workspaceRootPackage(baseDir) ?? null : null;
3986
4059
  const tailwind = detectTailwind(baseDir, pkg);
3987
4060
  const tailwind4 = tailwind.major !== void 0 && tailwind.major >= 4;
3988
4061
  const componentImports = [];
@@ -4186,30 +4259,44 @@ function baseImportLines(after, spec, brandImportPath2, file) {
4186
4259
  chalk9.yellow(` ! \uC774 \uC904\uC774 \uBE0C\uB79C\uB4DC import \uB4A4\uC5D0 \uB4E4\uC5B4\uAC14\uC2B5\uB2C8\uB2E4. \uBE0C\uB79C\uB4DC \uAC12\uC774 \uAE30\uBCF8 \uD1A0\uD070\uC5D0 \uB36E\uC774\uBBC0\uB85C @import "${brandImportPath2}"; \uC55E\uC73C\uB85C \uC62E\uAE30\uC138\uC694`)
4187
4260
  ];
4188
4261
  }
4189
- function tokensInstallCommand(baseDir) {
4190
- return addCommandFor(detectInstallCommand(baseDir), { [TOKENS_PACKAGE]: TOKENS_DEPENDENCY_RANGE });
4191
- }
4192
4262
  var TOKENS_INSTALL_COMMAND = addCommandFor("pnpm install", { [TOKENS_PACKAGE]: TOKENS_DEPENDENCY_RANGE });
4193
- function tokensStatusGuide(status, version, installCommand = TOKENS_INSTALL_COMMAND) {
4263
+ function tokensInstallGuide(baseDir) {
4264
+ return dependencyInstallGuide(baseDir, TOKENS_PACKAGE, TOKENS_DEPENDENCY_RANGE);
4265
+ }
4266
+ function asGuide(guide) {
4267
+ return typeof guide === "string" ? { kind: "add", installCommand: guide, addCommand: guide } : guide;
4268
+ }
4269
+ function tokensPnpMessage(range) {
4270
+ return `${TOKENS_PACKAGE}${range ? ` ${range}` : ""} \uAC00 package.json \uC5D0 \uC120\uC5B8\uB3FC \uC788\uC9C0\uB9CC Plug'n'Play \uC124\uCE58\uB77C \uC124\uCE58\uBCF8\uC744 \uD310\uC815\uD558\uC9C0 \uBABB\uD574 \uBE0C\uB79C\uB4DC\uB97C \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.`;
4271
+ }
4272
+ var ROOT_TOKENS_UPGRADE_GUIDE = `\uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uB8E8\uD2B8 package.json \uC758 ${TOKENS_PACKAGE} \uC120\uC5B8\uC744 ^${MIN_BRAND_TOKENS_VERSION} \uC774\uC0C1\uC73C\uB85C \uC62C\uB9AC\uACE0 \uC124\uCE58\uD558\uC138\uC694.`;
4273
+ function installPhrase(g) {
4274
+ if (g.kind === "install-at-root") return `\uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uB8E8\uD2B8\uC5D0\uC11C ${chalk9.cyan(g.installCommand)}`;
4275
+ return chalk9.cyan(g.kind === "install" ? g.installCommand : g.addCommand);
4276
+ }
4277
+ function rebuildGuide(g) {
4278
+ return `\uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4\uBA74 ${chalk9.cyan(workspaceRunCommand(g.installCommand, TOKENS_PACKAGE, "build"))}, \uC544\uB2C8\uBA74 \uC7AC\uC124\uCE58: ${installPhrase(g)}`;
4279
+ }
4280
+ function tokensStatusGuide(status, version, guide = TOKENS_INSTALL_COMMAND) {
4281
+ const g = asGuide(guide);
4282
+ if (g.kind === "pnp") return [chalk9.yellow(tokensPnpMessage(g.range))];
4283
+ const install = installPhrase(g);
4194
4284
  switch (status) {
4195
4285
  case "not-installed":
4196
- return [
4197
- chalk9.yellow(`${TOKENS_PACKAGE} \uAC00 \uC124\uCE58\uB3FC \uC788\uC9C0 \uC54A\uC544 \uBE0C\uB79C\uB4DC\uB97C \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.`),
4198
- ` \uC124\uCE58: ${chalk9.cyan(installCommand)}`
4199
- ];
4286
+ return [chalk9.yellow(`${TOKENS_PACKAGE} \uAC00 \uC124\uCE58\uB3FC \uC788\uC9C0 \uC54A\uC544 \uBE0C\uB79C\uB4DC\uB97C \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.`), ` \uC124\uCE58: ${install}`];
4200
4287
  case "unsupported":
4201
4288
  return [
4202
4289
  chalk9.yellow(
4203
4290
  `${TOKENS_PACKAGE} ${version ?? "(\uBC84\uC804 \uBAA8\uB984)"} \uC740 \uBE0C\uB79C\uB4DC\uB97C \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4(${MIN_BRAND_TOKENS_VERSION} \uC774\uC0C1 \uD544\uC694).`
4204
4291
  ),
4205
- ` \uC5C5\uADF8\uB808\uC774\uB4DC: ${chalk9.cyan(installCommand)}`
4292
+ g.source === "root" ? ` ${ROOT_TOKENS_UPGRADE_GUIDE}` : ` \uC5C5\uADF8\uB808\uC774\uB4DC: ${chalk9.cyan(g.addCommand)}`
4206
4293
  ];
4207
4294
  case "not-built":
4208
4295
  return [
4209
4296
  chalk9.yellow(
4210
4297
  `${TOKENS_PACKAGE}${version ? ` ${version}` : ""} \uB294 \uC788\uC9C0\uB9CC \uBE4C\uB4DC \uC0B0\uCD9C\uBB3C\uC774 \uC5C6\uC5B4 \uBE0C\uB79C\uB4DC\uB97C \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.`
4211
4298
  ),
4212
- ` \uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4\uBA74 ${chalk9.cyan(workspaceRunCommand(installCommand, TOKENS_PACKAGE, "build"))}, \uC544\uB2C8\uBA74 \uC7AC\uC124\uCE58: ${chalk9.cyan(installCommand)}`
4299
+ ` ${rebuildGuide(g)}`
4213
4300
  ];
4214
4301
  }
4215
4302
  }
@@ -4416,6 +4503,8 @@ function renderThemeAdd(plan, written) {
4416
4503
  );
4417
4504
  }
4418
4505
  const dep = plan.dependency;
4506
+ const tokensGuide = plan.tokensGuide;
4507
+ const pnpTokens = tokensGuide.kind === "pnp" && plan.tokens.status !== "ok";
4419
4508
  if (dep?.action === "add") {
4420
4509
  lines.push(
4421
4510
  ` ${chalk9.green("\u2713")} package.json: dependencies \uC5D0 "${TOKENS_PACKAGE}": "${TOKENS_DEPENDENCY_RANGE}" \uCD94\uAC00`,
@@ -4426,12 +4515,16 @@ function renderThemeAdd(plan, written) {
4426
4515
  ` ${chalk9.gray("-")} package.json: ${TOKENS_PACKAGE} ${dep.declaredRange} \uAC00 \uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uB8E8\uD2B8\uC5D0 \uC120\uC5B8\uB3FC \uC788\uC5B4 \uC571 package.json \uC740 \uBC14\uAFB8\uC9C0 \uC54A\uC74C`
4427
4516
  );
4428
4517
  if (plan.tokens.status === "not-installed") lines.push(` \uC124\uCE58: ${chalk9.cyan(plan.installCommand)}`);
4518
+ else if (plan.tokens.status === "not-built") lines.push(` ${rebuildGuide(tokensGuide)}`);
4429
4519
  } else if (dep?.action === "present") {
4430
4520
  lines.push(` ${chalk9.gray("-")} package.json: ${TOKENS_PACKAGE} ${dep.declaredRange} \uAC00 \uC774\uBBF8 \uC788\uC5B4 \uBC94\uC704\uB97C \uBC14\uAFB8\uC9C0 \uC54A\uC74C`);
4521
+ if (pnpTokens) lines.push(` ${chalk9.yellow(tokensPnpMessage(tokensGuide.range))}`);
4522
+ else if (plan.tokens.status === "not-installed") lines.push(` \uC124\uCE58: ${chalk9.cyan(plan.installCommand)}`);
4523
+ else if (plan.tokens.status === "not-built") lines.push(` ${rebuildGuide(tokensGuide)}`);
4431
4524
  } else if (dep?.action === "no-package-json") {
4432
4525
  lines.push(chalk9.yellow(` ! package.json \uC774 \uC5C6\uC5B4 \uC758\uC874\uC131\uC744 \uCD94\uAC00\uD558\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. \uC124\uCE58: ${dep.tokensAddCommand}`));
4433
4526
  }
4434
- if (dep?.upgrade) {
4527
+ if (dep?.upgrade && !pnpTokens) {
4435
4528
  lines.push(
4436
4529
  chalk9.yellow(
4437
4530
  ` ! \uC124\uCE58\uB41C ${TOKENS_PACKAGE} ${plan.tokens.version} \uC740 \uBE0C\uB79C\uB4DC\uB97C \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4(${MIN_BRAND_TOKENS_VERSION} \uC774\uC0C1 \uD544\uC694).`
@@ -4520,11 +4613,11 @@ function registerThemeCommand(program2) {
4520
4613
  const themeCmd = program2.command("theme").description("\uBE0C\uB79C\uB4DC \uD14C\uB9C8 (@axis-ds/tokens \uBE0C\uB79C\uB4DC)");
4521
4614
  themeCmd.command("list").alias("ls").description("\uC124\uCE58\uB41C @axis-ds/tokens \uC758 \uBE0C\uB79C\uB4DC \uBAA9\uB85D").option("-d, --dir <path>", "\uB300\uC0C1 \uB514\uB809\uD1A0\uB9AC").action((options) => {
4522
4615
  const baseDir = path12.resolve(options.dir || ".");
4523
- print(renderThemeList(listBrands(baseDir), tokensInstallCommand(baseDir)));
4616
+ print(renderThemeList(listBrands(baseDir), tokensInstallGuide(baseDir)));
4524
4617
  });
4525
4618
  themeCmd.command("info <brand>").description("\uBE0C\uB79C\uB4DC \uC0C1\uC138: import \uACBD\uB85C \xB7 Provider \uC608\uC2DC \xB7 \uC8FC\uC694 \uD1A0\uD070 \xB7 \uBCF4\uC815 \uB0B4\uC5ED").option("-d, --dir <path>", "\uB300\uC0C1 \uB514\uB809\uD1A0\uB9AC").action((name, options) => {
4526
4619
  const baseDir = path12.resolve(options.dir || ".");
4527
- print(renderThemeInfo(getBrand(baseDir, name), name, tokensInstallCommand(baseDir)));
4620
+ print(renderThemeInfo(getBrand(baseDir, name), name, tokensInstallGuide(baseDir)));
4528
4621
  });
4529
4622
  themeCmd.command("add <brand>").description("\uBE0C\uB79C\uB4DC \uC801\uC6A9: CSS import \xB7 package.json \uC758\uC874\uC131 \xB7 axis.config.json brand (\uC124\uCE58\uB294 \uC548\uB0B4\uB9CC)").option("-d, --dir <path>", "\uB300\uC0C1 \uB514\uB809\uD1A0\uB9AC").action((name, options) => {
4530
4623
  const baseDir = path12.resolve(options.dir || ".");
package/dist/monet.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  getMonetMcpConfig,
5
5
  getMonetUrl,
6
6
  monetImportNextSteps
7
- } from "./chunk-YYSEFWYD.js";
7
+ } from "./chunk-I3HWV7Y5.js";
8
8
  import "./chunk-HFMMK6R4.js";
9
9
  export {
10
10
  MONET_CATEGORIES,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axis-ds/cli",
3
- "version": "1.7.5",
3
+ "version": "1.7.6",
4
4
  "type": "module",
5
5
  "description": "AXIS Design System - CLI for adding components (shadcn compatible)",
6
6
  "publishConfig": {