@axis-ds/cli 1.7.4 → 1.7.5

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.
Files changed (3) hide show
  1. package/README.md +3 -2
  2. package/dist/index.js +92 -24
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -48,7 +48,7 @@ axis list
48
48
  - `utils.ts` 가 이미 있으면 같은 내용이면 「유지(이미 같은 내용)」(다시 쓰지 않음), 다르면 init 의 utils 로 덮어쓰고 「덮어씀」으로 알립니다(터미널이 아닌 곳에서 `-y` 없이 실행하면 덮어쓰지 않고 rc 1, 아래 「터미널이 아닌 곳에서 실행」). `utils.ts` 쓰기는 `axis add` 와 같은 규칙입니다: 심볼릭 링크면 같은 내용일 때 「유지(이미 같은 내용, 링크)」로 두고, 내용이 다른 링크(프로젝트 안 · 밖) · 깨진 링크 · 디렉터리 · 읽을 수 없는 파일 · 다른 경로와 하드링크로 이어진 파일은 쓰지 않고 그 사실을 알린 뒤 rc 1 입니다. 이 판정은 쓰기 전에 하므로 이때는 `axis.config.json` · `package.json` 도 쓰지 않습니다. 다른 경로와 하드링크로 이어진 `axis.config.json` 을 다시 써야 할 때도 같습니다.
49
49
  - 경로 기본값(`-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
50
  - 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";`).
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 는 루트 선언을 인정하지 않고 앱 선언이 있으면 안내하지 않습니다.
52
52
  - `tailwind-merge` 범위와 아래 안내는 프로젝트의 Tailwind 버전(설치본, 없으면 `package.json` 선언)으로 정합니다. 판정하지 못하면 Tailwind 3 으로 봅니다.
53
53
  - Tailwind 4 이상이면 전역 CSS 에 넣을 줄을 안내합니다. CSS 파일은 고치지 않습니다.
54
54
 
@@ -83,8 +83,9 @@ axis theme info ontology
83
83
  axis theme add ontology
84
84
  ```
85
85
 
86
- - `axis theme add` 는 `axis.config.json` 의 `globalCss` → `app/globals.css` → `src/app/globals.css` → `styles/globals.css` → `src/styles/globals.css` → 루트 `globals.css` 순으로 찾은 파일의 앞쪽 import 구간 끝(`@tailwind` 등 규칙보다 앞)에 줄을 넣습니다. 1.6.0 부터 브랜드 import 앞에 기본 토큰 CSS 도 넣습니다: Tailwind 3 은 `@axis-ds/tokens/css` · `@axis-ds/tokens/css/shadcn`, Tailwind 4 는 `@axis-ds/tokens/css/tailwind4` 와 `package.json` 에 선언된 `@axis-ds/ui-react` · `@axis-ds/agentic-ui` 의 `tailwind.css` 입니다. 이미 있는 줄은 다시 넣지 않으므로 여러 번 실행해도 같습니다. 규칙 뒤에 있는 기존 `@import` 는 CSS 규칙상 무시될 수 있어 맨 앞으로 옮기라고 알립니다(Next.js 15 는 위치와 관계없이 앞으로 끌어올려 적용함을 측정).
86
+ - `axis theme add` 는 `axis.config.json` 의 `globalCss` → `app/globals.css` → `src/app/globals.css` → `styles/globals.css` → `src/styles/globals.css` → 루트 `globals.css` 순으로 찾은 파일의 앞쪽 import 구간 끝(`@tailwind` 등 규칙보다 앞)에 줄을 넣습니다. 1.6.0 부터 브랜드 import 앞에 기본 토큰 CSS 도 넣습니다: Tailwind 3 은 `@axis-ds/tokens/css` · `@axis-ds/tokens/css/shadcn`, Tailwind 4 는 `@axis-ds/tokens/css/tailwind4` 와 `package.json` 에 선언된 `@axis-ds/ui-react` · `@axis-ds/agentic-ui` 의 `tailwind.css` 입니다. 1.7.5 부터 워크스페이스 루트에만 선언한 패키지는 설치본에 `tailwind.css` 가 실제로 있을 때만 넣고, 없으면(미설치 · 1.4.0 미만) 넣지 않은 이유를 한 줄로 알립니다. 이미 있는 줄은 다시 넣지 않으므로 여러 번 실행해도 같습니다. 규칙 뒤에 있는 기존 `@import` 는 CSS 규칙상 무시될 수 있어 맨 앞으로 옮기라고 알립니다(Next.js 15 는 위치와 관계없이 앞으로 끌어올려 적용함을 측정).
87
87
  - `package.json` 에 `@axis-ds/tokens` 가 없으면 `dependencies` 에 `^1.6.0`(1.6.0 부터, 이전에는 `^1.3.0`)을 더하고 설치 명령만 안내합니다. 설치는 실행하지 않습니다. 설치 · 업그레이드 안내 명령은 lockfile 로 고릅니다(`npm install` · `yarn add` · `pnpm add`). lockfile 이 없으면 `package.json` 의 `packageManager`(`npm@…` · `yarn@…` · `pnpm@…`)를 보고, 둘 다 없으면 `pnpm` 입니다(1.7.2 부터 `packageManager` 를 봄).
88
+ - 1.7.5 부터 `@axis-ds/tokens` 가 워크스페이스 루트 `package.json`(`dependencies` · `devDependencies`)에 선언돼 있으면 앱 `package.json` 에 쓰지 않고 「워크스페이스 루트에 선언돼 있어 앱 package.json 은 바꾸지 않음」으로 알립니다. 설치본이 없으면 설치 명령을, 업그레이드 안내 때는 루트 선언을 올리라는 줄을 더합니다. 루트에 `@axis-ds/theme` 가 있으면 ThemeProvider 설치 안내를 내지 않습니다. 앱만 따로 운영 설치 · 배포하면 루트 선언이 따라가지 않으니 앱에 직접 선언합니다. Yarn PnP 와 앱 디렉터리에 자체 lockfile 이 있는 앱은 루트 선언을 보지 않습니다(종전).
88
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 이 빠짐).
89
90
  - 넣은 import 줄의 출력은 1.6.1 부터 실제 위치 · 분류를 따릅니다. 컴포넌트 `tailwind.css` 는 「컴포넌트 스캔 경로, 위치 무관」, 기본 토큰 CSS 는 브랜드 줄보다 앞에 들어갔을 때만 「브랜드 앞」이고 뒤에 들어가면 옮기라고 경고합니다.
90
91
  - `@axis-ds/tokens` 가 없거나 1.3.0 미만이면 목록 대신 설치 · 업그레이드 안내를 내고 종료 코드 1 로 끝납니다.
package/dist/index.js CHANGED
@@ -3802,11 +3802,13 @@ import chalk9 from "chalk";
3802
3802
  import path12 from "path";
3803
3803
 
3804
3804
  // src/theme/theme-add.ts
3805
- import { accessSync, constants, existsSync as existsSync3, readFileSync as readFileSync4, realpathSync as realpathSync2, unlinkSync, writeFileSync } from "fs";
3805
+ import { accessSync, constants, existsSync as existsSync3, readFileSync as readFileSync4, realpathSync as realpathSync2, statSync as statSync2, unlinkSync, writeFileSync } from "fs";
3806
3806
  import path11 from "path";
3807
3807
  var TOKENS_DEPENDENCY_RANGE = `^${TOKENS_DEPENDENCY_MIN_VERSION}`;
3808
3808
  var TAILWIND3_BASE_IMPORTS = [`${TOKENS_PACKAGE}/css`, `${TOKENS_PACKAGE}/css/shadcn`];
3809
3809
  var THEME_MIN_VERSION = "1.3.0";
3810
+ 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"];
3810
3812
  function readText(file) {
3811
3813
  return existsSync3(file) ? readFileSync4(file, "utf8") : null;
3812
3814
  }
@@ -3905,6 +3907,13 @@ function realPathInside(baseDir, file) {
3905
3907
  const inside = relPath !== "" && !relPath.startsWith("..") && !path11.isAbsolute(relPath);
3906
3908
  return { inside, realPath };
3907
3909
  }
3910
+ function isFile2(file) {
3911
+ try {
3912
+ return statSync2(file).isFile();
3913
+ } catch {
3914
+ return false;
3915
+ }
3916
+ }
3908
3917
  function isStylesheet(realPath) {
3909
3918
  return path11.extname(realPath).toLowerCase() === ".css";
3910
3919
  }
@@ -3972,14 +3981,28 @@ function planThemeAdd(baseDirInput, brand) {
3972
3981
  return plan;
3973
3982
  }
3974
3983
  }
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;
3975
3986
  const tailwind = detectTailwind(baseDir, pkg);
3976
3987
  const tailwind4 = tailwind.major !== void 0 && tailwind.major >= 4;
3977
- const requiredBaseImports = tailwind4 ? [
3978
- TOKENS_TAILWIND4_ENTRY,
3979
- ...TAILWIND4_COMPONENT_PACKAGES.filter((n) => pkg !== void 0 && hasDependency(pkg, n) !== void 0).map(
3980
- (n) => `${n}/tailwind.css`
3981
- )
3982
- ] : [...TAILWIND3_BASE_IMPORTS];
3988
+ const componentImports = [];
3989
+ const deferredComponentImports = [];
3990
+ if (tailwind4 && pkg !== void 0) {
3991
+ for (const n of TAILWIND4_COMPONENT_PACKAGES) {
3992
+ if (hasDependency(pkg, n) !== void 0) {
3993
+ componentImports.push(n);
3994
+ continue;
3995
+ }
3996
+ if (declaredDependency(baseDir, pkg, n, rootPkg)?.source !== "root") continue;
3997
+ const installed2 = findInstalledPackage(baseDir, n);
3998
+ if (installed2 !== void 0 && isFile2(path11.join(installed2.dir, "tailwind.css"))) {
3999
+ componentImports.push(n);
4000
+ } else {
4001
+ deferredComponentImports.push(installed2 === void 0 ? { name: n } : { name: n, installedVersion: installed2.version ?? "?" });
4002
+ }
4003
+ }
4004
+ }
4005
+ const requiredBaseImports = tailwind4 ? [TOKENS_TAILWIND4_ENTRY, ...componentImports.map((n) => `${n}/tailwind.css`)] : [...TAILWIND3_BASE_IMPORTS];
3983
4006
  const location = findGlobalCss(baseDir, config);
3984
4007
  if (location.path) {
3985
4008
  const where = realPathInside(baseDir, location.path);
@@ -3998,6 +4021,7 @@ function planThemeAdd(baseDirInput, brand) {
3998
4021
  const otherBrands = [...new Set(imported.filter((n) => n !== brand))];
3999
4022
  const brandAdded = !imported.includes(brand);
4000
4023
  const baseImports = requiredBaseImports.filter((spec) => !hasCssImport(before, spec));
4024
+ const deferredHere = deferredComponentImports.filter((d) => !hasCssImport(before, `${d.name}/tailwind.css`));
4001
4025
  const lines = [...baseImports.map((spec) => `@import "${spec}";`), ...brandAdded ? [`@import "${plan.importPath}";`] : []];
4002
4026
  plan.css = {
4003
4027
  file: location.path,
@@ -4008,7 +4032,8 @@ function planThemeAdd(baseDirInput, brand) {
4008
4032
  baseImports,
4009
4033
  requiredBaseImports,
4010
4034
  lateImports: findLateImports(before),
4011
- tailwind4
4035
+ tailwind4,
4036
+ ...deferredHere.length > 0 ? { deferredComponentImports: deferredHere } : {}
4012
4037
  };
4013
4038
  if (lines.length > 0) {
4014
4039
  plan.writes.push({ file: location.path, before, after: insertImportLines(before, lines) });
@@ -4022,7 +4047,8 @@ function planThemeAdd(baseDirInput, brand) {
4022
4047
  baseImports: requiredBaseImports,
4023
4048
  requiredBaseImports,
4024
4049
  lateImports: [],
4025
- tailwind4
4050
+ tailwind4,
4051
+ ...deferredComponentImports.length > 0 ? { deferredComponentImports } : {}
4026
4052
  };
4027
4053
  }
4028
4054
  if (!tailwind4) {
@@ -4043,10 +4069,18 @@ function planThemeAdd(baseDirInput, brand) {
4043
4069
  if (pkgText === null || pkg === void 0) {
4044
4070
  plan.dependency = { action: "no-package-json", upgrade, themeMissing: false, tokensAddCommand, themeAddCommand };
4045
4071
  } else {
4046
- const themeMissing = hasDependency(pkg, THEME_PACKAGE) === void 0;
4047
- const declared = hasDependency(pkg, TOKENS_PACKAGE);
4072
+ const themeMissing = declaredDependency(baseDir, pkg, THEME_PACKAGE, rootPkg) === void 0;
4073
+ const declared = declaredDependency(baseDir, pkg, TOKENS_PACKAGE, rootPkg);
4048
4074
  if (declared !== void 0) {
4049
- plan.dependency = { action: "present", declaredRange: declared, upgrade, themeMissing, tokensAddCommand, themeAddCommand };
4075
+ plan.dependency = {
4076
+ action: "present",
4077
+ declaredRange: declared.range,
4078
+ declaredSource: declared.source,
4079
+ upgrade,
4080
+ themeMissing,
4081
+ tokensAddCommand,
4082
+ themeAddCommand
4083
+ };
4050
4084
  } else {
4051
4085
  const deps = isPlainObject(pkg.dependencies) ? { ...pkg.dependencies } : {};
4052
4086
  deps[TOKENS_PACKAGE] = TOKENS_DEPENDENCY_RANGE;
@@ -4365,6 +4399,15 @@ function renderThemeAdd(plan, written) {
4365
4399
  )
4366
4400
  );
4367
4401
  }
4402
+ for (const d of css?.deferredComponentImports ?? []) {
4403
+ const line = `@import "${d.name}/tailwind.css";`;
4404
+ const current = d.installedVersion !== void 0 && d.installedVersion !== "?" && (compareExactVersions(d.installedVersion, COMPONENT_TAILWIND_CSS_MIN_VERSION) ?? -1) >= 0;
4405
+ lines.push(
4406
+ chalk9.yellow(
4407
+ d.installedVersion === void 0 ? ` ! ${d.name} \uAC00 \uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uB8E8\uD2B8\uC5D0 \uC120\uC5B8\uB410\uC9C0\uB9CC \uC124\uCE58\uB418\uC9C0 \uC54A\uC544 ${line} \uB97C \uB123\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. \uC124\uCE58(${plan.installCommand}) \uB4A4 theme add \uB97C \uB2E4\uC2DC \uC2E4\uD589\uD558\uAC70\uB098 \uC9C1\uC811 \uB123\uC73C\uC138\uC694.` : current ? ` ! \uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uB8E8\uD2B8\uC5D0 \uC120\uC5B8\uB41C ${d.name} \uC758 \uC124\uCE58\uBCF8(${d.installedVersion})\uC5D0 tailwind.css \uAC00 \uC5C6\uC5B4 ${line} \uB97C \uB123\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. \uC124\uCE58\uAC00 \uC190\uC0C1\uB410\uC744 \uC218 \uC788\uC73C\uB2C8 \uB2E4\uC2DC \uC124\uCE58(${plan.installCommand}) \uB4A4 theme add \uB97C \uB2E4\uC2DC \uC2E4\uD589\uD558\uAC70\uB098 \uC9C1\uC811 \uB123\uC73C\uC138\uC694.` : ` ! \uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uB8E8\uD2B8\uC5D0 \uC120\uC5B8\uB41C ${d.name} \uC758 \uC124\uCE58\uBCF8(${d.installedVersion === "?" ? "\uBC84\uC804 \uBAA8\uB984" : d.installedVersion})\uC5D0 tailwind.css \uAC00 \uC5C6\uC5B4(${COMPONENT_TAILWIND_CSS_MIN_VERSION} \uBD80\uD130 \uC81C\uACF5) ${line} \uB97C \uB123\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. ${COMPONENT_TAILWIND_CSS_MIN_VERSION} \uC774\uC0C1\uC73C\uB85C \uC62C\uB9B0 \uB4A4 theme add \uB97C \uB2E4\uC2DC \uC2E4\uD589\uD558\uAC70\uB098 \uC9C1\uC811 \uB123\uC73C\uC138\uC694.`
4408
+ )
4409
+ );
4410
+ }
4368
4411
  if (css && css.otherBrands.length > 0) {
4369
4412
  lines.push(
4370
4413
  chalk9.yellow(
@@ -4378,6 +4421,11 @@ function renderThemeAdd(plan, written) {
4378
4421
  ` ${chalk9.green("\u2713")} package.json: dependencies \uC5D0 "${TOKENS_PACKAGE}": "${TOKENS_DEPENDENCY_RANGE}" \uCD94\uAC00`,
4379
4422
  ` \uC124\uCE58\uB294 \uC2E4\uD589\uD558\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. \uC124\uCE58: ${chalk9.cyan(plan.installCommand)}`
4380
4423
  );
4424
+ } else if (dep?.action === "present" && dep.declaredSource === "root") {
4425
+ lines.push(
4426
+ ` ${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
+ );
4428
+ if (plan.tokens.status === "not-installed") lines.push(` \uC124\uCE58: ${chalk9.cyan(plan.installCommand)}`);
4381
4429
  } else if (dep?.action === "present") {
4382
4430
  lines.push(` ${chalk9.gray("-")} package.json: ${TOKENS_PACKAGE} ${dep.declaredRange} \uAC00 \uC774\uBBF8 \uC788\uC5B4 \uBC94\uC704\uB97C \uBC14\uAFB8\uC9C0 \uC54A\uC74C`);
4383
4431
  } else if (dep?.action === "no-package-json") {
@@ -4387,9 +4435,13 @@ function renderThemeAdd(plan, written) {
4387
4435
  lines.push(
4388
4436
  chalk9.yellow(
4389
4437
  ` ! \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).`
4390
- ),
4391
- ` \uC5C5\uADF8\uB808\uC774\uB4DC: ${chalk9.cyan(dep.tokensAddCommand)}`
4438
+ )
4392
4439
  );
4440
+ if (dep.action === "present" && dep.declaredSource === "root") {
4441
+ lines.push(` \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.`);
4442
+ } else {
4443
+ lines.push(` \uC5C5\uADF8\uB808\uC774\uB4DC: ${chalk9.cyan(dep.tokensAddCommand)}`);
4444
+ }
4393
4445
  }
4394
4446
  if (plan.configChanged) {
4395
4447
  lines.push(` ${chalk9.green("\u2713")} axis.config.json: "brand": "${plan.brand}" \uAE30\uB85D`);
@@ -4794,13 +4846,13 @@ async function fetchRegistryJson(url, options = {}) {
4794
4846
  }
4795
4847
 
4796
4848
  // src/init/init.ts
4797
- import { accessSync as accessSync2, constants as constants2, existsSync as existsSync5, lstatSync as lstatSync3, readFileSync as readFileSync5, realpathSync as realpathSync4, statSync as statSync3, writeFileSync as writeFileSync2 } from "fs";
4849
+ import { accessSync as accessSync2, constants as constants2, existsSync as existsSync5, lstatSync as lstatSync3, readFileSync as readFileSync5, realpathSync as realpathSync4, statSync as statSync4, writeFileSync as writeFileSync2 } from "fs";
4798
4850
  import path14 from "path";
4799
4851
  import chalk10 from "chalk";
4800
4852
  import fs12 from "fs-extra";
4801
4853
 
4802
4854
  // ../axis-registry-core/src/add/safe-write.ts
4803
- import { constants as fsConstants, existsSync as existsSync4, lstatSync as lstatSync2, realpathSync as realpathSync3, statSync as statSync2 } from "fs";
4855
+ import { constants as fsConstants, existsSync as existsSync4, lstatSync as lstatSync2, realpathSync as realpathSync3, statSync as statSync3 } from "fs";
4804
4856
  import path13 from "path";
4805
4857
  import fs11 from "fs-extra";
4806
4858
  var NEW_FILE_FLAGS = fsConstants.O_WRONLY | fsConstants.O_CREAT | fsConstants.O_EXCL | (fsConstants.O_NOFOLLOW ?? 0);
@@ -4856,7 +4908,7 @@ function escapeReason(root, target, options = {}) {
4856
4908
  }
4857
4909
  let followed;
4858
4910
  try {
4859
- followed = statSync2(realTarget);
4911
+ followed = statSync3(realTarget);
4860
4912
  } catch {
4861
4913
  return `\uAE30\uC874 \uD30C\uC77C \uC815\uBCF4\uB97C \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4(${target})`;
4862
4914
  }
@@ -5049,9 +5101,25 @@ async function resolveInitAnswers(baseDirInput, tailwind4) {
5049
5101
  }
5050
5102
  return { answers, notes };
5051
5103
  }
5052
- function animationGuideLine(pkg, tailwind4, installCommand) {
5104
+ function animationGuideLine(pkg, tailwind4, installCommand, baseDir) {
5053
5105
  const name = tailwind4 ? ANIMATION_PLUGIN_TAILWIND4 : ANIMATION_PLUGIN_TAILWIND3;
5054
- if (pkg !== void 0 && (hasDependency(pkg, ANIMATION_PLUGIN_TAILWIND3) !== void 0 || hasDependency(pkg, ANIMATION_PLUGIN_TAILWIND4) !== void 0)) {
5106
+ if (baseDir !== void 0) {
5107
+ const pnp = isPnpProject(baseDir);
5108
+ const candidates = tailwind4 ? [ANIMATION_PLUGIN_TAILWIND4, ANIMATION_PLUGIN_TAILWIND3] : [ANIMATION_PLUGIN_TAILWIND3];
5109
+ const declaredOf = (n) => {
5110
+ if (pkg === void 0) return void 0;
5111
+ if (pnp) return hasDependency(pkg, n) !== void 0 ? { source: "app" } : void 0;
5112
+ return declaredDependency(baseDir, pkg, n);
5113
+ };
5114
+ for (const candidate of candidates) {
5115
+ const declared = declaredOf(candidate);
5116
+ if (declared === void 0) continue;
5117
+ if (pnp || findInstalledPackage(baseDir, candidate) !== void 0) return void 0;
5118
+ const declaredWhere = declared.source === "root" ? "\uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uB8E8\uD2B8\uC5D0 " : "";
5119
+ const setup = !tailwind4 ? `tailwind.config \uC758 plugins \uC5D0 require("${candidate}") \uB97C \uB123\uC73C\uC138\uC694` : candidate === ANIMATION_PLUGIN_TAILWIND4 ? `\uC804\uC5ED CSS \uC5D0 @import "${candidate}"; \uB97C \uB123\uC73C\uC138\uC694` : `\uC804\uC5ED CSS \uC5D0 @plugin "${candidate}"; \uB97C \uB123\uC73C\uC138\uC694`;
5120
+ return `\uC560\uB2C8\uBA54\uC774\uC158: ${candidate} \uB294 ${declaredWhere}\uC120\uC5B8\uB3FC \uC788\uC9C0\uB9CC \uC124\uCE58\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. ${installCommand} \uB4A4 ${setup}.`;
5121
+ }
5122
+ } else if (pkg !== void 0 && (hasDependency(pkg, ANIMATION_PLUGIN_TAILWIND3) !== void 0 || hasDependency(pkg, ANIMATION_PLUGIN_TAILWIND4) !== void 0)) {
5055
5123
  return void 0;
5056
5124
  }
5057
5125
  const add = `${addCommandFor(installCommand, {}).trimEnd()} ${name}`;
@@ -5315,7 +5383,7 @@ function planUtilsWrite(baseDirInput, utilsPath) {
5315
5383
  }
5316
5384
  let target;
5317
5385
  try {
5318
- target = statSync3(real);
5386
+ target = statSync4(real);
5319
5387
  } catch (e) {
5320
5388
  return { action: "reject", reason: `${shown} \uB9C1\uD06C \uB300\uC0C1(${real})\uC758 \uC815\uBCF4\uB97C \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4(${errCode(e)})` };
5321
5389
  }
@@ -5391,7 +5459,7 @@ async function runInit(baseDirInput, answers, registryUrl, log = console.log, op
5391
5459
  }
5392
5460
  if (previousText !== null && previousText !== nextText) {
5393
5461
  try {
5394
- const st = statSync3(configPath);
5462
+ const st = statSync4(configPath);
5395
5463
  if (st.isFile() && st.nlink >= 2) rejects.push(hardLinkMessage("axis.config.json", st.nlink));
5396
5464
  } catch {
5397
5465
  }
@@ -5490,7 +5558,7 @@ async function runInit(baseDirInput, answers, registryUrl, log = console.log, op
5490
5558
  return;
5491
5559
  }
5492
5560
  reportDependencies(plan, log);
5493
- const animation = animationGuideLine(readPackageJsonSafe(baseDir), tailwind4, plan.installCommand);
5561
+ const animation = animationGuideLine(readPackageJsonSafe(baseDir), tailwind4, plan.installCommand, baseDir);
5494
5562
  if (animation !== void 0) log(chalk10.yellow(` ${animation}`));
5495
5563
  if (tailwind4) {
5496
5564
  const [head, ...rest] = tailwind4GuideLines(
@@ -5550,7 +5618,7 @@ function registerInitCommand(program2, registryUrl = DEFAULT_REGISTRY_URL, deps
5550
5618
  import chalk12 from "chalk";
5551
5619
 
5552
5620
  // ../axis-registry-core/src/add/add.ts
5553
- import { existsSync as existsSync7, readFileSync as readFileSync7, statSync as statSync4 } from "fs";
5621
+ import { existsSync as existsSync7, readFileSync as readFileSync7, statSync as statSync5 } from "fs";
5554
5622
  import path16 from "path";
5555
5623
  import fs13 from "fs-extra";
5556
5624
 
@@ -6209,7 +6277,7 @@ function relativeSpecifierResolves(fromFile, spec) {
6209
6277
  const base = path16.resolve(path16.dirname(fromFile), spec);
6210
6278
  return RESOLVE_EXTS.some((ext) => {
6211
6279
  try {
6212
- return statSync4(base + ext).isFile();
6280
+ return statSync5(base + ext).isFile();
6213
6281
  } catch {
6214
6282
  return false;
6215
6283
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axis-ds/cli",
3
- "version": "1.7.4",
3
+ "version": "1.7.5",
4
4
  "type": "module",
5
5
  "description": "AXIS Design System - CLI for adding components (shadcn compatible)",
6
6
  "publishConfig": {