@axis-ds/cli 1.2.1 → 1.4.0

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 +38 -0
  2. package/dist/index.js +540 -172
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -23,6 +23,28 @@ axis add button
23
23
  axis list
24
24
  ```
25
25
 
26
+ ## 프로젝트 초기화 (`axis init`)
27
+
28
+ - `axis.config.json` 과 `cn()` 을 담은 `utils.ts` 를 만들고, `clsx` · `tailwind-merge` 가 `package.json` 에 없으면 `dependencies` 에 더합니다. 설치는 실행하지 않고 명령만 안내합니다.
29
+ - `tailwind-merge` 범위와 아래 안내는 프로젝트의 Tailwind 버전(설치본, 없으면 `package.json` 선언)으로 정합니다. 판정하지 못하면 Tailwind 3 으로 봅니다.
30
+ - Tailwind 4 이상이면 전역 CSS 에 넣을 줄을 안내합니다. CSS 파일은 고치지 않습니다.
31
+
32
+ ```css
33
+ @import "tailwindcss";
34
+ @import "@axis-ds/tokens/css/tailwind4";
35
+ @import "@axis-ds/ui-react/tailwind.css"; /* npm 패키지 컴포넌트를 쓸 때, agentic-ui 도 같은 방식 */
36
+ ```
37
+
38
+ - 컴포넌트 패키지 줄은 `package.json` 에 선언된 `@axis-ds/ui-react` · `@axis-ds/agentic-ui` 만큼 냅니다. 선언이 없으면 예시 한 줄만 냅니다(`axis add` 로 복사한 컴포넌트는 프로젝트 소스라 따로 넣을 필요가 없습니다).
39
+ - 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」와 같은 내용).
40
+ - `@axis-ds/tokens` 가 `package.json` 에 없으면 lockfile 에 맞춘 설치 명령(예: `pnpm add "@axis-ds/tokens@^1.4.0"`)을 안내합니다. 토큰 진입점은 1.4.0 부터 있습니다.
41
+ - `package.json` 에 선언된 `@axis-ds/tokens` · `@axis-ds/ui-react` · `@axis-ds/agentic-ui` 의 버전 조건(`axis check` 와 같은 함수 · 같은 판정). 설치본을 먼저 보고, 없으면 선언 범위를 봅니다:
42
+ - 설치본: `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 이상으로 올린 뒤 다시 설치하라는 줄만 냅니다(선언을 덮어쓰지 않음).
43
+ - 설치본이 없을 때 선언 범위의 하한이 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`)는 가장 높은 하한을 봅니다.
44
+ - 하한을 읽을 수 없으면(`catalog:` · `latest` · `||` · `<2` · `*` 등) 선언을 덮어쓰는 명령 대신 「설치된 버전이 1.4.0 이상인지 확인하세요」를 냅니다.
45
+ - `workspace:` 프로토콜은 모노레포 링크라 설치본과 관계없이 안내하지 않습니다(링크된 패키지의 `version` 은 배포 전 소스의 값이라 1.4.0 미만이어도 진입점이 없다는 근거가 아닙니다).
46
+ - Tailwind 4 에는 설정 파일이 없으므로 `axis.config.json` 에 `tailwindConfig` 를 적지 않고, 대화형 실행에서도 묻지 않습니다. Tailwind 3 은 종전과 같습니다.
47
+
26
48
  ## 브랜드 테마 (`axis theme`)
27
49
 
28
50
  프로젝트에 설치된 `@axis-ds/tokens`(1.3.0 이상)의 브랜드를 조회하고 적용합니다. 세 명령 모두 `-d, --dir <path>` 로 대상 디렉터리를 받습니다(기본: 현재 디렉터리).
@@ -44,6 +66,22 @@ axis theme add ontology
44
66
  - `@axis-ds/tokens` 가 없거나 1.3.0 미만이면 목록 대신 설치 · 업그레이드 안내를 내고 종료 코드 1 로 끝납니다.
45
67
  - `axis check` 는 `axis.config.json` 의 `brand` 와 CSS 의 브랜드 import 가 맞는지도 봅니다.
46
68
 
69
+ ## 프로젝트 검증 (`axis check`)
70
+
71
+ - Tailwind 구성 항목: Tailwind 4 이상(설치본, 없으면 `package.json` 선언으로 판정)은 설정 파일 대신 전역 CSS(`globals.css` · `app/globals.css` · `src/app/globals.css` · `src/globals.css` · `styles/globals.css` 순으로 처음 찾은 파일 하나)를 봅니다. Tailwind 3 이하는 `tailwind.config.ts` · `.js` · `.mjs` · `.cjs` 를 찾습니다.
72
+ - Tailwind 4: `@import "tailwindcss"` 가 있는 CSS 에서 아래 문제가 하나도 없으면 PASS 이고, 하나라도 있으면 WARN 입니다(블록 주석 안은 없는 것으로 봅니다). `@import "tailwindcss"` 가 없으면 그 WARN 하나만 냅니다.
73
+ 1. 토큰 진입점 `@import "@axis-ds/tokens/css/tailwind4";` 이 없음 → 문구에 넣을 import 줄. 진입점이 없으면 `bg-primary` · `rounded-md` 같은 AXIS 매핑이 만들어지지 않습니다. `@axis-ds/tokens/css` · `css/shadcn` · `tailwind`(Tailwind 3 preset)는 진입점으로 치지 않습니다.
74
+ 2. `package.json` 에 선언된 `@axis-ds/ui-react` · `@axis-ds/agentic-ui` 의 `tailwind.css` import 가 없음 → 빠진 import 줄. 선언이 없으면(복사 설치) 요구하지 않습니다. `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 쪽으로 판정).
75
+ 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 기본 블록 이름이라, 같은 선언이 다른 선택자에 있어도 그 이름으로 표시됩니다.
76
+ 4. 진입점이 있는데 `@axis-ds/tokens` 가 아래 버전 조건에 걸림.
77
+ 5. `@axis-ds/ui-react/tailwind.css` · `@axis-ds/agentic-ui/tailwind.css` 를 import 하는데 그 패키지가 아래 버전 조건에 걸림(`tailwind.css` 는 1.4.0 부터 있음). 직접 `@source` 로 스캔하는 패키지는 `tailwind.css` 가 필요 없으므로 이 문제를 만들지 않습니다.
78
+ - 문제가 여럿이면 위 순서대로 ` / ` 로 이어 한 항목에 냅니다. 끝에는 `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:` 는 넣지 않습니다.
79
+ - 문구 예: `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)`
80
+ - Tailwind 3: `tailwind.config.ts` 에 `--background` · `hsl(var(` 가 있으면 종전 문구로 PASS 입니다. 그렇지 않아도 설정 파일(`.ts` · `.js` · `.mjs` · `.cjs`)이 `@axis-ds/tokens/tailwind` preset 을 `require` · `import` 하면(주석 밖) `tailwind.config.mjs에 AXIS 토큰이 설정되어 있습니다 (@axis-ds/tokens/tailwind preset)` 처럼 PASS 입니다. 1.3.0 에서는 preset 만 쓰는 `.ts` 가 WARN(`AXIS 토큰 설정이 없습니다`), `.js` · `.mjs` · `.cjs` 가 WARN(`TypeScript 권장`)이었습니다.
81
+ - globals.css 항목: 같은 후보에서 처음 찾은 CSS 하나를 봅니다. `--background` 와 `--primary` 를 직접 정의하거나, `@axis-ds/tokens/css` · `@axis-ds/tokens/css/shadcn` · `@axis-ds/tokens/css/tailwind4` 를 import 하면(블록 주석 밖, 작은따옴표 · `url()` · `layer()` 표기 포함) PASS 입니다. import 로 인정한 경우 문구 끝에 `(@axis-ds/tokens/css/tailwind4 import)` 처럼 경로가 붙습니다. 1.4.0 부터이고, 이전에는 import 만 있으면 WARN 이었습니다.
82
+ - FAIL 이 하나라도 있으면 종료 코드 1 로 끝납니다. WARN 만 있으면 0 입니다(1.3.0 부터, 이전에는 결과와 관계없이 0).
83
+ - MCP `axis.check_project` 도 같은 항목 · 문구를 냅니다.
84
+
47
85
  ## 문서
48
86
 
49
87
  자세한 사용법은 [AXIS Design System 문서](https://axis.minu.best)를 참고하세요.
package/dist/index.js CHANGED
@@ -1580,7 +1580,7 @@ function createInitConfig(answers, registry) {
1580
1580
  return {
1581
1581
  $schema: AXIS_CONFIG_SCHEMA_URL,
1582
1582
  componentsDir: answers.componentsDir,
1583
- tailwindConfig: answers.tailwindConfig,
1583
+ ...answers.tailwindConfig !== void 0 ? { tailwindConfig: answers.tailwindConfig } : {},
1584
1584
  globalCss: answers.globalCss,
1585
1585
  registry
1586
1586
  };
@@ -2099,6 +2099,438 @@ function getBrand(baseDir, name) {
2099
2099
  };
2100
2100
  }
2101
2101
 
2102
+ // src/template/tailwind-core.ts
2103
+ import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
2104
+ import { join as join2, resolve as resolve2 } from "path";
2105
+ function hasDependency(pkg, name) {
2106
+ for (const field of ["dependencies", "devDependencies"]) {
2107
+ const deps = pkg[field];
2108
+ if (typeof deps === "object" && deps !== null && name in deps) {
2109
+ return String(deps[name]);
2110
+ }
2111
+ }
2112
+ return void 0;
2113
+ }
2114
+ function isPlainObject(value) {
2115
+ return typeof value === "object" && value !== null && !Array.isArray(value);
2116
+ }
2117
+ var VERSION = String.raw`v?(\d+)(?:\.(\d+|[xX*]))?(?:\.(\d+|[xX*]))?(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?`;
2118
+ function versionParts(token) {
2119
+ const m = new RegExp(`^${VERSION}$`).exec(token);
2120
+ if (!m) return void 0;
2121
+ if (/^v?0\.0\.0-/.test(token)) return void 0;
2122
+ return { major: Number(m[1]), minor: m[2], patch: m[3] };
2123
+ }
2124
+ var isWild = (part) => part === void 0 || /^[xX*]$/.test(part);
2125
+ function comparatorBounds(op, v) {
2126
+ switch (op) {
2127
+ case ">=":
2128
+ return { lower: v.major };
2129
+ case ">":
2130
+ return { lower: isWild(v.minor) ? v.major + 1 : v.major };
2131
+ case "<=":
2132
+ return { upper: v.major };
2133
+ case "<": {
2134
+ const zeroOrWild = (part) => isWild(part) || Number(part) === 0;
2135
+ return { upper: zeroOrWild(v.minor) && zeroOrWild(v.patch) ? v.major - 1 : v.major };
2136
+ }
2137
+ default:
2138
+ return { lower: v.major, upper: v.major };
2139
+ }
2140
+ }
2141
+ function tailwindMajorBounds(range) {
2142
+ const r = range.trim();
2143
+ if (r === "" || r.includes("||")) return void 0;
2144
+ const simple = new RegExp(`^(?:\\^|~|=)?\\s*(${VERSION})$`).exec(r);
2145
+ if (simple) {
2146
+ const v = versionParts(simple[1]);
2147
+ return v ? { lower: v.major, upper: v.major } : void 0;
2148
+ }
2149
+ const hyphen = new RegExp(`^(${VERSION})\\s+-\\s+(${VERSION})$`).exec(r);
2150
+ if (hyphen) {
2151
+ const tokens2 = r.split(/\s+-\s+/);
2152
+ const a = versionParts(tokens2[0]);
2153
+ const b = versionParts(tokens2[1]);
2154
+ return a && b && a.major <= b.major ? { lower: a.major, upper: b.major } : void 0;
2155
+ }
2156
+ const tokens = r.replace(/(>=|<=|>|<|=)\s+/g, "$1").split(/\s+/);
2157
+ const lowers = [];
2158
+ const uppers = [];
2159
+ for (const t of tokens) {
2160
+ const c = /^(>=|<=|>|<|=)(.+)$/.exec(t);
2161
+ if (!c) return void 0;
2162
+ const v = versionParts(c[2]);
2163
+ if (v === void 0) return void 0;
2164
+ const b = comparatorBounds(c[1], v);
2165
+ if (b.lower !== void 0) lowers.push(b.lower);
2166
+ if (b.upper !== void 0) uppers.push(b.upper);
2167
+ }
2168
+ if (lowers.length === 0) return void 0;
2169
+ const lower = Math.max(...lowers);
2170
+ const upper = uppers.length > 0 ? Math.min(...uppers) : void 0;
2171
+ if (upper !== void 0 && upper < lower) return void 0;
2172
+ return upper !== void 0 ? { lower, upper } : { lower };
2173
+ }
2174
+ function majorWithin(major, bounds) {
2175
+ return major >= bounds.lower && (bounds.upper === void 0 || major <= bounds.upper);
2176
+ }
2177
+ function majorFromVersion(version) {
2178
+ if (typeof version !== "string") return void 0;
2179
+ const v = version.trim();
2180
+ const m = /^v?(\d+)\.\d+\.\d+(?:[-+][0-9A-Za-z.+-]*)?$/.exec(v);
2181
+ if (!m || /^v?0\.0\.0-/.test(v)) return void 0;
2182
+ return Number(m[1]);
2183
+ }
2184
+ function detectTailwind(baseDirInput, pkg) {
2185
+ const baseDir = resolve2(baseDirInput);
2186
+ const installedFile = join2(baseDir, "node_modules", "tailwindcss", "package.json");
2187
+ const declared = pkg ? hasDependency(pkg, "tailwindcss") : void 0;
2188
+ const bounds = declared !== void 0 ? tailwindMajorBounds(declared) : void 0;
2189
+ const declaredMajor = bounds?.lower;
2190
+ try {
2191
+ const installed = JSON.parse(readFileSync2(installedFile, "utf8"));
2192
+ const version = isPlainObject(installed) ? installed.version : void 0;
2193
+ const major = majorFromVersion(version);
2194
+ if (major !== void 0) {
2195
+ const found = { major, source: "installed", value: String(version) };
2196
+ if (declared !== void 0 && bounds !== void 0 && !majorWithin(major, bounds)) {
2197
+ found.mismatch = { declared, declaredMajor: bounds.lower };
2198
+ }
2199
+ return found;
2200
+ }
2201
+ } catch {
2202
+ }
2203
+ if (declared !== void 0) {
2204
+ if (declaredMajor !== void 0) return { major: declaredMajor, source: "declared", value: declared };
2205
+ return { source: "none", value: declared };
2206
+ }
2207
+ return { source: "none" };
2208
+ }
2209
+ var TAILWIND_CONFIG_FILES = [
2210
+ "tailwind.config.ts",
2211
+ "tailwind.config.js",
2212
+ "tailwind.config.mjs",
2213
+ "tailwind.config.cjs"
2214
+ ];
2215
+ var TAILWIND_CSS_CANDIDATES = [
2216
+ "globals.css",
2217
+ "app/globals.css",
2218
+ "src/app/globals.css",
2219
+ "src/globals.css",
2220
+ "styles/globals.css"
2221
+ ];
2222
+ var TAILWIND_IMPORT = /@import\s+(?:url\(\s*)?["']tailwindcss["']/;
2223
+ function stripCssComments(css) {
2224
+ return css.replace(/\/\*[\s\S]*?\*\//g, "");
2225
+ }
2226
+ function hasTailwindImport(css) {
2227
+ return TAILWIND_IMPORT.test(stripCssComments(css));
2228
+ }
2229
+ var TOKENS_TAILWIND4_ENTRY = "@axis-ds/tokens/css/tailwind4";
2230
+ var TOKENS_TAILWIND4_IMPORT_LINE = `@import "${TOKENS_TAILWIND4_ENTRY}";`;
2231
+ var TOKENS_TAILWIND4_IMPORT = /@import\s+(?:url\(\s*)?["']@axis-ds\/tokens\/css\/tailwind4["']/;
2232
+ function hasTokensTailwind4Import(css) {
2233
+ return TOKENS_TAILWIND4_IMPORT.test(stripCssComments(css));
2234
+ }
2235
+ var TOKENS_CSS_IMPORT = /@import\s+(?:url\(\s*)?["'](@axis-ds\/tokens\/css(?:\/shadcn|\/tailwind4)?)["']/;
2236
+ function findTokensCssImport(css) {
2237
+ return TOKENS_CSS_IMPORT.exec(stripCssComments(css))?.[1];
2238
+ }
2239
+ function checkGlobalsCss(baseDirInput) {
2240
+ const baseDir = resolve2(baseDirInput);
2241
+ for (const candidate of TAILWIND_CSS_CANDIDATES) {
2242
+ const file = join2(baseDir, candidate);
2243
+ if (!existsSync2(file)) continue;
2244
+ const content = readFileSync2(file, "utf8");
2245
+ if (content.includes("--background") && content.includes("--primary")) {
2246
+ return { name: "globals.css", severity: "pass", message: `${candidate}\uC5D0 AXIS CSS \uBCC0\uC218\uAC00 \uC815\uC758\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4` };
2247
+ }
2248
+ const imported = findTokensCssImport(content);
2249
+ if (imported !== void 0) {
2250
+ return { name: "globals.css", severity: "pass", message: `${candidate}\uC5D0 AXIS CSS \uBCC0\uC218\uAC00 \uC788\uC2B5\uB2C8\uB2E4 (${imported} import)` };
2251
+ }
2252
+ return { name: "globals.css", severity: "warn", message: `${candidate}\uC5D0 AXIS CSS \uBCC0\uC218\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4` };
2253
+ }
2254
+ return { name: "globals.css", severity: "fail", message: "globals.css \uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4" };
2255
+ }
2256
+ var TAILWIND4_MIN_AXIS_VERSION = "1.4.0";
2257
+ var TAILWIND4_AXIS_PACKAGES = ["@axis-ds/tokens", "@axis-ds/ui-react", "@axis-ds/agentic-ui"];
2258
+ function lowerOf(token) {
2259
+ const v = versionParts(token);
2260
+ if (!v) return void 0;
2261
+ const num = (part) => isWild(part) ? 0 : Number(part);
2262
+ const pre = /^v?\d+(?:\.(?:\d+|[xX*]))?(?:\.(?:\d+|[xX*]))?-/.test(token);
2263
+ return { core: [v.major, num(v.minor), num(v.patch)], pre };
2264
+ }
2265
+ function compareLower(a, b) {
2266
+ for (let i = 0; i < 3; i++) {
2267
+ if (a.core[i] !== b.core[i]) return a.core[i] - b.core[i];
2268
+ }
2269
+ return Number(b.pre) - Number(a.pre);
2270
+ }
2271
+ function rangeLowerVersion(range) {
2272
+ const r = range.trim();
2273
+ if (r === "" || r.includes("||")) return void 0;
2274
+ const simple = new RegExp(`^(?:\\^|~|=)?\\s*(${VERSION})$`).exec(r);
2275
+ if (simple) return lowerOf(simple[1]);
2276
+ if (new RegExp(`^(${VERSION})\\s+-\\s+(${VERSION})$`).test(r)) {
2277
+ const [a, b] = r.split(/\s+-\s+/);
2278
+ return lowerOf(b) ? lowerOf(a) : void 0;
2279
+ }
2280
+ const tokens = r.replace(/(>=|<=|>|<|=)\s+/g, "$1").split(/\s+/);
2281
+ let lower;
2282
+ for (const t of tokens) {
2283
+ const c = /^(>=|<=|>|<|=)(.+)$/.exec(t);
2284
+ if (!c) return void 0;
2285
+ const v = versionParts(c[2]);
2286
+ const low = lowerOf(c[2]);
2287
+ if (!v || !low) return void 0;
2288
+ let candidate;
2289
+ if (c[1] === ">=" || c[1] === "=") candidate = low;
2290
+ else if (c[1] === ">") {
2291
+ if (isWild(v.minor)) candidate = { core: [v.major + 1, 0, 0], pre: false };
2292
+ else if (isWild(v.patch)) candidate = { core: [v.major, Number(v.minor) + 1, 0], pre: false };
2293
+ else candidate = { core: [v.major, Number(v.minor), Number(v.patch) + 1], pre: false };
2294
+ }
2295
+ if (candidate && (!lower || compareLower(candidate, lower) > 0)) lower = candidate;
2296
+ }
2297
+ return lower;
2298
+ }
2299
+ function rangeLowerAtLeast(range, min) {
2300
+ const lower = rangeLowerVersion(range);
2301
+ const target = lowerOf(min);
2302
+ if (!lower || !target) return void 0;
2303
+ return compareLower(lower, target) >= 0;
2304
+ }
2305
+ function exactVersion(version) {
2306
+ if (typeof version !== "string") return void 0;
2307
+ const v = version.trim();
2308
+ if (!/^v?\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/.test(v) || /^v?0\.0\.0-/.test(v)) return void 0;
2309
+ return v;
2310
+ }
2311
+ function installedVersion(baseDir, name) {
2312
+ try {
2313
+ const parsed = JSON.parse(readFileSync2(join2(baseDir, "node_modules", ...name.split("/"), "package.json"), "utf8"));
2314
+ return isPlainObject(parsed) ? exactVersion(parsed.version) : void 0;
2315
+ } catch {
2316
+ return void 0;
2317
+ }
2318
+ }
2319
+ function axisPackagesBelowTailwind4(pkg, baseDirInput) {
2320
+ if (!pkg) return [];
2321
+ const baseDir = baseDirInput !== void 0 ? resolve2(baseDirInput) : void 0;
2322
+ const out = [];
2323
+ const min = lowerOf(TAILWIND4_MIN_AXIS_VERSION);
2324
+ for (const name of TAILWIND4_AXIS_PACKAGES) {
2325
+ const range = hasDependency(pkg, name);
2326
+ if (range === void 0 || range.trim().startsWith("workspace:")) continue;
2327
+ const installed = baseDir !== void 0 ? installedVersion(baseDir, name) : void 0;
2328
+ const installedLower = installed !== void 0 ? lowerOf(installed) : void 0;
2329
+ if (installed !== void 0 && installedLower !== void 0) {
2330
+ if (compareLower(installedLower, min) < 0) out.push({ name, range, status: "below", source: "installed", installed });
2331
+ continue;
2332
+ }
2333
+ const atLeast = rangeLowerAtLeast(range, TAILWIND4_MIN_AXIS_VERSION);
2334
+ if (atLeast === false) out.push({ name, range, status: "below", source: "declared" });
2335
+ else if (atLeast === void 0) out.push({ name, range, status: "unknown", source: "declared" });
2336
+ }
2337
+ return out;
2338
+ }
2339
+ function axisPackageVersionLabel(issue) {
2340
+ return issue.source === "installed" ? `${issue.name} \uC124\uCE58\uBCF8 ${issue.installed}` : `${issue.name} ${issue.range}`;
2341
+ }
2342
+ var declaredList = (issues) => issues.map(axisPackageVersionLabel).join(" \xB7 ");
2343
+ function tailwind4VersionNote(issues) {
2344
+ const below = issues.filter((i) => i.status === "below");
2345
+ const unknown = issues.filter((i) => i.status === "unknown");
2346
+ let note = "";
2347
+ if (below.length > 0) note += ` (${TAILWIND4_MIN_AXIS_VERSION} \uC774\uC0C1 \uD544\uC694: ${declaredList(below)})`;
2348
+ if (unknown.length > 0) note += ` (\uC124\uCE58\uB41C \uBC84\uC804\uC774 ${TAILWIND4_MIN_AXIS_VERSION} \uC774\uC0C1\uC778\uC9C0 \uD655\uC778\uD558\uC138\uC694: ${declaredList(unknown)})`;
2349
+ return note;
2350
+ }
2351
+ var TAILWIND4_COMPONENT_PACKAGES = ["@axis-ds/ui-react", "@axis-ds/agentic-ui"];
2352
+ function componentTailwindImportLine(name) {
2353
+ return `@import "${name}/tailwind.css";`;
2354
+ }
2355
+ var escapeRegExp = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
2356
+ function hasComponentTailwindImport(css, name) {
2357
+ const re = new RegExp(`@import\\s+(?:url\\(\\s*)?["']${escapeRegExp(name)}/tailwind\\.css["']`);
2358
+ return re.test(stripCssComments(css));
2359
+ }
2360
+ function hasComponentSource(css, name) {
2361
+ const re = new RegExp(`@source\\s+(["'])(?!@axis-ds/)[^"'\\n]*${escapeRegExp(name)}(?:[/\\\\][^"'\\n]*)?\\1`);
2362
+ return re.test(stripCssComments(css));
2363
+ }
2364
+ var CREATE_NEXT_APP_DEFAULTS = [
2365
+ {
2366
+ prefix: ":root \uC0C9\uAC12",
2367
+ pattern: /(?<![\w-])(--(?:background|foreground))\s*:\s*(?:#[0-9a-fA-F]{3,8}\b|(?:rgba?|hsla?|hwb|oklch|oklab|lab|lch|color)\()/g,
2368
+ item: (m) => m[1]
2369
+ },
2370
+ {
2371
+ prefix: "@theme",
2372
+ pattern: /(?<![\w-])(--color-(?:background|foreground))\s*:\s*var\(\s*(--(?:background|foreground))\s*\)/g,
2373
+ item: (m) => `${m[1]}: var(${m[2]})`
2374
+ },
2375
+ {
2376
+ prefix: "@theme",
2377
+ pattern: /(?<![\w-])(--font-(?:sans|mono))\s*:\s*var\(\s*(--font-geist-(?:sans|mono))\s*\)/g,
2378
+ item: (m) => `${m[1]}: var(${m[2]})`
2379
+ },
2380
+ {
2381
+ prefix: "body",
2382
+ pattern: /(?<![\w-])(background|background-color|color)\s*:\s*var\(\s*(--(?:background|foreground))\s*\)/g,
2383
+ item: (m) => `${m[1]}: var(${m[2]})`
2384
+ }
2385
+ ];
2386
+ function findCreateNextAppDefaults(css) {
2387
+ const body = stripCssComments(css);
2388
+ const labels = [];
2389
+ for (const d of CREATE_NEXT_APP_DEFAULTS) {
2390
+ const items = [];
2391
+ for (const m of body.matchAll(d.pattern)) {
2392
+ const item = d.item(m);
2393
+ if (!items.includes(item)) items.push(item);
2394
+ }
2395
+ if (items.length > 0) labels.push(`${d.prefix} ${items.join(", ")}`);
2396
+ }
2397
+ return labels;
2398
+ }
2399
+ function stripJsComments(src) {
2400
+ let out = "";
2401
+ let i = 0;
2402
+ const n = src.length;
2403
+ while (i < n) {
2404
+ const c = src[i];
2405
+ const d = src[i + 1];
2406
+ if (c === '"' || c === "'" || c === "`") {
2407
+ let j = i + 1;
2408
+ while (j < n && src[j] !== c) {
2409
+ if (src[j] === "\\") j++;
2410
+ else if (c !== "`" && src[j] === "\n") break;
2411
+ j++;
2412
+ }
2413
+ out += src.slice(i, j + 1);
2414
+ i = j + 1;
2415
+ continue;
2416
+ }
2417
+ if (c === "/" && d === "/") {
2418
+ const end = src.indexOf("\n", i);
2419
+ i = end === -1 ? n : end;
2420
+ continue;
2421
+ }
2422
+ if (c === "/" && d === "*") {
2423
+ const end = src.indexOf("*/", i + 2);
2424
+ i = end === -1 ? n : end + 2;
2425
+ out += " ";
2426
+ continue;
2427
+ }
2428
+ out += c;
2429
+ i++;
2430
+ }
2431
+ return out;
2432
+ }
2433
+ var TOKENS_TAILWIND3_PRESET = "@axis-ds/tokens/tailwind";
2434
+ var PRESET_REFERENCE = /(?:\brequire\s*\(\s*|\bimport\s*\(\s*|\bfrom\s*|\bimport\s+)(["'])@axis-ds\/tokens\/tailwind\1/;
2435
+ function hasTokensPresetReference(source) {
2436
+ return PRESET_REFERENCE.test(stripJsComments(source));
2437
+ }
2438
+ var PRESET_PASS_SUFFIX = `\uC5D0 AXIS \uD1A0\uD070\uC774 \uC124\uC815\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4 (${TOKENS_TAILWIND3_PRESET} preset)`;
2439
+ function readPackageJson(baseDir) {
2440
+ try {
2441
+ const parsed = JSON.parse(readFileSync2(join2(baseDir, "package.json"), "utf8"));
2442
+ return isPlainObject(parsed) ? parsed : void 0;
2443
+ } catch {
2444
+ return void 0;
2445
+ }
2446
+ }
2447
+ function tailwind4Issues(css, pkg, versions) {
2448
+ const issues = [];
2449
+ const hasEntry = hasTokensTailwind4Import(css);
2450
+ if (!hasEntry) issues.push(`AXIS \uD1A0\uD070 \uC9C4\uC785\uC810\uC774 \uC5C6\uC2B5\uB2C8\uB2E4 \u2192 ${TOKENS_TAILWIND4_IMPORT_LINE}`);
2451
+ const missing = TAILWIND4_COMPONENT_PACKAGES.filter(
2452
+ (name) => pkg !== void 0 && hasDependency(pkg, name) !== void 0 && !hasComponentTailwindImport(css, name) && !hasComponentSource(css, name)
2453
+ );
2454
+ if (missing.length > 0) {
2455
+ issues.push(`\uCEF4\uD3EC\uB10C\uD2B8 \uC2A4\uCE94 \uACBD\uB85C(tailwind.css)\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4 \u2192 ${missing.map(componentTailwindImportLine).join(" ")}`);
2456
+ }
2457
+ if (hasEntry) {
2458
+ const defaults = findCreateNextAppDefaults(css);
2459
+ if (defaults.length > 0) issues.push(`create-next-app \uAE30\uBCF8 \uC815\uC758\uAC00 \uB0A8\uC544 \uC788\uC2B5\uB2C8\uB2E4(${defaults.join(" \xB7 ")}) \u2192 \uC9C0\uC6B0\uC138\uC694`);
2460
+ if (versions.some((v) => v.name === TAILWIND4_AXIS_PACKAGES[0])) {
2461
+ issues.push(`AXIS \uD1A0\uD070 \uC9C4\uC785\uC810\uC774 \uC788\uC9C0\uB9CC ${TAILWIND4_AXIS_PACKAGES[0]} \uBC84\uC804 \uD655\uC778\uC774 \uD544\uC694\uD569\uB2C8\uB2E4`);
2462
+ }
2463
+ }
2464
+ for (const name of TAILWIND4_COMPONENT_PACKAGES) {
2465
+ if (hasComponentTailwindImport(css, name) && versions.some((v) => v.name === name)) {
2466
+ issues.push(`${name}/tailwind.css import \uAC00 \uC788\uC9C0\uB9CC ${name} \uBC84\uC804 \uD655\uC778\uC774 \uD544\uC694\uD569\uB2C8\uB2E4`);
2467
+ }
2468
+ }
2469
+ return issues;
2470
+ }
2471
+ function checkTailwindSetup(baseDirInput) {
2472
+ const baseDir = resolve2(baseDirInput);
2473
+ const pkg = readPackageJson(baseDir);
2474
+ const tailwind = detectTailwind(baseDir, pkg);
2475
+ if (tailwind.major !== void 0 && tailwind.major >= 4) {
2476
+ const label = `Tailwind ${tailwind.major}`;
2477
+ for (const candidate of TAILWIND_CSS_CANDIDATES) {
2478
+ const file = join2(baseDir, candidate);
2479
+ if (!existsSync2(file)) continue;
2480
+ const css = readFileSync2(file, "utf8");
2481
+ if (!hasTailwindImport(css)) {
2482
+ return {
2483
+ name: "tailwind.config",
2484
+ severity: "warn",
2485
+ message: `${label}: ${candidate}\uC5D0 @import "tailwindcss" \uAC00 \uC5C6\uC2B5\uB2C8\uB2E4`
2486
+ };
2487
+ }
2488
+ const versions = axisPackagesBelowTailwind4(pkg, baseDir);
2489
+ const issues = tailwind4Issues(css, pkg, versions);
2490
+ if (issues.length > 0) {
2491
+ return {
2492
+ name: "tailwind.config",
2493
+ severity: "warn",
2494
+ message: `${label}: ${candidate}\uC5D0 ${issues.join(" / ")}${tailwind4VersionNote(versions)}`
2495
+ };
2496
+ }
2497
+ return {
2498
+ name: "tailwind.config",
2499
+ severity: "pass",
2500
+ message: `${label}: ${candidate}\uC5D0 @import "tailwindcss" \uC640 AXIS \uD1A0\uD070 \uC9C4\uC785\uC810\uC774 \uC788\uC2B5\uB2C8\uB2E4`
2501
+ };
2502
+ }
2503
+ return {
2504
+ name: "tailwind.config",
2505
+ severity: "warn",
2506
+ message: `${label}: @import "tailwindcss" \uB97C \uD655\uC778\uD560 CSS \uD30C\uC77C\uC744 \uCC3E\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4`
2507
+ };
2508
+ }
2509
+ const [tsFile, ...otherFiles] = TAILWIND_CONFIG_FILES;
2510
+ const tsPath = join2(baseDir, tsFile);
2511
+ if (existsSync2(tsPath)) {
2512
+ const content = readFileSync2(tsPath, "utf8");
2513
+ const hasTokens = content.includes("--background") || content.includes("hsl(var(");
2514
+ if (hasTokens) {
2515
+ return { name: "tailwind.config", severity: "pass", message: "tailwind.config.ts\uC5D0 AXIS \uD1A0\uD070\uC774 \uC124\uC815\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4" };
2516
+ }
2517
+ if (hasTokensPresetReference(content)) {
2518
+ return { name: "tailwind.config", severity: "pass", message: `tailwind.config.ts${PRESET_PASS_SUFFIX}` };
2519
+ }
2520
+ return { name: "tailwind.config", severity: "warn", message: "tailwind.config.ts\uC5D0 AXIS \uD1A0\uD070 \uC124\uC815\uC774 \uC5C6\uC2B5\uB2C8\uB2E4" };
2521
+ }
2522
+ for (const file of otherFiles) {
2523
+ const path13 = join2(baseDir, file);
2524
+ if (existsSync2(path13)) {
2525
+ if (hasTokensPresetReference(readFileSync2(path13, "utf8"))) {
2526
+ return { name: "tailwind.config", severity: "pass", message: `${file}${PRESET_PASS_SUFFIX}` };
2527
+ }
2528
+ return { name: "tailwind.config", severity: "warn", message: `${file} \uC874\uC7AC (TypeScript \uAD8C\uC7A5)` };
2529
+ }
2530
+ }
2531
+ return { name: "tailwind.config", severity: "fail", message: "tailwind.config \uD30C\uC77C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4" };
2532
+ }
2533
+
2102
2534
  // src/template/template-check.ts
2103
2535
  var SEVERITY_ICON = {
2104
2536
  pass: chalk6.green("PASS"),
@@ -2109,8 +2541,8 @@ async function collectCheckResults(dir) {
2109
2541
  const baseDir = path8.resolve(dir || ".");
2110
2542
  const results = [];
2111
2543
  results.push(await checkFileExists(baseDir, "axis.config.json", "axis.config.json"));
2112
- results.push(await checkTailwindConfig(baseDir));
2113
- results.push(await checkGlobalsCss(baseDir));
2544
+ results.push(checkTailwindSetup(baseDir));
2545
+ results.push(checkGlobalsCss(baseDir));
2114
2546
  results.push(await checkUtils(baseDir));
2115
2547
  results.push(await checkDependencies(baseDir));
2116
2548
  const brand = checkBrand(baseDir);
@@ -2148,6 +2580,7 @@ async function runCheck(dir) {
2148
2580
  } else {
2149
2581
  console.log(chalk6.green("\n\uBAA8\uB4E0 \uAC80\uC99D\uC744 \uD1B5\uACFC\uD588\uC2B5\uB2C8\uB2E4!"));
2150
2582
  }
2583
+ return { pass: passCount, warn: warnCount, fail: failCount };
2151
2584
  }
2152
2585
  async function checkFileExists(baseDir, fileName, label) {
2153
2586
  const exists = await fs9.pathExists(path8.join(baseDir, fileName));
@@ -2157,57 +2590,6 @@ async function checkFileExists(baseDir, fileName, label) {
2157
2590
  message: exists ? `${label} \uD30C\uC77C\uC774 \uC874\uC7AC\uD569\uB2C8\uB2E4` : `${label} \uD30C\uC77C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4 \u2192 'axis init'\uC744 \uC2E4\uD589\uD558\uC138\uC694`
2158
2591
  };
2159
2592
  }
2160
- async function checkTailwindConfig(baseDir) {
2161
- const tsPath = path8.join(baseDir, "tailwind.config.ts");
2162
- const jsPath = path8.join(baseDir, "tailwind.config.js");
2163
- if (await fs9.pathExists(tsPath)) {
2164
- const content = await fs9.readFile(tsPath, "utf-8");
2165
- const hasTokens = content.includes("--background") || content.includes("hsl(var(");
2166
- return {
2167
- name: "tailwind.config",
2168
- severity: hasTokens ? "pass" : "warn",
2169
- message: hasTokens ? "tailwind.config.ts\uC5D0 AXIS \uD1A0\uD070\uC774 \uC124\uC815\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4" : "tailwind.config.ts\uC5D0 AXIS \uD1A0\uD070 \uC124\uC815\uC774 \uC5C6\uC2B5\uB2C8\uB2E4"
2170
- };
2171
- }
2172
- if (await fs9.pathExists(jsPath)) {
2173
- return {
2174
- name: "tailwind.config",
2175
- severity: "warn",
2176
- message: "tailwind.config.js \uC874\uC7AC (TypeScript \uAD8C\uC7A5)"
2177
- };
2178
- }
2179
- return {
2180
- name: "tailwind.config",
2181
- severity: "fail",
2182
- message: "tailwind.config \uD30C\uC77C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4"
2183
- };
2184
- }
2185
- async function checkGlobalsCss(baseDir) {
2186
- const candidates = [
2187
- "globals.css",
2188
- "app/globals.css",
2189
- "src/app/globals.css",
2190
- "src/globals.css",
2191
- "styles/globals.css"
2192
- ];
2193
- for (const candidate of candidates) {
2194
- const fullPath = path8.join(baseDir, candidate);
2195
- if (await fs9.pathExists(fullPath)) {
2196
- const content = await fs9.readFile(fullPath, "utf-8");
2197
- const hasTokens = content.includes("--background") && content.includes("--primary");
2198
- return {
2199
- name: "globals.css",
2200
- severity: hasTokens ? "pass" : "warn",
2201
- message: hasTokens ? `${candidate}\uC5D0 AXIS CSS \uBCC0\uC218\uAC00 \uC815\uC758\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4` : `${candidate}\uC5D0 AXIS CSS \uBCC0\uC218\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4`
2202
- };
2203
- }
2204
- }
2205
- return {
2206
- name: "globals.css",
2207
- severity: "fail",
2208
- message: "globals.css \uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4"
2209
- };
2210
- }
2211
2593
  async function checkUtils(baseDir) {
2212
2594
  const candidates = [
2213
2595
  "lib/utils.ts",
@@ -2402,7 +2784,8 @@ function registerTemplateCommand(program2) {
2402
2784
  }
2403
2785
  function registerCheckCommand(program2) {
2404
2786
  program2.command("check").description("AXIS \uD504\uB85C\uC81D\uD2B8 \uC124\uC815 \uAC80\uC99D").option("-d, --dir <path>", "\uB300\uC0C1 \uB514\uB809\uD1A0\uB9AC").action(async (options) => {
2405
- await runCheck(options.dir);
2787
+ const summary = await runCheck(options.dir);
2788
+ if (summary.fail > 0) process.exitCode = 1;
2406
2789
  });
2407
2790
  }
2408
2791
 
@@ -2411,12 +2794,12 @@ import chalk8 from "chalk";
2411
2794
  import path10 from "path";
2412
2795
 
2413
2796
  // src/theme/theme-add.ts
2414
- import { accessSync, constants, existsSync as existsSync2, readFileSync as readFileSync2, realpathSync, unlinkSync, writeFileSync } from "fs";
2797
+ import { accessSync, constants, existsSync as existsSync3, readFileSync as readFileSync3, realpathSync, unlinkSync, writeFileSync } from "fs";
2415
2798
  import path9 from "path";
2416
2799
  var TOKENS_DEPENDENCY_RANGE = `^${MIN_BRAND_TOKENS_VERSION}`;
2417
2800
  var THEME_PACKAGE = "@axis-ds/theme";
2418
2801
  function readText(file) {
2419
- return existsSync2(file) ? readFileSync2(file, "utf8") : null;
2802
+ return existsSync3(file) ? readFileSync3(file, "utf8") : null;
2420
2803
  }
2421
2804
  function eolOf(text) {
2422
2805
  return text.includes("\r\n") ? "\r\n" : "\n";
@@ -2492,12 +2875,12 @@ function isStylesheet(realPath) {
2492
2875
  return path9.extname(realPath).toLowerCase() === ".css";
2493
2876
  }
2494
2877
  function detectInstallCommand(baseDir) {
2495
- if (existsSync2(path9.join(baseDir, "pnpm-lock.yaml"))) return "pnpm install";
2496
- if (existsSync2(path9.join(baseDir, "yarn.lock"))) return "yarn install";
2497
- if (existsSync2(path9.join(baseDir, "package-lock.json"))) return "npm install";
2878
+ if (existsSync3(path9.join(baseDir, "pnpm-lock.yaml"))) return "pnpm install";
2879
+ if (existsSync3(path9.join(baseDir, "yarn.lock"))) return "yarn install";
2880
+ if (existsSync3(path9.join(baseDir, "package-lock.json"))) return "npm install";
2498
2881
  return "pnpm install";
2499
2882
  }
2500
- function hasDependency(pkg, name) {
2883
+ function hasDependency2(pkg, name) {
2501
2884
  for (const field of ["dependencies", "devDependencies"]) {
2502
2885
  const deps = pkg[field];
2503
2886
  if (typeof deps === "object" && deps !== null && name in deps) {
@@ -2506,7 +2889,7 @@ function hasDependency(pkg, name) {
2506
2889
  }
2507
2890
  return void 0;
2508
2891
  }
2509
- function isPlainObject(value) {
2892
+ function isPlainObject2(value) {
2510
2893
  return typeof value === "object" && value !== null && !Array.isArray(value);
2511
2894
  }
2512
2895
  function planThemeAdd(baseDirInput, brand) {
@@ -2531,7 +2914,7 @@ function planThemeAdd(baseDirInput, brand) {
2531
2914
  let config;
2532
2915
  try {
2533
2916
  const parsed = JSON.parse(configText);
2534
- if (!isPlainObject(parsed)) throw new Error("\uCD5C\uC0C1\uC704\uAC00 \uAC1D\uCCB4\uAC00 \uC544\uB2D9\uB2C8\uB2E4");
2917
+ if (!isPlainObject2(parsed)) throw new Error("\uCD5C\uC0C1\uC704\uAC00 \uAC1D\uCCB4\uAC00 \uC544\uB2D9\uB2C8\uB2E4");
2535
2918
  config = parsed;
2536
2919
  } catch (err) {
2537
2920
  plan.errors.push({ kind: "invalid-config", message: err.message });
@@ -2543,7 +2926,7 @@ function planThemeAdd(baseDirInput, brand) {
2543
2926
  }
2544
2927
  plan.tokens = resolveTokens(baseDir);
2545
2928
  if (plan.tokens.status === "ok" && plan.tokens.indexPath) {
2546
- const data = JSON.parse(readFileSync2(plan.tokens.indexPath, "utf8"));
2929
+ const data = JSON.parse(readFileSync3(plan.tokens.indexPath, "utf8"));
2547
2930
  const entries = Array.isArray(data.brands) ? data.brands : [];
2548
2931
  const entry = entries.find((e) => e.name === brand);
2549
2932
  if (!entry) {
@@ -2572,7 +2955,7 @@ function planThemeAdd(baseDirInput, brand) {
2572
2955
  plan.writes = [];
2573
2956
  return plan;
2574
2957
  }
2575
- const before = readFileSync2(location.path, "utf8");
2958
+ const before = readFileSync3(location.path, "utf8");
2576
2959
  const imported = findBrandImports(before);
2577
2960
  const otherBrands = [...new Set(imported.filter((n) => n !== brand))];
2578
2961
  if (imported.includes(brand)) {
@@ -2598,19 +2981,19 @@ function planThemeAdd(baseDirInput, brand) {
2598
2981
  let pkg;
2599
2982
  try {
2600
2983
  const parsed = JSON.parse(pkgText);
2601
- if (!isPlainObject(parsed)) throw new Error("\uCD5C\uC0C1\uC704\uAC00 \uAC1D\uCCB4\uAC00 \uC544\uB2D9\uB2C8\uB2E4");
2984
+ if (!isPlainObject2(parsed)) throw new Error("\uCD5C\uC0C1\uC704\uAC00 \uAC1D\uCCB4\uAC00 \uC544\uB2D9\uB2C8\uB2E4");
2602
2985
  pkg = parsed;
2603
2986
  } catch (err) {
2604
2987
  plan.errors.push({ kind: "invalid-package-json", message: err.message });
2605
2988
  plan.writes = [];
2606
2989
  return plan;
2607
2990
  }
2608
- const themeMissing = hasDependency(pkg, THEME_PACKAGE) === void 0;
2609
- const declared = hasDependency(pkg, TOKENS_PACKAGE);
2991
+ const themeMissing = hasDependency2(pkg, THEME_PACKAGE) === void 0;
2992
+ const declared = hasDependency2(pkg, TOKENS_PACKAGE);
2610
2993
  if (declared !== void 0) {
2611
2994
  plan.dependency = { action: "present", declaredRange: declared, upgrade, themeMissing };
2612
2995
  } else {
2613
- const deps = isPlainObject(pkg.dependencies) ? { ...pkg.dependencies } : {};
2996
+ const deps = isPlainObject2(pkg.dependencies) ? { ...pkg.dependencies } : {};
2614
2997
  deps[TOKENS_PACKAGE] = TOKENS_DEPENDENCY_RANGE;
2615
2998
  const next = { ...pkg, dependencies: deps };
2616
2999
  plan.dependency = { action: "add", upgrade, themeMissing };
@@ -2990,7 +3373,7 @@ import chalk10 from "chalk";
2990
3373
  import prompts2 from "prompts";
2991
3374
 
2992
3375
  // src/init/init.ts
2993
- import { accessSync as accessSync2, constants as constants2, existsSync as existsSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
3376
+ import { accessSync as accessSync2, constants as constants2, existsSync as existsSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync2 } from "fs";
2994
3377
  import path11 from "path";
2995
3378
  import chalk9 from "chalk";
2996
3379
  import fs10 from "fs-extra";
@@ -2999,98 +3382,6 @@ var TAILWIND_MERGE_RANGES = {
2999
3382
  tailwind4: "^3.4.0",
3000
3383
  tailwind3: "^2.6.0"
3001
3384
  };
3002
- var VERSION = String.raw`v?(\d+)(?:\.(\d+|[xX*]))?(?:\.(\d+|[xX*]))?(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?`;
3003
- function versionParts(token) {
3004
- const m = new RegExp(`^${VERSION}$`).exec(token);
3005
- if (!m) return void 0;
3006
- if (/^v?0\.0\.0-/.test(token)) return void 0;
3007
- return { major: Number(m[1]), minor: m[2], patch: m[3] };
3008
- }
3009
- var isWild = (part) => part === void 0 || /^[xX*]$/.test(part);
3010
- function comparatorBounds(op, v) {
3011
- switch (op) {
3012
- case ">=":
3013
- return { lower: v.major };
3014
- case ">":
3015
- return { lower: isWild(v.minor) ? v.major + 1 : v.major };
3016
- case "<=":
3017
- return { upper: v.major };
3018
- case "<": {
3019
- const zeroOrWild = (part) => isWild(part) || Number(part) === 0;
3020
- return { upper: zeroOrWild(v.minor) && zeroOrWild(v.patch) ? v.major - 1 : v.major };
3021
- }
3022
- default:
3023
- return { lower: v.major, upper: v.major };
3024
- }
3025
- }
3026
- function tailwindMajorBounds(range) {
3027
- const r = range.trim();
3028
- if (r === "" || r.includes("||")) return void 0;
3029
- const simple = new RegExp(`^(?:\\^|~|=)?\\s*(${VERSION})$`).exec(r);
3030
- if (simple) {
3031
- const v = versionParts(simple[1]);
3032
- return v ? { lower: v.major, upper: v.major } : void 0;
3033
- }
3034
- const hyphen = new RegExp(`^(${VERSION})\\s+-\\s+(${VERSION})$`).exec(r);
3035
- if (hyphen) {
3036
- const tokens2 = r.split(/\s+-\s+/);
3037
- const a = versionParts(tokens2[0]);
3038
- const b = versionParts(tokens2[1]);
3039
- return a && b && a.major <= b.major ? { lower: a.major, upper: b.major } : void 0;
3040
- }
3041
- const tokens = r.replace(/(>=|<=|>|<|=)\s+/g, "$1").split(/\s+/);
3042
- const lowers = [];
3043
- const uppers = [];
3044
- for (const t of tokens) {
3045
- const c = /^(>=|<=|>|<|=)(.+)$/.exec(t);
3046
- if (!c) return void 0;
3047
- const v = versionParts(c[2]);
3048
- if (v === void 0) return void 0;
3049
- const b = comparatorBounds(c[1], v);
3050
- if (b.lower !== void 0) lowers.push(b.lower);
3051
- if (b.upper !== void 0) uppers.push(b.upper);
3052
- }
3053
- if (lowers.length === 0) return void 0;
3054
- const lower = Math.max(...lowers);
3055
- const upper = uppers.length > 0 ? Math.min(...uppers) : void 0;
3056
- if (upper !== void 0 && upper < lower) return void 0;
3057
- return upper !== void 0 ? { lower, upper } : { lower };
3058
- }
3059
- function majorWithin(major, bounds) {
3060
- return major >= bounds.lower && (bounds.upper === void 0 || major <= bounds.upper);
3061
- }
3062
- function majorFromVersion(version) {
3063
- if (typeof version !== "string") return void 0;
3064
- const v = version.trim();
3065
- const m = /^v?(\d+)\.\d+\.\d+(?:[-+][0-9A-Za-z.+-]*)?$/.exec(v);
3066
- if (!m || /^v?0\.0\.0-/.test(v)) return void 0;
3067
- return Number(m[1]);
3068
- }
3069
- function detectTailwind(baseDirInput, pkg) {
3070
- const baseDir = path11.resolve(baseDirInput);
3071
- const installedFile = path11.join(baseDir, "node_modules", "tailwindcss", "package.json");
3072
- const declared = pkg ? hasDependency(pkg, "tailwindcss") : void 0;
3073
- const bounds = declared !== void 0 ? tailwindMajorBounds(declared) : void 0;
3074
- const declaredMajor = bounds?.lower;
3075
- try {
3076
- const installed = JSON.parse(readFileSync3(installedFile, "utf8"));
3077
- const version = isPlainObject(installed) ? installed.version : void 0;
3078
- const major = majorFromVersion(version);
3079
- if (major !== void 0) {
3080
- const found = { major, source: "installed", value: String(version) };
3081
- if (declared !== void 0 && bounds !== void 0 && !majorWithin(major, bounds)) {
3082
- found.mismatch = { declared, declaredMajor: bounds.lower };
3083
- }
3084
- return found;
3085
- }
3086
- } catch {
3087
- }
3088
- if (declared !== void 0) {
3089
- if (declaredMajor !== void 0) return { major: declaredMajor, source: "declared", value: declared };
3090
- return { source: "none", value: declared };
3091
- }
3092
- return { source: "none" };
3093
- }
3094
3385
  function selectUtilsDependencies(tailwind) {
3095
3386
  return {
3096
3387
  clsx: CLSX_RANGE,
@@ -3132,6 +3423,70 @@ var INIT_DEFAULTS = {
3132
3423
  globalCss: "./src/app/globals.css"
3133
3424
  };
3134
3425
  var INIT_NEXT_STEP_COMMAND = "npx @axis-ds/cli add button";
3426
+ function isTailwind4(tailwind) {
3427
+ return tailwind.major !== void 0 && tailwind.major >= 4;
3428
+ }
3429
+ var TAILWIND4_TOKENS_VERSION = TAILWIND4_MIN_AXIS_VERSION;
3430
+ var TAILWIND4_CONFLICT_LINE = " ! create-next-app \uAE30\uBCF8 globals.css \uC758 :root \xB7 @theme inline \xB7 @media (prefers-color-scheme: dark) \xB7 body \uBE14\uB85D\uC740 AXIS \uC640 \uAC19\uC740 \uC774\uB984(--background \xB7 --foreground \xB7 --color-background \xB7 --font-sans \xB7 --font-mono)\uC744 \uB2E4\uB978 \uAC12\uC73C\uB85C \uC815\uC758\uD569\uB2C8\uB2E4. \uC774 \uBE14\uB85D\uB4E4\uC744 \uC9C0\uC6B0\uC138\uC694.";
3431
+ function readPackageJsonSafe(baseDir) {
3432
+ try {
3433
+ const text = readFileSync4(path11.join(baseDir, "package.json"), "utf8");
3434
+ const parsed = JSON.parse(text.startsWith(BOM) ? text.slice(1) : text);
3435
+ return isPlainObject2(parsed) ? parsed : void 0;
3436
+ } catch {
3437
+ return void 0;
3438
+ }
3439
+ }
3440
+ function tailwind4GuideLines(pkg, installCommand, globalCss, baseDir) {
3441
+ const used = TAILWIND4_COMPONENT_PACKAGES.filter((name) => pkg !== void 0 && hasDependency2(pkg, name) !== void 0);
3442
+ const lines = [
3443
+ `Tailwind 4: \uC804\uC5ED CSS(${globalCss}) \uB9E8 \uC704\uC5D0 \uB2E4\uC74C \uC904\uC744 \uB123\uC73C\uC138\uC694(\uD30C\uC77C\uC740 \uACE0\uCE58\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4).`,
3444
+ ' @import "tailwindcss";',
3445
+ ` ${TOKENS_TAILWIND4_IMPORT_LINE}`,
3446
+ ...used.map((name) => ` ${componentTailwindImportLine(name)}`)
3447
+ ];
3448
+ if (used.length === 0) {
3449
+ lines.push(
3450
+ ` npm \uD328\uD0A4\uC9C0 \uCEF4\uD3EC\uB10C\uD2B8\uB97C \uC4F0\uBA74 \uADF8 \uD328\uD0A4\uC9C0\uC758 tailwind.css \uB3C4 \uB123\uC73C\uC138\uC694(\uC608: @import "${TAILWIND4_COMPONENT_PACKAGES[0]}/tailwind.css";).`
3451
+ );
3452
+ }
3453
+ lines.push(TAILWIND4_CONFLICT_LINE);
3454
+ if (pkg === void 0 || hasDependency2(pkg, TOKENS_PACKAGE) === void 0) {
3455
+ const add = addCommandFor(installCommand, { [TOKENS_PACKAGE]: `^${TAILWIND4_TOKENS_VERSION}` });
3456
+ lines.push(` ${TOKENS_PACKAGE} \uC124\uCE58: ${add}`);
3457
+ }
3458
+ const versions = axisPackagesBelowTailwind4(pkg, baseDir);
3459
+ const unknown = versions.filter((v) => v.status === "unknown");
3460
+ const declaredOf = (list) => list.map(axisPackageVersionLabel).join(" \xB7 ");
3461
+ const upgradeOf = (list) => addCommandFor(installCommand, Object.fromEntries(list.map((b) => [b.name, `^${TAILWIND4_MIN_AXIS_VERSION}`])));
3462
+ const belowDeclared = versions.filter((v) => v.status === "below" && v.source === "declared");
3463
+ const readableRange = (v) => rangeLowerAtLeast(v.range, TAILWIND4_MIN_AXIS_VERSION) !== void 0;
3464
+ const installedBelow = versions.filter((v) => v.status === "below" && v.source === "installed");
3465
+ const belowInstalled = installedBelow.filter(readableRange);
3466
+ const belowInstalledOpaque = installedBelow.filter((v) => !readableRange(v));
3467
+ const installedOf = (list) => list.map((v) => `${v.name} ${v.installed}, \uC120\uC5B8 ${v.range}`).join(" \xB7 ");
3468
+ if (belowDeclared.length > 0) {
3469
+ lines.push(
3470
+ ` ! Tailwind 4 \uC9C4\uC785\uC810\uC740 ${TAILWIND4_MIN_AXIS_VERSION} \uBD80\uD130 \uC788\uC2B5\uB2C8\uB2E4. \uC120\uC5B8(${declaredOf(belowDeclared)})\uC744 \uC62C\uB9AC\uC138\uC694: ${upgradeOf(belowDeclared)}`
3471
+ );
3472
+ }
3473
+ if (belowInstalled.length > 0) {
3474
+ lines.push(
3475
+ ` ! Tailwind 4 \uC9C4\uC785\uC810\uC740 ${TAILWIND4_MIN_AXIS_VERSION} \uBD80\uD130 \uC788\uC2B5\uB2C8\uB2E4. \uC124\uCE58\uBCF8(${installedOf(belowInstalled)})\uC744 \uC62C\uB9AC\uC138\uC694: ${upgradeOf(belowInstalled)}`
3476
+ );
3477
+ }
3478
+ if (belowInstalledOpaque.length > 0) {
3479
+ lines.push(
3480
+ ` ! Tailwind 4 \uC9C4\uC785\uC810\uC740 ${TAILWIND4_MIN_AXIS_VERSION} \uBD80\uD130 \uC788\uC2B5\uB2C8\uB2E4. \uC124\uCE58\uBCF8(${installedOf(belowInstalledOpaque)})\uC774 ${TAILWIND4_MIN_AXIS_VERSION} \uBBF8\uB9CC\uC785\uB2C8\uB2E4. \uC120\uC5B8\uC774 \uAC00\uB9AC\uD0A4\uB294 \uBC84\uC804\uC744 ${TAILWIND4_MIN_AXIS_VERSION} \uC774\uC0C1\uC73C\uB85C \uC62C\uB9B0 \uB4A4 \uB2E4\uC2DC \uC124\uCE58\uD558\uC138\uC694(\uC120\uC5B8\uC740 \uB36E\uC5B4\uC4F0\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4).`
3481
+ );
3482
+ }
3483
+ if (unknown.length > 0) {
3484
+ lines.push(
3485
+ ` ! Tailwind 4 \uC9C4\uC785\uC810\uC740 ${TAILWIND4_MIN_AXIS_VERSION} \uBD80\uD130 \uC788\uC2B5\uB2C8\uB2E4. \uC120\uC5B8(${declaredOf(unknown)})\uC73C\uB85C\uB294 \uBC84\uC804\uC744 \uD310\uC815\uD560 \uC218 \uC5C6\uC73C\uB2C8 \uC124\uCE58\uB41C \uBC84\uC804\uC774 ${TAILWIND4_MIN_AXIS_VERSION} \uC774\uC0C1\uC778\uC9C0 \uD655\uC778\uD558\uC138\uC694.`
3486
+ );
3487
+ }
3488
+ return lines;
3489
+ }
3135
3490
  var BOM = "\uFEFF";
3136
3491
  function addCommandFor(installCommand, deps) {
3137
3492
  const specs = Object.entries(deps).map(([name, range]) => `"${name}@${range}"`).join(" ");
@@ -3154,7 +3509,7 @@ function planUtilsDependencies(baseDirInput) {
3154
3509
  addCommand: addCommandFor(installCommand, ranges0)
3155
3510
  };
3156
3511
  const pkgFile = path11.join(baseDir, "package.json");
3157
- if (!existsSync3(pkgFile)) return plan;
3512
+ if (!existsSync4(pkgFile)) return plan;
3158
3513
  const unwritable = (reason) => ({ ...plan, action: "unwritable", reason });
3159
3514
  let where;
3160
3515
  try {
@@ -3165,7 +3520,7 @@ function planUtilsDependencies(baseDirInput) {
3165
3520
  if (!where.inside) return unwritable(`\uC2E4\uC81C \uC704\uCE58(${where.realPath})\uAC00 \uD504\uB85C\uC81D\uD2B8 \uB514\uB809\uD130\uB9AC \uBC16\uC785\uB2C8\uB2E4`);
3166
3521
  let text;
3167
3522
  try {
3168
- text = readFileSync3(pkgFile, "utf8");
3523
+ text = readFileSync4(pkgFile, "utf8");
3169
3524
  } catch (err) {
3170
3525
  return unwritable(err.message);
3171
3526
  }
@@ -3174,7 +3529,7 @@ function planUtilsDependencies(baseDirInput) {
3174
3529
  let pkg;
3175
3530
  try {
3176
3531
  const parsed = JSON.parse(body);
3177
- if (!isPlainObject(parsed)) throw new Error("\uCD5C\uC0C1\uC704\uAC00 \uAC1D\uCCB4\uAC00 \uC544\uB2D9\uB2C8\uB2E4");
3532
+ if (!isPlainObject2(parsed)) throw new Error("\uCD5C\uC0C1\uC704\uAC00 \uAC1D\uCCB4\uAC00 \uC544\uB2D9\uB2C8\uB2E4");
3178
3533
  pkg = parsed;
3179
3534
  } catch (err) {
3180
3535
  return unwritable(`JSON \uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${err.message}`);
@@ -3184,14 +3539,14 @@ function planUtilsDependencies(baseDirInput) {
3184
3539
  plan.addCommand = addCommandFor(installCommand, plan.ranges);
3185
3540
  const missing = {};
3186
3541
  for (const [name, range] of Object.entries(plan.ranges)) {
3187
- const declared = hasDependency(pkg, name);
3542
+ const declared = hasDependency2(pkg, name);
3188
3543
  if (declared !== void 0) plan.present.push({ name, range: declared });
3189
3544
  else missing[name] = range;
3190
3545
  }
3191
3546
  plan.added = Object.keys(missing);
3192
3547
  plan.addCommand = addCommandFor(installCommand, plan.added.length > 0 ? missing : plan.ranges);
3193
3548
  if (plan.added.length === 0) return { ...plan, action: "present" };
3194
- if (pkg.dependencies !== void 0 && !isPlainObject(pkg.dependencies)) {
3549
+ if (pkg.dependencies !== void 0 && !isPlainObject2(pkg.dependencies)) {
3195
3550
  return unwritable("dependencies \uAC00 \uAC1D\uCCB4\uAC00 \uC544\uB2D9\uB2C8\uB2E4");
3196
3551
  }
3197
3552
  try {
@@ -3208,7 +3563,7 @@ function applyUtilsDependencies(baseDirInput, plan, writeFile = defaultWriteFile
3208
3563
  const w = plan.write;
3209
3564
  if (plan.action !== "add" || !w) return false;
3210
3565
  const baseDir = path11.resolve(baseDirInput);
3211
- const current = existsSync3(w.file) ? readFileSync3(w.file, "utf8") : null;
3566
+ const current = existsSync4(w.file) ? readFileSync4(w.file, "utf8") : null;
3212
3567
  if (current !== w.before) {
3213
3568
  throw new Error(`${w.file} \uC774 \uACC4\uD68D \uB4A4\uC5D0 \uBC14\uB00C\uC5C8\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694.`);
3214
3569
  }
@@ -3224,7 +3579,7 @@ function applyUtilsDependencies(baseDirInput, plan, writeFile = defaultWriteFile
3224
3579
  let restored;
3225
3580
  try {
3226
3581
  writeFile(w.file, w.before);
3227
- if (readFileSync3(w.file, "utf8") !== w.before) throw new Error("\uB418\uB3CC\uB9B0 \uB0B4\uC6A9\uC774 \uC6D0\uB798 \uB0B4\uC6A9\uACFC \uB2E4\uB985\uB2C8\uB2E4");
3582
+ if (readFileSync4(w.file, "utf8") !== w.before) throw new Error("\uB418\uB3CC\uB9B0 \uB0B4\uC6A9\uC774 \uC6D0\uB798 \uB0B4\uC6A9\uACFC \uB2E4\uB985\uB2C8\uB2E4");
3228
3583
  restored = "\uC6D0\uB798 \uB0B4\uC6A9\uC73C\uB85C \uB418\uB3CC\uB838\uC2B5\uB2C8\uB2E4";
3229
3584
  } catch (restoreErr) {
3230
3585
  restored = `\uC6D0\uB798 \uB0B4\uC6A9\uC73C\uB85C \uB418\uB3CC\uB9AC\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4(${restoreErr.message}). \uD30C\uC77C\uC774 \uC798\uB838\uAC70\uB098 \uBE44\uC5C8\uC744 \uC218 \uC788\uC73C\uB2C8 \uBC84\uC804 \uAD00\uB9AC \uB3C4\uAD6C \uB4F1\uC73C\uB85C \uBCF5\uAD6C\uD558\uC138\uC694`;
@@ -3261,10 +3616,12 @@ function reportDependencies(plan, log) {
3261
3616
  }
3262
3617
  async function runInit(baseDirInput, answers, registryUrl, log = console.log) {
3263
3618
  const baseDir = path11.resolve(baseDirInput);
3619
+ const plan = planUtilsDependencies(baseDir);
3620
+ const tailwind4 = isTailwind4(plan.tailwind);
3264
3621
  const axisConfig = createInitConfig(
3265
3622
  {
3266
3623
  componentsDir: answers.componentsDir,
3267
- tailwindConfig: answers.tailwindConfig,
3624
+ tailwindConfig: tailwind4 ? void 0 : answers.tailwindConfig,
3268
3625
  globalCss: answers.globalCss
3269
3626
  },
3270
3627
  registryUrl
@@ -3275,7 +3632,6 @@ async function runInit(baseDirInput, answers, registryUrl, log = console.log) {
3275
3632
  await fs10.ensureDir(path11.dirname(utilsPath));
3276
3633
  await fs10.writeFile(utilsPath, UTILS_TS_CONTENT);
3277
3634
  log(chalk9.green("\u2713 utils.ts \uC0DD\uC131 \uC644\uB8CC"));
3278
- const plan = planUtilsDependencies(baseDir);
3279
3635
  try {
3280
3636
  applyUtilsDependencies(baseDir, plan);
3281
3637
  } catch (err) {
@@ -3286,6 +3642,17 @@ async function runInit(baseDirInput, answers, registryUrl, log = console.log) {
3286
3642
  return;
3287
3643
  }
3288
3644
  reportDependencies(plan, log);
3645
+ if (tailwind4) {
3646
+ const [head, ...rest] = tailwind4GuideLines(
3647
+ readPackageJsonSafe(baseDir),
3648
+ plan.installCommand,
3649
+ answers.globalCss,
3650
+ baseDir
3651
+ );
3652
+ log(chalk9.blue(`
3653
+ ${head}`));
3654
+ for (const line of rest) log(line.startsWith(" !") ? chalk9.yellow(line) : chalk9.cyan(line));
3655
+ }
3289
3656
  log(chalk9.blue("\n\uCD08\uAE30\uD654 \uC644\uB8CC! \uC774\uC81C \uB2E4\uC74C \uBA85\uB839\uC5B4\uB85C \uCEF4\uD3EC\uB10C\uD2B8\uB97C \uCD94\uAC00\uD558\uC138\uC694:"));
3290
3657
  log(chalk9.cyan(` ${INIT_NEXT_STEP_COMMAND}
3291
3658
  `));
@@ -3295,6 +3662,7 @@ async function runInit(baseDirInput, answers, registryUrl, log = console.log) {
3295
3662
  function registerInitCommand(program2, registryUrl) {
3296
3663
  program2.command("init").description("\uD504\uB85C\uC81D\uD2B8\uC5D0 AXIS Design System \uCD08\uAE30\uD654").option("-y, --yes", "\uAE30\uBCF8\uAC12\uC73C\uB85C \uC790\uB3D9 \uC124\uC815").action(async (options) => {
3297
3664
  console.log(chalk10.blue("\n\u{1F3A8} AXIS Design System \uCD08\uAE30\uD654\n"));
3665
+ const tailwind4 = isTailwind4(planUtilsDependencies(process.cwd()).tailwind);
3298
3666
  const config = options.yes ? { ...INIT_DEFAULTS } : await prompts2([
3299
3667
  {
3300
3668
  type: "text",
@@ -3303,7 +3671,7 @@ function registerInitCommand(program2, registryUrl) {
3303
3671
  initial: INIT_DEFAULTS.componentsDir
3304
3672
  },
3305
3673
  {
3306
- type: "text",
3674
+ type: tailwind4 ? null : "text",
3307
3675
  name: "tailwindConfig",
3308
3676
  message: "Tailwind \uC124\uC815 \uD30C\uC77C:",
3309
3677
  initial: INIT_DEFAULTS.tailwindConfig
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axis-ds/cli",
3
- "version": "1.2.1",
3
+ "version": "1.4.0",
4
4
  "type": "module",
5
5
  "description": "AXIS Design System - CLI for adding components (shadcn compatible)",
6
6
  "publishConfig": {