@axis-ds/cli 1.6.0 → 1.6.2

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/dist/index.js CHANGED
@@ -1106,17 +1106,59 @@ function toSearchItem(c) {
1106
1106
  url: `/library/${c.category}/${c.slug}`
1107
1107
  };
1108
1108
  }
1109
+ var sourceTypeOf = (item) => typeof item.source === "string" ? item.source : item.source.type;
1110
+ function resolveRouteSlugs(items) {
1111
+ const groups = /* @__PURE__ */ new Map();
1112
+ for (const item of items) {
1113
+ const key = `${item.category}/${item.slug}`;
1114
+ if (!groups.has(key)) groups.set(key, []);
1115
+ groups.get(key).push(item);
1116
+ }
1117
+ const result = /* @__PURE__ */ new Map();
1118
+ for (const [key, group] of groups) {
1119
+ if (group.length === 1) {
1120
+ result.set(group[0].id, group[0].slug);
1121
+ continue;
1122
+ }
1123
+ const axis = group.filter((i) => sourceTypeOf(i) === "axis");
1124
+ if (axis.length > 1) {
1125
+ throw new Error(`\uC0C1\uC138 \uC8FC\uC18C /library/${key} \uB97C AXIS \uD56D\uBAA9 ${axis.map((i) => i.id).join(", ")} \uAC00 \uD568\uAED8 \uC501\uB2C8\uB2E4`);
1126
+ }
1127
+ const keeper = axis[0] || group[0];
1128
+ for (const item of group) {
1129
+ result.set(item.id, item === keeper ? item.slug : `${sourceTypeOf(item)}-${item.slug}`);
1130
+ }
1131
+ }
1132
+ const seen = /* @__PURE__ */ new Map();
1133
+ for (const item of items) {
1134
+ const key = `${item.category}/${result.get(item.id)}`;
1135
+ const other = seen.get(key);
1136
+ if (other !== void 0 && other !== item.id) {
1137
+ throw new Error(`slug \uB97C \uBC14\uAFBC \uB4A4\uC5D0\uB3C4 \uC0C1\uC138 \uC8FC\uC18C /library/${key} \uAC00 ${other}, ${item.id} \uC5D0\uC11C \uACB9\uCE69\uB2C8\uB2E4`);
1138
+ }
1139
+ seen.set(key, item.id);
1140
+ }
1141
+ return result;
1142
+ }
1143
+ function withRouteSlugs(items) {
1144
+ const slugs = resolveRouteSlugs(items);
1145
+ return items.map((item) => slugs.get(item.id) === item.slug ? item : { ...item, slug: slugs.get(item.id) });
1146
+ }
1147
+ function componentFileOf(item) {
1148
+ return `components/${item.id}.json`;
1149
+ }
1109
1150
  var Publisher = class {
1110
1151
  defaultOutputDir = "apps/web/public/library";
1111
1152
  /**
1112
1153
  * 라이브러리 인덱스를 사이트에 배치
1113
1154
  */
1114
- async publish(index, options = {}) {
1155
+ async publish(input, options = {}) {
1115
1156
  const outputDir = options.outputDir || this.defaultOutputDir;
1116
1157
  const files = [];
1117
1158
  const errors = [];
1118
1159
  const spinner = ora("\uB77C\uC774\uBE0C\uB7EC\uB9AC \uBC30\uCE58 \uC911...").start();
1119
1160
  try {
1161
+ const index = { ...input, components: withRouteSlugs(input.components) };
1120
1162
  await fs3.ensureDir(outputDir);
1121
1163
  const indexPath = path3.join(outputDir, "index.json");
1122
1164
  await this.writeJson(indexPath, this.createPublicIndex(index), options.minify);
@@ -1143,7 +1185,7 @@ var Publisher = class {
1143
1185
  const componentsDir = path3.join(outputDir, "components");
1144
1186
  await fs3.ensureDir(componentsDir);
1145
1187
  for (const component of index.components) {
1146
- const componentPath = path3.join(componentsDir, `${component.slug}.json`);
1188
+ const componentPath = path3.join(outputDir, componentFileOf(component));
1147
1189
  await this.writeJson(componentPath, this.createPublicComponent(component), options.minify);
1148
1190
  files.push(componentPath);
1149
1191
  }
@@ -1400,6 +1442,25 @@ async function refreshAxisLibrary(options) {
1400
1442
  }
1401
1443
  for (const f of existingFiles.values()) if (f.data.source?.type === AXIS) oldAxisIds.add(f.data.id);
1402
1444
  const removed = [...oldAxisIds].filter((id) => !axisIds.has(id)).sort();
1445
+ const routeSlugs = resolveRouteSlugs([...extOrder.map((id) => extCategory.get(id)), ...axisComponents]);
1446
+ const renamedSlugs = {};
1447
+ const renamedFrom = {};
1448
+ for (const id of extOrder) {
1449
+ const slug = routeSlugs.get(id);
1450
+ const full = extCategory.get(id);
1451
+ if (slug === full.slug) continue;
1452
+ renamedSlugs[id] = slug;
1453
+ renamedFrom[id] = full.slug;
1454
+ extCategory.set(id, { ...full, slug });
1455
+ extIndex.set(id, { ...extIndex.get(id), slug });
1456
+ const s = extSearch.get(id);
1457
+ extSearch.set(id, { ...s, slug, url: `/library/${s.category}/${slug}` });
1458
+ }
1459
+ for (const c of axisComponents) {
1460
+ const slug = routeSlugs.get(c.id);
1461
+ if (slug === c.slug) continue;
1462
+ throw new Error(`AXIS \uD56D\uBAA9 ${c.id} \uC758 slug \uAC00 ${slug} \uB85C \uBC14\uB00C\uC5B4\uC57C \uD569\uB2C8\uB2E4. \uC218\uC9D1 \uACB0\uACFC\uB97C \uD655\uC778\uD558\uC138\uC694`);
1463
+ }
1403
1464
  const indexEntries = [
1404
1465
  ...extOrder.map((id) => extIndex.get(id)),
1405
1466
  ...axisComponents.map((c) => toIndexEntry(c))
@@ -1457,24 +1518,18 @@ async function refreshAxisLibrary(options) {
1457
1518
  })
1458
1519
  );
1459
1520
  }
1460
- const finalSlugs = /* @__PURE__ */ new Set();
1461
- const axisBySlug = new Map(axisComponents.map((c) => [c.slug, c]));
1462
- for (const c of allPublic) finalSlugs.add(c.slug);
1463
- const shadowedAxis = [];
1464
- for (const slug of [...finalSlugs].sort()) {
1465
- const axis = axisBySlug.get(slug);
1466
- const existing = existingFiles.get(slug);
1467
- const extForSlug = extOrder.map((id) => extCategory.get(id)).filter((c) => c.slug === slug);
1468
- const existingIsExternal = !!existing && extForSlug.some((c) => c.id === existing.data.id);
1469
- if (existingIsExternal) {
1470
- if (axis) shadowedAxis.push(axis.id);
1471
- continue;
1472
- }
1473
- if (axis) {
1474
- outputs.set(`components/${slug}.json`, serialize(axis));
1521
+ const finalFiles = /* @__PURE__ */ new Set();
1522
+ for (const c of allPublic) {
1523
+ const rel3 = componentFileOf(c);
1524
+ finalFiles.add(rel3);
1525
+ if (c.source.type === AXIS) {
1526
+ outputs.set(rel3, serialize(c));
1475
1527
  continue;
1476
1528
  }
1477
- outputs.set(`components/${slug}.json`, serialize(extForSlug[0]));
1529
+ const same = (f) => f.data?.id === c.id && isDeepStrictEqual(f.data, c);
1530
+ const atKey = existingFiles.get(c.id);
1531
+ const kept = atKey && same(atKey) ? atKey : [...existingFiles.values()].find(same);
1532
+ outputs.set(rel3, kept ? kept.raw : serialize(c));
1478
1533
  }
1479
1534
  const writtenFiles = [];
1480
1535
  for (const [rel3, content] of outputs) {
@@ -1485,13 +1540,13 @@ async function refreshAxisLibrary(options) {
1485
1540
  if (!options.dryRun) await fs4.writeFile(file, content, "utf-8");
1486
1541
  }
1487
1542
  const removedFiles = [];
1488
- for (const slug of existingFiles.keys()) {
1489
- if (finalSlugs.has(slug)) continue;
1490
- const rel3 = `components/${slug}.json`;
1543
+ for (const key of existingFiles.keys()) {
1544
+ const rel3 = `components/${key}.json`;
1545
+ if (finalFiles.has(rel3)) continue;
1491
1546
  removedFiles.push(rel3);
1492
1547
  if (!options.dryRun) await fs4.remove(path4.join(libraryDir, rel3));
1493
1548
  }
1494
- return { added, changed, unchanged, removed, shadowedAxis, writtenFiles, removedFiles, stats };
1549
+ return { added, changed, unchanged, removed, renamedSlugs, renamedFrom, writtenFiles, removedFiles, stats };
1495
1550
  }
1496
1551
  function registerRefreshAxisCommand(libraryCmd2) {
1497
1552
  libraryCmd2.command("refresh-axis").description("AXIS \uD56D\uBAA9\uB9CC \uC800\uC7A5\uC18C \uC18C\uC2A4\uC5D0\uC11C \uB2E4\uC2DC \uB9CC\uB4E6 (\uC678\uBD80 \uC18C\uC2A4 \uD56D\uBAA9\uC740 \uADF8\uB300\uB85C, \uB124\uD2B8\uC6CC\uD06C \uC5C6\uC74C)").option("--root <dir>", "\uC800\uC7A5\uC18C \uB8E8\uD2B8", process.cwd()).option("-o, --output <dir>", "library \uB514\uB809\uD130\uB9AC (\uB8E8\uD2B8 \uAE30\uC900)", "apps/web/public/library").option("--updated-at <iso>", "\uBC14\uB010 \uD56D\uBAA9\uC5D0 \uAE30\uB85D\uD560 \uC2DC\uAC01 (\uAE30\uBCF8: \uC624\uB298 KST \uB0A0\uC9DC\uC758 00:00:00.000Z)").option("--dry-run", "\uD30C\uC77C\uC744 \uC4F0\uC9C0 \uC54A\uACE0 \uBC14\uB014 \uB0B4\uC6A9\uB9CC \uCD9C\uB825").action(async (opts) => {
@@ -1511,9 +1566,12 @@ ${head}AXIS library \uC7AC\uC0DD\uC131`));
1511
1566
  for (const id of result.added) console.log(chalk2.green(` + ${id}`));
1512
1567
  for (const id of result.changed) console.log(chalk2.yellow(` ~ ${id}`));
1513
1568
  for (const id of result.removed) console.log(chalk2.red(` - ${id}`));
1514
- if (result.shadowedAxis.length > 0) {
1569
+ const renamed = Object.entries(result.renamedSlugs);
1570
+ if (renamed.length > 0) {
1515
1571
  console.log(
1516
- chalk2.yellow(` slug \uAC00 \uC678\uBD80 \uD56D\uBAA9 \uD30C\uC77C\uACFC \uACB9\uCCD0 \uD30C\uC77C\uC744 \uC4F0\uC9C0 \uC54A\uC74C(E4): ${result.shadowedAxis.join(", ")}`)
1572
+ chalk2.yellow(
1573
+ ` \uC0C1\uC138 \uC8FC\uC18C\uAC00 \uACB9\uCCD0 slug \uB97C \uBC14\uAFC8(WI-0060): ${renamed.map(([id, slug]) => `${id}: ${result.renamedFrom[id] ?? id} \u2192 ${slug}`).join(", ")}`
1574
+ )
1517
1575
  );
1518
1576
  }
1519
1577
  console.log(` \uD30C\uC77C \uC4F0\uAE30 ${result.writtenFiles.length}\uAC1C \xB7 \uC0AD\uC81C ${result.removedFiles.length}\uAC1C`);
@@ -1745,7 +1803,7 @@ import ora5 from "ora";
1745
1803
 
1746
1804
  // src/template/template-apply.ts
1747
1805
  import fs8 from "fs-extra";
1748
- import path8 from "path";
1806
+ import path9 from "path";
1749
1807
  import chalk5 from "chalk";
1750
1808
  import ora3 from "ora";
1751
1809
  import prompts from "prompts";
@@ -1843,8 +1901,18 @@ async function readAxisConfig(baseDir) {
1843
1901
  }
1844
1902
 
1845
1903
  // ../axis-registry-core/src/template/tailwind-core.ts
1846
- import { existsSync, lstatSync, readdirSync, readFileSync } from "fs";
1847
- import { join, resolve } from "path";
1904
+ import { existsSync as existsSync2, lstatSync, readdirSync, readFileSync as readFileSync2 } from "fs";
1905
+ import { extname, join, resolve } from "path";
1906
+
1907
+ // ../axis-registry-core/src/project.ts
1908
+ import { existsSync, readFileSync, statSync } from "fs";
1909
+ import path8 from "path";
1910
+ function detectInstallCommand(baseDir) {
1911
+ if (existsSync(path8.join(baseDir, "pnpm-lock.yaml"))) return "pnpm install";
1912
+ if (existsSync(path8.join(baseDir, "yarn.lock"))) return "yarn install";
1913
+ if (existsSync(path8.join(baseDir, "package-lock.json"))) return "npm install";
1914
+ return "pnpm install";
1915
+ }
1848
1916
  function hasDependency(pkg, name) {
1849
1917
  for (const field of ["dependencies", "devDependencies"]) {
1850
1918
  const deps = pkg[field];
@@ -1857,6 +1925,134 @@ function hasDependency(pkg, name) {
1857
1925
  function isPlainObject(value) {
1858
1926
  return typeof value === "object" && value !== null && !Array.isArray(value);
1859
1927
  }
1928
+ function addCommandFor(installCommand, deps) {
1929
+ const specs = Object.entries(deps).map(([name, range]) => `"${name}@${range}"`).join(" ");
1930
+ if (installCommand.startsWith("yarn")) return `yarn add ${specs}`;
1931
+ if (installCommand.startsWith("npm")) return `npm install ${specs}`;
1932
+ return `pnpm add ${specs}`;
1933
+ }
1934
+ var GLOBAL_CSS_CANDIDATES = [
1935
+ "app/globals.css",
1936
+ "src/app/globals.css",
1937
+ "styles/globals.css",
1938
+ "src/styles/globals.css",
1939
+ "globals.css"
1940
+ ];
1941
+ var TAILWIND_CONFIG_CANDIDATES = [
1942
+ "tailwind.config.ts",
1943
+ "tailwind.config.js",
1944
+ "tailwind.config.mjs",
1945
+ "tailwind.config.cjs"
1946
+ ];
1947
+ function isFile(file) {
1948
+ try {
1949
+ return statSync(file).isFile();
1950
+ } catch {
1951
+ return false;
1952
+ }
1953
+ }
1954
+ function isDirectory(dir) {
1955
+ try {
1956
+ return statSync(dir).isDirectory();
1957
+ } catch {
1958
+ return false;
1959
+ }
1960
+ }
1961
+ function findFirstFile(baseDir, candidates) {
1962
+ return candidates.find((c) => isFile(path8.join(baseDir, c)));
1963
+ }
1964
+ function detectProjectPaths(baseDirInput) {
1965
+ const baseDir = path8.resolve(baseDirInput);
1966
+ const hasSrc = isDirectory(path8.join(baseDir, "src"));
1967
+ const css = findFirstFile(baseDir, GLOBAL_CSS_CANDIDATES);
1968
+ const tw = findFirstFile(baseDir, TAILWIND_CONFIG_CANDIDATES);
1969
+ return {
1970
+ componentsDir: hasSrc ? "./src/components/ui" : "./components/ui",
1971
+ globalCss: css !== void 0 ? `./${css}` : hasSrc ? "./src/app/globals.css" : "./app/globals.css",
1972
+ globalCssSource: css !== void 0 ? "found" : "default",
1973
+ tailwindConfig: tw !== void 0 ? `./${tw}` : "./tailwind.config.ts",
1974
+ tailwindConfigSource: tw !== void 0 ? "found" : "default"
1975
+ };
1976
+ }
1977
+ function projectFileExists(baseDir, relPath) {
1978
+ return isFile(path8.resolve(baseDir, relPath));
1979
+ }
1980
+ var ROOT_LAYOUT_FILES = [
1981
+ "app/layout.tsx",
1982
+ "app/layout.jsx",
1983
+ "app/layout.js",
1984
+ "src/app/layout.tsx",
1985
+ "src/app/layout.jsx",
1986
+ "src/app/layout.js",
1987
+ "pages/_app.tsx",
1988
+ "pages/_app.jsx",
1989
+ "pages/_document.tsx",
1990
+ "pages/_document.jsx",
1991
+ "src/pages/_app.tsx",
1992
+ "src/pages/_app.jsx",
1993
+ "src/pages/_document.tsx",
1994
+ "src/pages/_document.jsx"
1995
+ ];
1996
+ function exactVersionOf(version) {
1997
+ if (typeof version !== "string") return void 0;
1998
+ const v = version.trim();
1999
+ if (!/^v?\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/.test(v) || /^v?0\.0\.0-/.test(v)) return void 0;
2000
+ return v;
2001
+ }
2002
+ function findInstalledPackage(baseDirInput, name) {
2003
+ let dir = path8.resolve(baseDirInput);
2004
+ for (; ; ) {
2005
+ const pkgDir = path8.join(dir, "node_modules", ...name.split("/"));
2006
+ const file = path8.join(pkgDir, "package.json");
2007
+ if (isFile(file)) {
2008
+ let version;
2009
+ try {
2010
+ const parsed = JSON.parse(readFileSync(file, "utf8"));
2011
+ version = isPlainObject(parsed) ? exactVersionOf(parsed.version) : void 0;
2012
+ } catch {
2013
+ version = void 0;
2014
+ }
2015
+ return { dir: pkgDir, version };
2016
+ }
2017
+ const parent = path8.dirname(dir);
2018
+ if (parent === dir) return void 0;
2019
+ dir = parent;
2020
+ }
2021
+ }
2022
+ function isPnpProject(baseDirInput) {
2023
+ let dir = path8.resolve(baseDirInput);
2024
+ for (; ; ) {
2025
+ if (isFile(path8.join(dir, ".pnp.cjs")) || isFile(path8.join(dir, ".pnp.js"))) return true;
2026
+ const parent = path8.dirname(dir);
2027
+ if (parent === dir) return false;
2028
+ dir = parent;
2029
+ }
2030
+ }
2031
+ function compareExactVersions(a, b) {
2032
+ const parse = (v) => {
2033
+ const m = /^v?(\d+)\.(\d+)\.(\d+)(-[0-9A-Za-z.-]+)?/.exec(v.trim());
2034
+ return m ? { core: [Number(m[1]), Number(m[2]), Number(m[3])], pre: m[4] !== void 0 } : void 0;
2035
+ };
2036
+ const x = parse(a);
2037
+ const y = parse(b);
2038
+ if (!x || !y) return void 0;
2039
+ for (let i = 0; i < 3; i++) if (x.core[i] !== y.core[i]) return x.core[i] - y.core[i];
2040
+ return Number(y.pre) - Number(x.pre);
2041
+ }
2042
+
2043
+ // ../axis-registry-core/src/template/tailwind-core.ts
2044
+ function hasDependency2(pkg, name) {
2045
+ for (const field of ["dependencies", "devDependencies"]) {
2046
+ const deps = pkg[field];
2047
+ if (typeof deps === "object" && deps !== null && name in deps) {
2048
+ return String(deps[name]);
2049
+ }
2050
+ }
2051
+ return void 0;
2052
+ }
2053
+ function isPlainObject2(value) {
2054
+ return typeof value === "object" && value !== null && !Array.isArray(value);
2055
+ }
1860
2056
  var VERSION = String.raw`v?(\d+)(?:\.(\d+|[xX*]))?(?:\.(\d+|[xX*]))?(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?`;
1861
2057
  function versionParts(token) {
1862
2058
  const m = new RegExp(`^${VERSION}$`).exec(token);
@@ -1930,12 +2126,12 @@ function majorFromVersion(version) {
1930
2126
  function detectTailwind(baseDirInput, pkg) {
1931
2127
  const baseDir = resolve(baseDirInput);
1932
2128
  const installedFile = join(baseDir, "node_modules", "tailwindcss", "package.json");
1933
- const declared = pkg ? hasDependency(pkg, "tailwindcss") : void 0;
2129
+ const declared = pkg ? hasDependency2(pkg, "tailwindcss") : void 0;
1934
2130
  const bounds = declared !== void 0 ? tailwindMajorBounds(declared) : void 0;
1935
2131
  const declaredMajor = bounds?.lower;
1936
2132
  try {
1937
- const installed = JSON.parse(readFileSync(installedFile, "utf8"));
1938
- const version = isPlainObject(installed) ? installed.version : void 0;
2133
+ const installed = JSON.parse(readFileSync2(installedFile, "utf8"));
2134
+ const version = isPlainObject2(installed) ? installed.version : void 0;
1939
2135
  const major = majorFromVersion(version);
1940
2136
  if (major !== void 0) {
1941
2137
  const found = { major, source: "installed", value: String(version) };
@@ -1982,18 +2178,57 @@ var TOKENS_CSS_IMPORT = /@import\s+(?:url\(\s*)?["'](@axis-ds\/tokens\/css(?:\/s
1982
2178
  function findTokensCssImport(css) {
1983
2179
  return TOKENS_CSS_IMPORT.exec(stripCssComments(css))?.[1];
1984
2180
  }
2181
+ var TOKENS_CSS_JS_IMPORT = /(?:\bimport\s+|\bfrom\s+|\brequire\s*\(\s*)(["'])(@axis-ds\/tokens\/css(?:\/shadcn|\/tailwind4)?)\1/;
2182
+ var AXIS_VARIABLE_DEFINITION = /(?<![\w-])--axis-[\w-]+\s*:/;
2183
+ function findLayoutTokensCssImport(baseDirInput) {
2184
+ const baseDir = resolve(baseDirInput);
2185
+ for (const candidate of ROOT_LAYOUT_FILES) {
2186
+ const file = join(baseDir, candidate);
2187
+ if (!existsSync2(file)) continue;
2188
+ let text;
2189
+ try {
2190
+ text = readFileSync2(file, "utf8");
2191
+ } catch {
2192
+ continue;
2193
+ }
2194
+ const m = TOKENS_CSS_JS_IMPORT.exec(stripJsComments(text));
2195
+ if (m) return { file: candidate, spec: m[2] };
2196
+ }
2197
+ return void 0;
2198
+ }
1985
2199
  function checkGlobalsCss(baseDirInput) {
1986
2200
  const baseDir = resolve(baseDirInput);
1987
2201
  for (const candidate of TAILWIND_CSS_CANDIDATES) {
1988
2202
  const file = join(baseDir, candidate);
1989
- if (!existsSync(file)) continue;
1990
- const content = readFileSync(file, "utf8");
1991
- if (content.includes("--background") && content.includes("--primary")) {
1992
- return { name: "globals.css", severity: "pass", message: `${candidate}\uC5D0 AXIS CSS \uBCC0\uC218\uAC00 \uC815\uC758\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4` };
1993
- }
2203
+ if (!existsSync2(file)) continue;
2204
+ const content = readFileSync2(file, "utf8");
2205
+ const css = stripCssComments(content);
1994
2206
  const imported = findTokensCssImport(content);
1995
- if (imported !== void 0) {
1996
- return { name: "globals.css", severity: "pass", message: `${candidate}\uC5D0 AXIS CSS \uBCC0\uC218\uAC00 \uC788\uC2B5\uB2C8\uB2E4 (${imported} import)` };
2207
+ let pass;
2208
+ if (imported !== void 0) pass = `${candidate}\uC5D0 AXIS CSS \uBCC0\uC218\uAC00 \uC788\uC2B5\uB2C8\uB2E4 (${imported} import)`;
2209
+ else if (AXIS_VARIABLE_DEFINITION.test(css)) pass = `${candidate}\uC5D0 AXIS CSS \uBCC0\uC218(--axis-*)\uAC00 \uC815\uC758\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4`;
2210
+ else {
2211
+ const layout = findLayoutTokensCssImport(baseDir);
2212
+ if (layout) pass = `${candidate}\uC5D0 AXIS CSS \uBCC0\uC218\uAC00 \uC788\uC2B5\uB2C8\uB2E4 (${layout.file}\uC758 ${layout.spec} import)`;
2213
+ }
2214
+ if (pass !== void 0) {
2215
+ const tailwind = detectTailwind(baseDir, readPackageJson(baseDir));
2216
+ const tailwind4 = tailwind.major !== void 0 && tailwind.major >= 4;
2217
+ if (!tailwind4 && findCreateNextAppDefaults(content).some((d) => d.includes("font-family: Arial"))) {
2218
+ return {
2219
+ name: "globals.css",
2220
+ severity: "warn",
2221
+ message: `${pass}. \uB2E4\uB9CC create-next-app \uAE30\uBCF8 body font-family: Arial \uC774 \uB0A8\uC544 \uC788\uC2B5\uB2C8\uB2E4 \u2192 \uC9C0\uC6B0\uC138\uC694(AXIS \uAE00\uAF34 \uB300\uC2E0 Arial \uC774 \uC801\uC6A9\uB428)`
2222
+ };
2223
+ }
2224
+ return { name: "globals.css", severity: "pass", message: pass };
2225
+ }
2226
+ if (css.includes("--background") && css.includes("--primary")) {
2227
+ return {
2228
+ name: "globals.css",
2229
+ severity: "warn",
2230
+ message: `${candidate}\uC5D0 \uC790\uCCB4 CSS \uBCC0\uC218(--background \xB7 --primary)\uB9CC \uC788\uACE0 AXIS \uD1A0\uD070\uC774 \uC5C6\uC2B5\uB2C8\uB2E4 \u2192 @axis-ds/tokens CSS \uB97C import \uD558\uC138\uC694`
2231
+ };
1997
2232
  }
1998
2233
  return { name: "globals.css", severity: "warn", message: `${candidate}\uC5D0 AXIS CSS \uBCC0\uC218\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4` };
1999
2234
  }
@@ -2056,8 +2291,8 @@ function exactVersion(version) {
2056
2291
  }
2057
2292
  function installedVersion(baseDir, name) {
2058
2293
  try {
2059
- const parsed = JSON.parse(readFileSync(join(baseDir, "node_modules", ...name.split("/"), "package.json"), "utf8"));
2060
- return isPlainObject(parsed) ? exactVersion(parsed.version) : void 0;
2294
+ const parsed = JSON.parse(readFileSync2(join(baseDir, "node_modules", ...name.split("/"), "package.json"), "utf8"));
2295
+ return isPlainObject2(parsed) ? exactVersion(parsed.version) : void 0;
2061
2296
  } catch {
2062
2297
  return void 0;
2063
2298
  }
@@ -2068,7 +2303,7 @@ function axisPackagesBelowTailwind4(pkg, baseDirInput) {
2068
2303
  const out = [];
2069
2304
  const min = lowerOf(TAILWIND4_MIN_AXIS_VERSION);
2070
2305
  for (const name of TAILWIND4_AXIS_PACKAGES) {
2071
- const range = hasDependency(pkg, name);
2306
+ const range = hasDependency2(pkg, name);
2072
2307
  if (range === void 0 || range.trim().startsWith("workspace:")) continue;
2073
2308
  const installed = baseDir !== void 0 ? installedVersion(baseDir, name) : void 0;
2074
2309
  const installedLower = installed !== void 0 ? lowerOf(installed) : void 0;
@@ -2125,8 +2360,10 @@ var CREATE_NEXT_APP_DEFAULTS = [
2125
2360
  },
2126
2361
  {
2127
2362
  prefix: "body",
2128
- pattern: /(?<![\w-])(background|background-color|color)\s*:\s*var\(\s*(--(?:background|foreground))\s*\)/g,
2129
- item: (m) => `${m[1]}: var(${m[2]})`
2363
+ // WI-0070: create-next-app 의 body `font-family: Arial, Helvetica, sans-serif` 도 같은 특징으로 봅니다. 레이어 밖 규칙이라
2364
+ // AXIS 글꼴(Pretendard, html 에 적용)을 이기고 Button 등이 `font-family: inherit` 로 Arial 을 물려받습니다.
2365
+ pattern: /(?<![\w-])(?:(background|background-color|color)\s*:\s*var\(\s*(--(?:background|foreground))\s*\)|font-family\s*:\s*Arial\b)/g,
2366
+ item: (m) => m[1] !== void 0 ? `${m[1]}: var(${m[2]})` : "font-family: Arial"
2130
2367
  }
2131
2368
  ];
2132
2369
  function findCreateNextAppDefaults(css) {
@@ -2182,10 +2419,55 @@ function hasTokensPresetReference(source) {
2182
2419
  return PRESET_REFERENCE.test(stripJsComments(source));
2183
2420
  }
2184
2421
  var PRESET_PASS_SUFFIX = `\uC5D0 AXIS \uD1A0\uD070\uC774 \uC124\uC815\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4 (${TOKENS_TAILWIND3_PRESET} preset)`;
2422
+ var TOKENS_CJS_PRESET_FIXED_VERSION = "1.7.0";
2423
+ var TOKENS_TAILWIND3_CJS_REQUIRE = `require("${TOKENS_TAILWIND3_PRESET}").default`;
2424
+ var PRESET_REQUIRE_CALL = /\brequire\s*\(\s*(["'])@axis-ds\/tokens\/tailwind\1\s*\)/g;
2425
+ var DEFAULT_ACCESS_AHEAD = /^\s*(?:\.\s*default\b|\[\s*["']default["']\s*\])/;
2426
+ function hasBareCjsPresetRequire(code) {
2427
+ for (const m of code.matchAll(PRESET_REQUIRE_CALL)) {
2428
+ const start = m.index ?? 0;
2429
+ const end = start + m[0].length;
2430
+ if (DEFAULT_ACCESS_AHEAD.test(code.slice(end))) continue;
2431
+ const before = code.slice(0, start);
2432
+ if (/\b(?:const|let|var)\s*\{[^{}]*\}\s*=\s*$/.test(before)) continue;
2433
+ const bound = /\b(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*=\s*$/.exec(before);
2434
+ if (!bound) return true;
2435
+ const ident = escapeRegExp(bound[1]);
2436
+ const rest = code.slice(0, bound.index) + code.slice(end);
2437
+ const bareUse = new RegExp(`(?<![\\w$.])${ident}(?![\\w$])(?!\\s*(?:\\.\\s*default\\b|\\[\\s*["']default["']\\s*\\]))`);
2438
+ if (bareUse.test(rest)) return true;
2439
+ }
2440
+ return false;
2441
+ }
2442
+ function isCommonJsConfig(file, source) {
2443
+ return extname(file) === ".cjs" || /\bmodule\.exports\b/.test(source);
2444
+ }
2445
+ function packageVersionGate(baseDirInput, pkg, name, min) {
2446
+ const baseDir = resolve(baseDirInput);
2447
+ if (!isPnpProject(baseDir)) {
2448
+ const installed = findInstalledPackage(baseDir, name)?.version;
2449
+ if (installed !== void 0) {
2450
+ const cmp = compareExactVersions(installed, min);
2451
+ if (cmp !== void 0) return { status: cmp >= 0 ? "ok" : "below", source: "installed", value: installed };
2452
+ }
2453
+ }
2454
+ const declared = pkg ? hasDependency2(pkg, name) : void 0;
2455
+ if (declared !== void 0) {
2456
+ const atLeast = rangeLowerAtLeast(declared, min);
2457
+ if (atLeast !== void 0) return { status: atLeast ? "ok" : "below", source: "declared", value: declared };
2458
+ return { status: "unknown", source: "declared", value: declared };
2459
+ }
2460
+ return { status: "unknown", source: "none" };
2461
+ }
2462
+ function versionGateLabel(gate) {
2463
+ if (gate.source === "installed") return `\uC124\uCE58\uBCF8 ${gate.value}`;
2464
+ if (gate.source === "declared") return `\uC120\uC5B8 ${gate.value}`;
2465
+ return "\uC124\uCE58\uBCF8 \xB7 \uC120\uC5B8 \uC5C6\uC74C";
2466
+ }
2185
2467
  function readPackageJson(baseDir) {
2186
2468
  try {
2187
- const parsed = JSON.parse(readFileSync(join(baseDir, "package.json"), "utf8"));
2188
- return isPlainObject(parsed) ? parsed : void 0;
2469
+ const parsed = JSON.parse(readFileSync2(join(baseDir, "package.json"), "utf8"));
2470
+ return isPlainObject2(parsed) ? parsed : void 0;
2189
2471
  } catch {
2190
2472
  return void 0;
2191
2473
  }
@@ -2195,7 +2477,7 @@ function tailwind4Issues(css, pkg, versions) {
2195
2477
  const hasEntry = hasTokensTailwind4Import(css);
2196
2478
  if (!hasEntry) issues.push(`AXIS \uD1A0\uD070 \uC9C4\uC785\uC810\uC774 \uC5C6\uC2B5\uB2C8\uB2E4 \u2192 ${TOKENS_TAILWIND4_IMPORT_LINE}`);
2197
2479
  const missing = TAILWIND4_COMPONENT_PACKAGES.filter(
2198
- (name) => pkg !== void 0 && hasDependency(pkg, name) !== void 0 && !hasComponentTailwindImport(css, name) && !hasComponentSource(css, name)
2480
+ (name) => pkg !== void 0 && hasDependency2(pkg, name) !== void 0 && !hasComponentTailwindImport(css, name) && !hasComponentSource(css, name)
2199
2481
  );
2200
2482
  if (missing.length > 0) {
2201
2483
  issues.push(`\uCEF4\uD3EC\uB10C\uD2B8 \uC2A4\uCE94 \uACBD\uB85C(tailwind.css)\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4 \u2192 ${missing.map(componentTailwindImportLine).join(" ")}`);
@@ -2222,8 +2504,8 @@ function checkTailwindSetup(baseDirInput) {
2222
2504
  const label = `Tailwind ${tailwind.major}`;
2223
2505
  for (const candidate of TAILWIND_CSS_CANDIDATES) {
2224
2506
  const file = join(baseDir, candidate);
2225
- if (!existsSync(file)) continue;
2226
- const css = readFileSync(file, "utf8");
2507
+ if (!existsSync2(file)) continue;
2508
+ const css = readFileSync2(file, "utf8");
2227
2509
  if (!hasTailwindImport(css)) {
2228
2510
  return {
2229
2511
  name: "tailwind.config",
@@ -2254,9 +2536,21 @@ function checkTailwindSetup(baseDirInput) {
2254
2536
  }
2255
2537
  for (const file of TAILWIND_CONFIG_FILES) {
2256
2538
  const path18 = join(baseDir, file);
2257
- if (!existsSync(path18)) continue;
2258
- const content = readFileSync(path18, "utf8");
2539
+ if (!existsSync2(path18)) continue;
2540
+ const content = readFileSync2(path18, "utf8");
2259
2541
  if (hasTokensPresetReference(content)) {
2542
+ const code = stripJsComments(content);
2543
+ if (isCommonJsConfig(file, code) && hasBareCjsPresetRequire(code)) {
2544
+ const gate = packageVersionGate(baseDir, pkg, "@axis-ds/tokens", TOKENS_CJS_PRESET_FIXED_VERSION);
2545
+ if (gate.status !== "ok") {
2546
+ 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`;
2547
+ return {
2548
+ name: "tailwind.config",
2549
+ severity: "warn",
2550
+ message: `${file}\uC5D0 AXIS preset \uCC38\uC870\uAC00 \uC788\uC9C0\uB9CC ${why} \u2192 ${TOKENS_TAILWIND3_CJS_REQUIRE} \uB85C \uBC14\uAFB8\uAC70\uB098 @axis-ds/tokens ${TOKENS_CJS_PRESET_FIXED_VERSION} \uC774\uC0C1`
2551
+ };
2552
+ }
2553
+ }
2260
2554
  return { name: "tailwind.config", severity: "pass", message: `${file}${PRESET_PASS_SUFFIX}` };
2261
2555
  }
2262
2556
  const ownMapping = content.includes("--background") || content.includes("hsl(var(");
@@ -2270,8 +2564,8 @@ function checkTailwindSetup(baseDirInput) {
2270
2564
  }
2271
2565
  function readAxisConfigLike(baseDir) {
2272
2566
  try {
2273
- const parsed = JSON.parse(readFileSync(join(baseDir, "axis.config.json"), "utf8"));
2274
- return isPlainObject(parsed) ? parsed : void 0;
2567
+ const parsed = JSON.parse(readFileSync2(join(baseDir, "axis.config.json"), "utf8"));
2568
+ return isPlainObject2(parsed) ? parsed : void 0;
2275
2569
  } catch {
2276
2570
  return void 0;
2277
2571
  }
@@ -2358,7 +2652,7 @@ function inspectTailwindContent(baseDirInput) {
2358
2652
  const pkg = readPackageJson(baseDir);
2359
2653
  const tailwind = detectTailwind(baseDir, pkg);
2360
2654
  if (tailwind.major !== void 0 && tailwind.major >= 4) return null;
2361
- const configFile = TAILWIND_CONFIG_FILES.find((f) => existsSync(join(baseDir, f)));
2655
+ const configFile = TAILWIND_CONFIG_FILES.find((f) => existsSync2(join(baseDir, f)));
2362
2656
  if (configFile === void 0) return null;
2363
2657
  const targets = [];
2364
2658
  const componentsDir = readAxisConfigLike(baseDir)?.componentsDir;
@@ -2367,12 +2661,12 @@ function inspectTailwindContent(baseDirInput) {
2367
2661
  targets.push({ label: `componentsDir(${componentsDir})`, sample: `${rel3}/button.tsx`, suggest: `./${rel3}/**/*.{ts,tsx}` });
2368
2662
  }
2369
2663
  for (const name of TAILWIND4_COMPONENT_PACKAGES) {
2370
- if (pkg !== void 0 && hasDependency(pkg, name) !== void 0) {
2664
+ if (pkg !== void 0 && hasDependency2(pkg, name) !== void 0) {
2371
2665
  targets.push({ label: name, sample: `node_modules/${name}/dist/index.js`, suggest: `./node_modules/${name}/dist/**/*.{js,mjs}` });
2372
2666
  }
2373
2667
  }
2374
2668
  if (targets.length === 0) return null;
2375
- const read = readTailwindContent(readFileSync(join(baseDir, configFile), "utf8"));
2669
+ const read = readTailwindContent(readFileSync2(join(baseDir, configFile), "utf8"));
2376
2670
  const patterns = (read?.globs ?? []).filter((g) => !g.trim().startsWith("!")).map(contentGlobToRegExp);
2377
2671
  return {
2378
2672
  configFile,
@@ -2437,7 +2731,7 @@ function componentsUseAnimation(baseDir, componentsDir) {
2437
2731
  if (st.isDirectory()) {
2438
2732
  if (name !== "node_modules" && depth < ANIMATION_SCAN_DEPTH_LIMIT) stack.push([p, depth + 1]);
2439
2733
  } else if (st.isFile() && st.size <= ANIMATION_SCAN_FILE_BYTES && /\.(tsx|ts|jsx|js)$/.test(name)) {
2440
- if (/\banimate-(?:in|out)\b/.test(readFileSync(p, "utf8"))) return true;
2734
+ if (/\banimate-(?:in|out)\b/.test(readFileSync2(p, "utf8"))) return true;
2441
2735
  }
2442
2736
  }
2443
2737
  }
@@ -2447,14 +2741,14 @@ function checkAnimationPlugin(baseDirInput) {
2447
2741
  const baseDir = resolve(baseDirInput);
2448
2742
  const pkg = readPackageJson(baseDir);
2449
2743
  const config = readAxisConfigLike(baseDir);
2450
- const declared = pkg !== void 0 && hasDependency(pkg, "@axis-ds/ui-react") !== void 0;
2744
+ const declared = pkg !== void 0 && hasDependency2(pkg, "@axis-ds/ui-react") !== void 0;
2451
2745
  const copied = typeof config?.componentsDir === "string" && componentsUseAnimation(baseDir, config.componentsDir);
2452
2746
  if (!declared && !copied) return null;
2453
2747
  const by = declared ? "@axis-ds/ui-react \uC120\uC5B8" : "componentsDir \uC758 animate-in \uB958 \uD074\uB798\uC2A4";
2454
2748
  const tailwind = detectTailwind(baseDir, pkg);
2455
2749
  if (tailwind.major !== void 0 && tailwind.major >= 4) {
2456
- const file = TAILWIND_CSS_CANDIDATES.find((c) => existsSync(join(baseDir, c)));
2457
- const css = file !== void 0 ? stripCssComments(readFileSync(join(baseDir, file), "utf8")) : "";
2750
+ const file = TAILWIND_CSS_CANDIDATES.find((c) => existsSync2(join(baseDir, c)));
2751
+ const css = file !== void 0 ? stripCssComments(readFileSync2(join(baseDir, file), "utf8")) : "";
2458
2752
  const ok = new RegExp(`@import\\s+(?:url\\(\\s*)?["']${ANIMATION_PLUGIN_TAILWIND4}["']`).test(css) || new RegExp(`@plugin\\s+["']${ANIMATION_PLUGIN_TAILWIND3}["']`).test(css);
2459
2753
  return ok ? { name: "animation", severity: "pass", message: `${file}\uC5D0 \uC560\uB2C8\uBA54\uC774\uC158 \uD50C\uB7EC\uADF8\uC778\uC774 \uC788\uC2B5\uB2C8\uB2E4` } : {
2460
2754
  name: "animation",
@@ -2462,25 +2756,91 @@ function checkAnimationPlugin(baseDirInput) {
2462
2756
  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}";`
2463
2757
  };
2464
2758
  }
2465
- const configFile = TAILWIND_CONFIG_FILES.find((f) => existsSync(join(baseDir, f)));
2466
- const source = configFile !== void 0 ? stripJsComments(readFileSync(join(baseDir, configFile), "utf8")) : "";
2467
- const pluginRef = new RegExp(`["']${ANIMATION_PLUGIN_TAILWIND3}["']`).test(source);
2468
- const pluginDeclared = pkg !== void 0 && hasDependency(pkg, ANIMATION_PLUGIN_TAILWIND3) !== void 0;
2469
- if (pluginRef && pluginDeclared) {
2470
- return { name: "animation", severity: "pass", message: `${configFile}\uC5D0 ${ANIMATION_PLUGIN_TAILWIND3} \uD50C\uB7EC\uADF8\uC778\uC774 \uC788\uC2B5\uB2C8\uB2E4` };
2471
- }
2472
- const why = !pluginDeclared ? `${ANIMATION_PLUGIN_TAILWIND3} \uBBF8\uC124\uCE58` : `${configFile ?? "tailwind.config"} plugins \uC5D0 \uC5C6\uC74C`;
2759
+ const configFile = TAILWIND_CONFIG_FILES.find((f) => existsSync2(join(baseDir, f)));
2760
+ const source = configFile !== void 0 ? stripJsComments(readFileSync2(join(baseDir, configFile), "utf8")) : "";
2761
+ const plugins = configFile !== void 0 ? readAnimationPluginUse(source) : "absent";
2762
+ const pluginDeclared = pkg !== void 0 && hasDependency2(pkg, ANIMATION_PLUGIN_TAILWIND3) !== void 0;
2763
+ const pluginInstalled = pluginDeclared && (isPnpProject(baseDir) || findInstalledPackage(baseDir, ANIMATION_PLUGIN_TAILWIND3) !== void 0);
2764
+ if (plugins === "found" && pluginDeclared && pluginInstalled) {
2765
+ return { name: "animation", severity: "pass", message: `${configFile}\uC758 plugins \uC5D0 ${ANIMATION_PLUGIN_TAILWIND3} \uAC00 \uC788\uC2B5\uB2C8\uB2E4` };
2766
+ }
2767
+ const cfg = configFile ?? "tailwind.config";
2768
+ const reasons = [];
2769
+ if (!pluginDeclared) reasons.push(`${ANIMATION_PLUGIN_TAILWIND3} \uC120\uC5B8 \uC5C6\uC74C`);
2770
+ else if (!pluginInstalled) reasons.push(`${ANIMATION_PLUGIN_TAILWIND3} \uBBF8\uC124\uCE58(\uC120\uC5B8\uB9CC \uC788\uC74C)`);
2771
+ if (plugins === "dynamic") reasons.push(`${cfg} plugins \uB97C \uC815\uC801\uC73C\uB85C \uB2E4 \uC77D\uC9C0 \uBABB\uD574 \uD655\uC778\uD558\uC9C0 \uBABB\uD568`);
2772
+ else if (plugins !== "found") reasons.push(`${cfg} plugins \uC5D0 \uC5C6\uC74C`);
2473
2773
  return {
2474
2774
  name: "animation",
2475
2775
  severity: "warn",
2476
- message: `\uC560\uB2C8\uBA54\uC774\uC158 \uD50C\uB7EC\uADF8\uC778\uC774 \uC5C6\uC2B5\uB2C8\uB2E4(${by}, ${why}): 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_TAILWIND3} \uC124\uCE58 \uB4A4 plugins \uC5D0 require("${ANIMATION_PLUGIN_TAILWIND3}")`
2776
+ message: `\uC560\uB2C8\uBA54\uC774\uC158 \uD50C\uB7EC\uADF8\uC778\uC774 \uC5C6\uC2B5\uB2C8\uB2E4(${by}, ${reasons.join(" \xB7 ")}): 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_TAILWIND3} \uC124\uCE58 \uB4A4 plugins \uC5D0 require("${ANIMATION_PLUGIN_TAILWIND3}")`
2477
2777
  };
2478
2778
  }
2779
+ function readAnimationPluginUse(source) {
2780
+ const name = escapeRegExp(ANIMATION_PLUGIN_TAILWIND3);
2781
+ const idents = /* @__PURE__ */ new Set();
2782
+ for (const m of source.matchAll(new RegExp(`\\bimport\\s+([A-Za-z_$][\\w$]*)\\s+from\\s*(["'])${name}\\2`, "g"))) idents.add(m[1]);
2783
+ for (const m of source.matchAll(
2784
+ new RegExp(`\\b(?:const|let|var)\\s+([A-Za-z_$][\\w$]*)\\s*=\\s*require\\s*\\(\\s*(["'])${name}\\2\\s*\\)`, "g")
2785
+ )) {
2786
+ idents.add(m[1]);
2787
+ }
2788
+ const requireCall = new RegExp(`^require\\s*\\(\\s*(["'])${name}\\1\\s*\\)(?:\\s*\\.\\s*default)?$`);
2789
+ let sawDynamic = false;
2790
+ for (const m of source.matchAll(/\bplugins\b\s*(:)?\s*/g)) {
2791
+ if (m[1] === void 0) {
2792
+ const before = source.slice(Math.max(0, (m.index ?? 0) - 1), m.index ?? 0);
2793
+ if (/[{,\s]/.test(before) || before === "") sawDynamic = true;
2794
+ continue;
2795
+ }
2796
+ const at = (m.index ?? 0) + m[0].length;
2797
+ if (source[at] !== "[") {
2798
+ sawDynamic = true;
2799
+ continue;
2800
+ }
2801
+ const block = balancedSlice(source, at);
2802
+ if (block === void 0) {
2803
+ sawDynamic = true;
2804
+ continue;
2805
+ }
2806
+ const elements = splitTopLevel(block.slice(1, -1));
2807
+ for (const el of elements) {
2808
+ const e = el.trim();
2809
+ if (e === "") continue;
2810
+ if (requireCall.test(e) || idents.has(e) || idents.has(e.replace(/\(\s*\)$/, ""))) return "found";
2811
+ if (/^require\s*\(\s*(["'])[^"']+\1\s*\)(?:\s*\.\s*default)?$/.test(e)) continue;
2812
+ sawDynamic = true;
2813
+ }
2814
+ }
2815
+ return sawDynamic ? "dynamic" : "absent";
2816
+ }
2817
+ function splitTopLevel(body) {
2818
+ const out = [];
2819
+ let depth = 0;
2820
+ let start = 0;
2821
+ for (let i = 0; i < body.length; i++) {
2822
+ const c = body[i];
2823
+ if (c === '"' || c === "'" || c === "`") {
2824
+ let j = i + 1;
2825
+ while (j < body.length && body[j] !== c) j += body[j] === "\\" ? 2 : 1;
2826
+ i = j;
2827
+ continue;
2828
+ }
2829
+ if (c === "(" || c === "[" || c === "{") depth++;
2830
+ else if (c === ")" || c === "]" || c === "}") depth--;
2831
+ else if (c === "," && depth === 0) {
2832
+ out.push(body.slice(start, i));
2833
+ start = i + 1;
2834
+ }
2835
+ }
2836
+ out.push(body.slice(start));
2837
+ return out;
2838
+ }
2479
2839
 
2480
2840
  // src/template/template-apply.ts
2481
2841
  async function templateApplyWarnings(baseDir, detail) {
2482
2842
  const warnings = [];
2483
- const pkgPath = path8.join(baseDir, "package.json");
2843
+ const pkgPath = path9.join(baseDir, "package.json");
2484
2844
  const templateRange = detail.devDependencies?.tailwindcss ?? detail.dependencies?.tailwindcss;
2485
2845
  const templateMajor = templateRange !== void 0 ? tailwindMajorFromRange(templateRange) : void 0;
2486
2846
  if (templateMajor !== void 0 && await fs8.pathExists(pkgPath)) {
@@ -2498,7 +2858,7 @@ async function templateApplyWarnings(baseDir, detail) {
2498
2858
  }
2499
2859
  }
2500
2860
  const usesRootApp = detail.files.some((f) => f.path.startsWith("app/"));
2501
- if (usesRootApp && await fs8.pathExists(path8.join(baseDir, "src", "app"))) {
2861
+ if (usesRootApp && await fs8.pathExists(path9.join(baseDir, "src", "app"))) {
2502
2862
  warnings.push(
2503
2863
  "src/app \uC774 \uC788\uB294\uB370 \uD15C\uD50C\uB9BF\uC740 \uB8E8\uD2B8 app/ \uC744 \uC501\uB2C8\uB2E4. Next.js \uB294 \uB8E8\uD2B8 app/ \uC774 \uC788\uC73C\uBA74 src/app \uC744 \uC4F0\uC9C0 \uC54A\uC544 \uAE30\uC874 \uB77C\uC6B0\uD2B8\uAC00 \uBE60\uC9D1\uB2C8\uB2E4."
2504
2864
  );
@@ -2515,13 +2875,13 @@ async function applyTemplate(slug, options) {
2515
2875
  spinner.fail(err.message);
2516
2876
  process.exit(1);
2517
2877
  }
2518
- const baseDir = path8.resolve(options.dir || ".");
2878
+ const baseDir = path9.resolve(options.dir || ".");
2519
2879
  for (const w of await templateApplyWarnings(baseDir, detail)) {
2520
2880
  console.log(chalk5.yellow(`! ${w}`));
2521
2881
  }
2522
2882
  const conflicts = [];
2523
2883
  for (const file of detail.files) {
2524
- const dest = path8.join(baseDir, file.path);
2884
+ const dest = path9.join(baseDir, file.path);
2525
2885
  if (await fs8.pathExists(dest)) {
2526
2886
  conflicts.push(file.path);
2527
2887
  }
@@ -2546,7 +2906,7 @@ async function applyTemplate(slug, options) {
2546
2906
  if (options.dryRun) {
2547
2907
  console.log(chalk5.blue("\n[\uBBF8\uB9AC\uBCF4\uAE30] \uC0DD\uC131\uB420 \uD30C\uC77C:"));
2548
2908
  for (const file of detail.files) {
2549
- const dest = path8.join(baseDir, file.path);
2909
+ const dest = path9.join(baseDir, file.path);
2550
2910
  const exists = conflicts.includes(file.path);
2551
2911
  const label = exists ? chalk5.yellow("\uB36E\uC5B4\uC4F0\uAE30") : chalk5.green("\uC0DD\uC131");
2552
2912
  console.log(` ${label} ${dest}`);
@@ -2561,8 +2921,8 @@ async function applyTemplate(slug, options) {
2561
2921
  }
2562
2922
  const writeSpinner = ora3("\uD30C\uC77C \uC0DD\uC131 \uC911...").start();
2563
2923
  for (const file of detail.files) {
2564
- const dest = path8.join(baseDir, file.path);
2565
- await fs8.ensureDir(path8.dirname(dest));
2924
+ const dest = path9.join(baseDir, file.path);
2925
+ await fs8.ensureDir(path9.dirname(dest));
2566
2926
  await fs8.writeFile(dest, file.content);
2567
2927
  }
2568
2928
  writeSpinner.succeed(`${detail.files.length}\uAC1C \uD30C\uC77C \uC0DD\uC131 \uC644\uB8CC`);
@@ -2623,7 +2983,7 @@ async function initTemplate(slug, options) {
2623
2983
  }
2624
2984
  targetDir = dir;
2625
2985
  }
2626
- const resolved = path8.resolve(targetDir);
2986
+ const resolved = path9.resolve(targetDir);
2627
2987
  if (await fs8.pathExists(resolved)) {
2628
2988
  const entries = await fs8.readdir(resolved);
2629
2989
  if (entries.length > 0) {
@@ -2639,7 +2999,7 @@ async function initTemplate(slug, options) {
2639
2999
  await fs8.ensureDir(resolved);
2640
3000
  }
2641
3001
  await applyTemplate(selectedSlug, { dir: targetDir, yes: true });
2642
- const configPath = path8.join(resolved, "axis.config.json");
3002
+ const configPath = path9.join(resolved, "axis.config.json");
2643
3003
  if (!await fs8.pathExists(configPath)) {
2644
3004
  const axisConfig = createTemplateConfig(selectedSlug);
2645
3005
  await fs8.writeJSON(configPath, axisConfig, { spaces: 2 });
@@ -2654,7 +3014,7 @@ async function initTemplate(slug, options) {
2654
3014
 
2655
3015
  // src/template/template-diff.ts
2656
3016
  import fs9 from "fs-extra";
2657
- import path9 from "path";
3017
+ import path10 from "path";
2658
3018
  import chalk6 from "chalk";
2659
3019
  import ora4 from "ora";
2660
3020
  async function diffTemplate(slug, options) {
@@ -2667,10 +3027,10 @@ async function diffTemplate(slug, options) {
2667
3027
  spinner.fail(err.message);
2668
3028
  process.exit(1);
2669
3029
  }
2670
- const baseDir = path9.resolve(options.dir || ".");
3030
+ const baseDir = path10.resolve(options.dir || ".");
2671
3031
  const entries = [];
2672
3032
  for (const file of detail.files) {
2673
- const localPath = path9.join(baseDir, file.path);
3033
+ const localPath = path10.join(baseDir, file.path);
2674
3034
  if (!await fs9.pathExists(localPath)) {
2675
3035
  entries.push({ path: file.path, status: "added" });
2676
3036
  continue;
@@ -2751,12 +3111,12 @@ async function collectLocalFiles(dir, base) {
2751
3111
  }
2752
3112
  for (const entry of entries) {
2753
3113
  if (ignore.has(entry.name)) continue;
2754
- const fullPath = path9.join(dir, entry.name);
3114
+ const fullPath = path10.join(dir, entry.name);
2755
3115
  if (entry.isDirectory()) {
2756
3116
  const nested = await collectLocalFiles(fullPath, root);
2757
3117
  results.push(...nested);
2758
3118
  } else {
2759
- results.push(path9.relative(root, fullPath).replace(/\\/g, "/"));
3119
+ results.push(path10.relative(root, fullPath).replace(/\\/g, "/"));
2760
3120
  }
2761
3121
  }
2762
3122
  return results;
@@ -2768,85 +3128,9 @@ import path11 from "path";
2768
3128
  import chalk7 from "chalk";
2769
3129
 
2770
3130
  // src/theme/brand-core.ts
2771
- import { existsSync as existsSync3, readFileSync as readFileSync2, statSync as statSync2 } from "fs";
3131
+ import { existsSync as existsSync3, readFileSync as readFileSync3, statSync as statSync2 } from "fs";
2772
3132
  import { createRequire } from "module";
2773
3133
  import { dirname, join as join2, relative, resolve as resolve2, sep } from "path";
2774
-
2775
- // ../axis-registry-core/src/project.ts
2776
- import { existsSync as existsSync2, statSync } from "fs";
2777
- import path10 from "path";
2778
- function detectInstallCommand(baseDir) {
2779
- if (existsSync2(path10.join(baseDir, "pnpm-lock.yaml"))) return "pnpm install";
2780
- if (existsSync2(path10.join(baseDir, "yarn.lock"))) return "yarn install";
2781
- if (existsSync2(path10.join(baseDir, "package-lock.json"))) return "npm install";
2782
- return "pnpm install";
2783
- }
2784
- function hasDependency2(pkg, name) {
2785
- for (const field of ["dependencies", "devDependencies"]) {
2786
- const deps = pkg[field];
2787
- if (typeof deps === "object" && deps !== null && name in deps) {
2788
- return String(deps[name]);
2789
- }
2790
- }
2791
- return void 0;
2792
- }
2793
- function isPlainObject2(value) {
2794
- return typeof value === "object" && value !== null && !Array.isArray(value);
2795
- }
2796
- function addCommandFor(installCommand, deps) {
2797
- const specs = Object.entries(deps).map(([name, range]) => `"${name}@${range}"`).join(" ");
2798
- if (installCommand.startsWith("yarn")) return `yarn add ${specs}`;
2799
- if (installCommand.startsWith("npm")) return `npm install ${specs}`;
2800
- return `pnpm add ${specs}`;
2801
- }
2802
- var GLOBAL_CSS_CANDIDATES = [
2803
- "app/globals.css",
2804
- "src/app/globals.css",
2805
- "styles/globals.css",
2806
- "src/styles/globals.css",
2807
- "globals.css"
2808
- ];
2809
- var TAILWIND_CONFIG_CANDIDATES = [
2810
- "tailwind.config.ts",
2811
- "tailwind.config.js",
2812
- "tailwind.config.mjs",
2813
- "tailwind.config.cjs"
2814
- ];
2815
- function isFile(file) {
2816
- try {
2817
- return statSync(file).isFile();
2818
- } catch {
2819
- return false;
2820
- }
2821
- }
2822
- function isDirectory(dir) {
2823
- try {
2824
- return statSync(dir).isDirectory();
2825
- } catch {
2826
- return false;
2827
- }
2828
- }
2829
- function findFirstFile(baseDir, candidates) {
2830
- return candidates.find((c) => isFile(path10.join(baseDir, c)));
2831
- }
2832
- function detectProjectPaths(baseDirInput) {
2833
- const baseDir = path10.resolve(baseDirInput);
2834
- const hasSrc = isDirectory(path10.join(baseDir, "src"));
2835
- const css = findFirstFile(baseDir, GLOBAL_CSS_CANDIDATES);
2836
- const tw = findFirstFile(baseDir, TAILWIND_CONFIG_CANDIDATES);
2837
- return {
2838
- componentsDir: hasSrc ? "./src/components/ui" : "./components/ui",
2839
- globalCss: css !== void 0 ? `./${css}` : hasSrc ? "./src/app/globals.css" : "./app/globals.css",
2840
- globalCssSource: css !== void 0 ? "found" : "default",
2841
- tailwindConfig: tw !== void 0 ? `./${tw}` : "./tailwind.config.ts",
2842
- tailwindConfigSource: tw !== void 0 ? "found" : "default"
2843
- };
2844
- }
2845
- function projectFileExists(baseDir, relPath) {
2846
- return isFile(path10.resolve(baseDir, relPath));
2847
- }
2848
-
2849
- // src/theme/brand-core.ts
2850
3134
  var TOKENS_PACKAGE = "@axis-ds/tokens";
2851
3135
  var BRAND_NAME_PATTERN = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/;
2852
3136
  var MIN_BRAND_TOKENS_VERSION = "1.3.0";
@@ -2867,7 +3151,7 @@ var KEY_TOKENS = [
2867
3151
  ];
2868
3152
  var BRAND_ADJUSTMENT_REFERENCE = "WI-0025 PRD \uBD80\uB85D B (docs/workitems/WI-0025-brand-theme/prd.md)";
2869
3153
  function readJsonFile(file) {
2870
- return JSON.parse(readFileSync2(file, "utf8"));
3154
+ return JSON.parse(readFileSync3(file, "utf8"));
2871
3155
  }
2872
3156
  function errorCode(err) {
2873
3157
  return typeof err === "object" && err !== null && "code" in err ? String(err.code) : void 0;
@@ -2943,7 +3227,7 @@ var AXIS_CONFIG_FILE_NAME = "axis.config.json";
2943
3227
  function readBrandConfig(baseDir) {
2944
3228
  let parsed;
2945
3229
  try {
2946
- parsed = JSON.parse(readFileSync2(join2(resolve2(baseDir), AXIS_CONFIG_FILE_NAME), "utf8"));
3230
+ parsed = JSON.parse(readFileSync3(join2(resolve2(baseDir), AXIS_CONFIG_FILE_NAME), "utf8"));
2947
3231
  } catch {
2948
3232
  return null;
2949
3233
  }
@@ -2962,7 +3246,7 @@ function inspectBrandImport(baseDir) {
2962
3246
  return { ...base, state: "css-missing", imports: [] };
2963
3247
  }
2964
3248
  const cssFile = relative(root, location.path).split(sep).join("/");
2965
- const imports = [...new Set(findBrandImports(readFileSync2(location.path, "utf8")))];
3249
+ const imports = [...new Set(findBrandImports(readFileSync3(location.path, "utf8")))];
2966
3250
  let state;
2967
3251
  if (imports.includes(brand)) state = "match";
2968
3252
  else if (imports.length === 0) state = "import-missing";
@@ -3046,34 +3330,23 @@ function pickKeyTokens(decls) {
3046
3330
  }
3047
3331
  return out;
3048
3332
  }
3333
+ var THEME_MARKUP_BRAND_MIN_VERSION = "1.7.0";
3049
3334
  function providerExample(name) {
3050
3335
  return [
3051
- "// 1) Provider \uC5C6\uC774: \uB8E8\uD2B8 \uB808\uC774\uC544\uC6C3(app/layout.tsx)\uC758 <html> \uC5D0 \uBD99\uC785\uB2C8\uB2E4(\uCCAB \uD654\uBA74\uBD80\uD130 \uC801\uC6A9)",
3336
+ "// 1) \uB8E8\uD2B8 \uB808\uC774\uC544\uC6C3(app/layout.tsx)\uC758 <html> \uC5D0 \uBD99\uC785\uB2C8\uB2E4(\uCCAB \uD654\uBA74\uBD80\uD130 \uC801\uC6A9)",
3337
+ `// ThemeProvider \uB97C \uD568\uAED8 \uC4F0\uBA74 @axis-ds/theme ${THEME_MARKUP_BRAND_MIN_VERSION} \uC774\uC0C1\uC774 \uD544\uC694\uD569\uB2C8\uB2E4(\uADF8 \uC544\uB798\uB294 \uB9C8\uC6B4\uD2B8 \uB54C \uC18D\uC131\uC744 \uC9C0\uC6C0)`,
3052
3338
  `<html lang="ko" data-brand="${name}">`,
3053
3339
  "",
3054
- "// 2) ThemeProvider \uB97C \uC4F0\uBA74 \uB9C8\uC6B4\uD2B8 \uB54C \uBE0C\uB79C\uB4DC\uAC00 \uC5C6\uC73C\uBA74 \uC18D\uC131\uC744 \uC9C0\uC6B0\uBBC0\uB85C setBrand \uB85C \uCF2D\uB2C8\uB2E4(\uC800\uC7A5\uB3FC \uC720\uC9C0, setBrand(undefined) \uB85C \uB054)",
3340
+ `// 2) \uC0AC\uC6A9\uC790\uAC00 \uACE0\uB974\uAC8C \uD558\uB824\uBA74 setBrand \uB85C \uCF1C\uACE0 \uB055\uB2C8\uB2E4(\uC800\uC7A5\uB3FC \uC720\uC9C0, setBrand(undefined) \uB85C \uB048 \uC0C1\uD0DC \uC720\uC9C0\uB294 ${THEME_MARKUP_BRAND_MIN_VERSION} \uC774\uC0C1)`,
3055
3341
  'import { useTheme } from "@axis-ds/theme";',
3056
3342
  "const { setBrand } = useTheme();",
3057
3343
  `setBrand("${name}");`
3058
3344
  ].join("\n");
3059
3345
  }
3060
- var BRAND_ACTIVATION_FILES = [
3061
- "app/layout.tsx",
3062
- "app/layout.jsx",
3063
- "app/layout.js",
3064
- "src/app/layout.tsx",
3065
- "src/app/layout.jsx",
3066
- "src/app/layout.js",
3067
- "pages/_app.tsx",
3068
- "pages/_app.jsx",
3069
- "pages/_document.tsx",
3070
- "pages/_document.jsx",
3071
- "src/pages/_app.tsx",
3072
- "src/pages/_app.jsx",
3073
- "src/pages/_document.tsx",
3074
- "src/pages/_document.jsx"
3075
- ];
3346
+ var BRAND_ACTIVATION_FILES = ROOT_LAYOUT_FILES;
3076
3347
  var BRAND_ACTIVATION_PATTERN = /data-brand|setBrand\s*\(|defaultBrand\s*=/;
3348
+ var PROVIDER_ACTIVATION_PATTERN = /setBrand\s*\(|defaultBrand\s*=/;
3349
+ var THEME_PROVIDER_PATTERN = /<ThemeProvider\b/;
3077
3350
  function stripJsLikeComments(src) {
3078
3351
  return src.replace(/\/\*[\s\S]*?\*\//g, "").replace(/(^|[^:"'`])\/\/[^\n]*/g, "$1");
3079
3352
  }
@@ -3084,15 +3357,23 @@ function findBrandActivation(baseDir) {
3084
3357
  const file = join2(root, candidate);
3085
3358
  if (!isFile2(file)) continue;
3086
3359
  layoutFiles.push(candidate);
3087
- const text = stripJsLikeComments(readFileSync2(file, "utf8"));
3088
- if (BRAND_ACTIVATION_PATTERN.test(text)) return { found: candidate, layoutFiles };
3360
+ const text = stripJsLikeComments(readFileSync3(file, "utf8"));
3361
+ const providerTexts = [];
3089
3362
  for (const m of text.matchAll(/from\s+["']\.\/(providers?)["']/g)) {
3090
3363
  for (const ext of [".tsx", ".jsx", ".ts", ".js"]) {
3091
3364
  const rel3 = `${dirname(candidate)}/${m[1]}${ext}`;
3092
3365
  const p = join2(root, rel3);
3093
- if (isFile2(p) && BRAND_ACTIVATION_PATTERN.test(stripJsLikeComments(readFileSync2(p, "utf8")))) {
3094
- return { found: rel3, layoutFiles };
3095
- }
3366
+ if (isFile2(p)) providerTexts.push({ rel: rel3, text: stripJsLikeComments(readFileSync3(p, "utf8")) });
3367
+ }
3368
+ }
3369
+ const all = [text, ...providerTexts.map((x) => x.text)];
3370
+ const markupWithProvider = !all.some((t) => PROVIDER_ACTIVATION_PATTERN.test(t)) && all.some((t) => THEME_PROVIDER_PATTERN.test(t));
3371
+ if (BRAND_ACTIVATION_PATTERN.test(text)) {
3372
+ return markupWithProvider ? { found: candidate, layoutFiles, markupWithProvider } : { found: candidate, layoutFiles };
3373
+ }
3374
+ for (const x of providerTexts) {
3375
+ if (BRAND_ACTIVATION_PATTERN.test(x.text)) {
3376
+ return markupWithProvider ? { found: x.rel, layoutFiles, markupWithProvider } : { found: x.rel, layoutFiles };
3096
3377
  }
3097
3378
  }
3098
3379
  }
@@ -3102,7 +3383,18 @@ function inspectBrandActivation(baseDir) {
3102
3383
  const config = readBrandConfig(baseDir);
3103
3384
  const brand = config?.brand;
3104
3385
  if (typeof brand !== "string" || brand.trim() === "") return null;
3105
- return { brand, ...findBrandActivation(baseDir) };
3386
+ const location = findBrandActivation(baseDir);
3387
+ if (!location.markupWithProvider) return { brand, ...location };
3388
+ return { brand, ...location, theme: packageVersionGate(baseDir, readProjectPackageJson(baseDir), THEME_PACKAGE, THEME_MARKUP_BRAND_MIN_VERSION) };
3389
+ }
3390
+ var THEME_PACKAGE = "@axis-ds/theme";
3391
+ function readProjectPackageJson(baseDir) {
3392
+ try {
3393
+ const parsed = JSON.parse(readFileSync3(join2(resolve2(baseDir), "package.json"), "utf8"));
3394
+ return typeof parsed === "object" && parsed !== null && !Array.isArray(parsed) ? parsed : void 0;
3395
+ } catch {
3396
+ return void 0;
3397
+ }
3106
3398
  }
3107
3399
  function getBrand(baseDir, name) {
3108
3400
  const tokens = resolveTokens(baseDir);
@@ -3120,7 +3412,7 @@ function getBrand(baseDir, name) {
3120
3412
  try {
3121
3413
  summary = readSummary(baseDir, entry);
3122
3414
  const cssPath = projectRequire(baseDir).resolve(summary.importPath);
3123
- parsed = parseBrandCss(readFileSync2(cssPath, "utf8"), name);
3415
+ parsed = parseBrandCss(readFileSync3(cssPath, "utf8"), name);
3124
3416
  } catch (err) {
3125
3417
  if (isMissingBuildFile(err)) return { status: "not-built", version: tokens.version, brand: null, available: [] };
3126
3418
  throw err;
@@ -3138,6 +3430,57 @@ function getBrand(baseDir, name) {
3138
3430
  };
3139
3431
  }
3140
3432
 
3433
+ // ../axis-registry-core/src/template/dependencies-core.ts
3434
+ import { readFileSync as readFileSync4 } from "fs";
3435
+ import { join as join3, resolve as resolve3 } from "path";
3436
+ var REQUIRED_DEPENDENCIES = ["tailwindcss"];
3437
+ var RECOMMENDED_DEPENDENCIES = ["clsx", "tailwind-merge"];
3438
+ function declaredAxisPackages(pkg) {
3439
+ const out = [];
3440
+ for (const field of ["dependencies", "devDependencies"]) {
3441
+ const deps = pkg[field];
3442
+ if (!isPlainObject(deps)) continue;
3443
+ for (const name of Object.keys(deps)) if (name.startsWith("@axis-ds/") && !out.includes(name)) out.push(name);
3444
+ }
3445
+ return out;
3446
+ }
3447
+ function checkDependencies(baseDirInput) {
3448
+ const baseDir = resolve3(baseDirInput);
3449
+ let pkg;
3450
+ try {
3451
+ const parsed = JSON.parse(readFileSync4(join3(baseDir, "package.json"), "utf8"));
3452
+ if (!isPlainObject(parsed)) throw new Error("not object");
3453
+ pkg = parsed;
3454
+ } catch (err) {
3455
+ if (err?.code === "ENOENT") {
3456
+ return { name: "dependencies", severity: "fail", message: "package.json \uD30C\uC77C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4" };
3457
+ }
3458
+ return { name: "dependencies", severity: "fail", message: "package.json \uC744 \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4(JSON \uD655\uC778)" };
3459
+ }
3460
+ const missingRequired = REQUIRED_DEPENDENCIES.filter((d) => !hasDependency(pkg, d));
3461
+ if (missingRequired.length > 0) {
3462
+ return { name: "dependencies", severity: "fail", message: `\uD544\uC218 \uC758\uC874\uC131 \uB204\uB77D: ${missingRequired.join(", ")}` };
3463
+ }
3464
+ const missingRecommended = RECOMMENDED_DEPENDENCIES.filter((d) => !hasDependency(pkg, d));
3465
+ const targets = [
3466
+ ...[...REQUIRED_DEPENDENCIES, ...RECOMMENDED_DEPENDENCIES].filter((d) => hasDependency(pkg, d) !== void 0),
3467
+ ...declaredAxisPackages(pkg)
3468
+ ];
3469
+ const pnp = isPnpProject(baseDir);
3470
+ const notInstalled = pnp ? [] : targets.filter((d) => findInstalledPackage(baseDir, d) === void 0);
3471
+ const problems = [];
3472
+ if (missingRecommended.length > 0) problems.push(`\uAD8C\uC7A5 \uC758\uC874\uC131 \uB204\uB77D: ${missingRecommended.join(", ")}`);
3473
+ if (notInstalled.length > 0) {
3474
+ problems.push(`\uC120\uC5B8\uB410\uC9C0\uB9CC \uC124\uCE58\uB418\uC9C0 \uC54A\uC740 \uC758\uC874\uC131: ${notInstalled.join(", ")} \u2192 ${detectInstallCommand(baseDir)}`);
3475
+ }
3476
+ if (problems.length > 0) return { name: "dependencies", severity: "warn", message: problems.join(" / ") };
3477
+ return {
3478
+ name: "dependencies",
3479
+ severity: "pass",
3480
+ message: pnp ? `\uD544\uC218 \uBC0F \uAD8C\uC7A5 \uC758\uC874\uC131\uC774 \uC120\uC5B8\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4 (Plug'n'Play \uB77C \uC124\uCE58\uBCF8\uC740 \uD655\uC778\uD558\uC9C0 \uC54A\uC74C, ${targets.length}\uAC1C)` : `\uD544\uC218 \uBC0F \uAD8C\uC7A5 \uC758\uC874\uC131\uC774 \uC120\uC5B8 \xB7 \uC124\uCE58\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4 (${targets.length}\uAC1C \uD655\uC778)`
3481
+ };
3482
+ }
3483
+
3141
3484
  // src/template/template-check.ts
3142
3485
  var SEVERITY_ICON = {
3143
3486
  pass: chalk7.green("PASS"),
@@ -3151,7 +3494,7 @@ async function collectCheckResults(dir) {
3151
3494
  results.push(checkTailwindSetup(baseDir));
3152
3495
  results.push(checkGlobalsCss(baseDir));
3153
3496
  results.push(await checkUtils(baseDir));
3154
- results.push(await checkDependencies(baseDir));
3497
+ results.push(checkDependencies(baseDir));
3155
3498
  const brand = checkBrand(baseDir);
3156
3499
  if (brand) results.push(brand);
3157
3500
  const activation = inspectBrandActivation(baseDir);
@@ -3229,41 +3572,6 @@ async function checkUtils(baseDir) {
3229
3572
  message: "utils.ts\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4 (\uCEF4\uD3EC\uB10C\uD2B8 \uC0AC\uC6A9 \uC2DC \uD544\uC694)"
3230
3573
  };
3231
3574
  }
3232
- async function checkDependencies(baseDir) {
3233
- const pkgPath = path11.join(baseDir, "package.json");
3234
- if (!await fs10.pathExists(pkgPath)) {
3235
- return {
3236
- name: "package.json",
3237
- severity: "fail",
3238
- message: "package.json \uD30C\uC77C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4"
3239
- };
3240
- }
3241
- const pkg = await fs10.readJSON(pkgPath);
3242
- const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
3243
- const required = ["tailwindcss"];
3244
- const recommended = ["clsx", "tailwind-merge"];
3245
- const missingRequired = required.filter((d) => !allDeps[d]);
3246
- const missingRecommended = recommended.filter((d) => !allDeps[d]);
3247
- if (missingRequired.length > 0) {
3248
- return {
3249
- name: "dependencies",
3250
- severity: "fail",
3251
- message: `\uD544\uC218 \uC758\uC874\uC131 \uB204\uB77D: ${missingRequired.join(", ")}`
3252
- };
3253
- }
3254
- if (missingRecommended.length > 0) {
3255
- return {
3256
- name: "dependencies",
3257
- severity: "warn",
3258
- message: `\uAD8C\uC7A5 \uC758\uC874\uC131 \uB204\uB77D: ${missingRecommended.join(", ")}`
3259
- };
3260
- }
3261
- return {
3262
- name: "dependencies",
3263
- severity: "pass",
3264
- message: "\uD544\uC218 \uBC0F \uAD8C\uC7A5 \uC758\uC874\uC131\uC774 \uBAA8\uB450 \uC124\uCE58\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4"
3265
- };
3266
- }
3267
3575
  function checkBrand(baseDir) {
3268
3576
  const check = inspectBrandImport(baseDir);
3269
3577
  return check ? brandCheckResult(check) : null;
@@ -3299,6 +3607,15 @@ function brandCheckResult(check) {
3299
3607
  }
3300
3608
  }
3301
3609
  function brandActivationResult(check) {
3610
+ if (check.found && check.theme && check.theme.status !== "ok") {
3611
+ const label = versionGateLabel(check.theme);
3612
+ 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`;
3613
+ return {
3614
+ name: "brand.activation",
3615
+ severity: "warn",
3616
+ message: `${check.found}\uC758 <html data-brand> \uB97C ${why} \u2192 @axis-ds/theme ${THEME_MARKUP_BRAND_MIN_VERSION} \uC774\uC0C1\uC73C\uB85C \uC62C\uB9AC\uAC70\uB098 setBrand("${check.brand}")`
3617
+ };
3618
+ }
3302
3619
  if (check.found) {
3303
3620
  return {
3304
3621
  name: "brand.activation",
@@ -3422,14 +3739,13 @@ import chalk9 from "chalk";
3422
3739
  import path13 from "path";
3423
3740
 
3424
3741
  // src/theme/theme-add.ts
3425
- import { accessSync, constants, existsSync as existsSync4, readFileSync as readFileSync3, realpathSync, unlinkSync, writeFileSync } from "fs";
3742
+ import { accessSync, constants, existsSync as existsSync4, readFileSync as readFileSync5, realpathSync, unlinkSync, writeFileSync } from "fs";
3426
3743
  import path12 from "path";
3427
3744
  var TOKENS_DEPENDENCY_RANGE = `^${TOKENS_DEPENDENCY_MIN_VERSION}`;
3428
3745
  var TAILWIND3_BASE_IMPORTS = [`${TOKENS_PACKAGE}/css`, `${TOKENS_PACKAGE}/css/shadcn`];
3429
- var THEME_PACKAGE = "@axis-ds/theme";
3430
3746
  var THEME_MIN_VERSION = "1.3.0";
3431
3747
  function readText(file) {
3432
- return existsSync4(file) ? readFileSync3(file, "utf8") : null;
3748
+ return existsSync4(file) ? readFileSync5(file, "utf8") : null;
3433
3749
  }
3434
3750
  function eolOf(text) {
3435
3751
  return text.includes("\r\n") ? "\r\n" : "\n";
@@ -3551,7 +3867,7 @@ function planThemeAdd(baseDirInput, brand) {
3551
3867
  let config;
3552
3868
  try {
3553
3869
  const parsed = JSON.parse(configText);
3554
- if (!isPlainObject2(parsed)) throw new Error("\uCD5C\uC0C1\uC704\uAC00 \uAC1D\uCCB4\uAC00 \uC544\uB2D9\uB2C8\uB2E4");
3870
+ if (!isPlainObject(parsed)) throw new Error("\uCD5C\uC0C1\uC704\uAC00 \uAC1D\uCCB4\uAC00 \uC544\uB2D9\uB2C8\uB2E4");
3555
3871
  config = parsed;
3556
3872
  } catch (err) {
3557
3873
  plan.errors.push({ kind: "invalid-config", message: err.message });
@@ -3563,7 +3879,7 @@ function planThemeAdd(baseDirInput, brand) {
3563
3879
  }
3564
3880
  plan.tokens = resolveTokens(baseDir);
3565
3881
  if (plan.tokens.status === "ok" && plan.tokens.indexPath) {
3566
- const data = JSON.parse(readFileSync3(plan.tokens.indexPath, "utf8"));
3882
+ const data = JSON.parse(readFileSync5(plan.tokens.indexPath, "utf8"));
3567
3883
  const entries = Array.isArray(data.brands) ? data.brands : [];
3568
3884
  const entry = entries.find((e) => e.name === brand);
3569
3885
  if (!entry) {
@@ -3585,7 +3901,7 @@ function planThemeAdd(baseDirInput, brand) {
3585
3901
  if (pkgText !== null) {
3586
3902
  try {
3587
3903
  const parsed = JSON.parse(pkgText);
3588
- if (!isPlainObject2(parsed)) throw new Error("\uCD5C\uC0C1\uC704\uAC00 \uAC1D\uCCB4\uAC00 \uC544\uB2D9\uB2C8\uB2E4");
3904
+ if (!isPlainObject(parsed)) throw new Error("\uCD5C\uC0C1\uC704\uAC00 \uAC1D\uCCB4\uAC00 \uC544\uB2D9\uB2C8\uB2E4");
3589
3905
  pkg = parsed;
3590
3906
  } catch (err) {
3591
3907
  plan.errors.push({ kind: "invalid-package-json", message: err.message });
@@ -3597,7 +3913,7 @@ function planThemeAdd(baseDirInput, brand) {
3597
3913
  const tailwind4 = tailwind.major !== void 0 && tailwind.major >= 4;
3598
3914
  const requiredBaseImports = tailwind4 ? [
3599
3915
  TOKENS_TAILWIND4_ENTRY,
3600
- ...TAILWIND4_COMPONENT_PACKAGES.filter((n) => pkg !== void 0 && hasDependency2(pkg, n) !== void 0).map(
3916
+ ...TAILWIND4_COMPONENT_PACKAGES.filter((n) => pkg !== void 0 && hasDependency(pkg, n) !== void 0).map(
3601
3917
  (n) => `${n}/tailwind.css`
3602
3918
  )
3603
3919
  ] : [...TAILWIND3_BASE_IMPORTS];
@@ -3614,7 +3930,7 @@ function planThemeAdd(baseDirInput, brand) {
3614
3930
  plan.writes = [];
3615
3931
  return plan;
3616
3932
  }
3617
- const before = readFileSync3(location.path, "utf8");
3933
+ const before = readFileSync5(location.path, "utf8");
3618
3934
  const imported = findBrandImports(before);
3619
3935
  const otherBrands = [...new Set(imported.filter((n) => n !== brand))];
3620
3936
  const brandAdded = !imported.includes(brand);
@@ -3651,7 +3967,7 @@ function planThemeAdd(baseDirInput, brand) {
3651
3967
  const content = inspectTailwindContent(baseDir);
3652
3968
  plan.tailwindConfig = {
3653
3969
  configFile: configFile2,
3654
- presetMissing: configFile2 === void 0 || !hasTokensPresetReference(readFileSync3(path12.join(baseDir, configFile2), "utf8")),
3970
+ presetMissing: configFile2 === void 0 || !hasTokensPresetReference(readFileSync5(path12.join(baseDir, configFile2), "utf8")),
3655
3971
  contentMissing: content?.targets.filter((t) => !t.covered) ?? [],
3656
3972
  contentUnknown: content !== null && (content.unreadable || content.dynamic)
3657
3973
  };
@@ -3664,12 +3980,12 @@ function planThemeAdd(baseDirInput, brand) {
3664
3980
  if (pkgText === null || pkg === void 0) {
3665
3981
  plan.dependency = { action: "no-package-json", upgrade, themeMissing: false, tokensAddCommand, themeAddCommand };
3666
3982
  } else {
3667
- const themeMissing = hasDependency2(pkg, THEME_PACKAGE) === void 0;
3668
- const declared = hasDependency2(pkg, TOKENS_PACKAGE);
3983
+ const themeMissing = hasDependency(pkg, THEME_PACKAGE) === void 0;
3984
+ const declared = hasDependency(pkg, TOKENS_PACKAGE);
3669
3985
  if (declared !== void 0) {
3670
3986
  plan.dependency = { action: "present", declaredRange: declared, upgrade, themeMissing, tokensAddCommand, themeAddCommand };
3671
3987
  } else {
3672
- const deps = isPlainObject2(pkg.dependencies) ? { ...pkg.dependencies } : {};
3988
+ const deps = isPlainObject(pkg.dependencies) ? { ...pkg.dependencies } : {};
3673
3989
  deps[TOKENS_PACKAGE] = TOKENS_DEPENDENCY_RANGE;
3674
3990
  const next = { ...pkg, dependencies: deps };
3675
3991
  plan.dependency = { action: "add", upgrade, themeMissing, tokensAddCommand, themeAddCommand };
@@ -3754,6 +4070,25 @@ function applyThemeAdd(plan) {
3754
4070
  }
3755
4071
 
3756
4072
  // src/theme/index.ts
4073
+ function importOffset(css, spec) {
4074
+ const escaped = spec.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
4075
+ const m = new RegExp(`@import\\s+(?:url\\(\\s*)?["']${escaped}["']`).exec(css);
4076
+ return m ? m.index : -1;
4077
+ }
4078
+ function baseImportLines(after, spec, brandImportPath2, file) {
4079
+ if (spec.endsWith("/tailwind.css")) {
4080
+ return [` ${chalk9.green("\u2713")} ${file}: @import "${spec}"; \uCD94\uAC00(\uCEF4\uD3EC\uB10C\uD2B8 \uC2A4\uCE94 \uACBD\uB85C, \uC704\uCE58 \uBB34\uAD00)`];
4081
+ }
4082
+ const at = importOffset(after, spec);
4083
+ const brandAt = importOffset(after, brandImportPath2);
4084
+ if (brandAt === -1 || at !== -1 && at < brandAt) {
4085
+ return [` ${chalk9.green("\u2713")} ${file}: @import "${spec}"; \uCD94\uAC00(\uAE30\uBCF8 \uD1A0\uD070 CSS, \uBE0C\uB79C\uB4DC \uC55E)`];
4086
+ }
4087
+ return [
4088
+ ` ${chalk9.green("\u2713")} ${file}: @import "${spec}"; \uCD94\uAC00(\uAE30\uBCF8 \uD1A0\uD070 CSS)`,
4089
+ 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`)
4090
+ ];
4091
+ }
3757
4092
  function tokensInstallCommand(baseDir) {
3758
4093
  return addCommandFor(detectInstallCommand(baseDir), { [TOKENS_PACKAGE]: TOKENS_DEPENDENCY_RANGE });
3759
4094
  }
@@ -3941,8 +4276,9 @@ function renderThemeAdd(plan, written) {
3941
4276
  }
3942
4277
  const brandLine = `@import "${plan.importPath}";`;
3943
4278
  if (css?.action === "add" && css.file) {
4279
+ const after = plan.writes.find((w) => w.file === css.file)?.after ?? "";
3944
4280
  for (const spec of css.baseImports) {
3945
- lines.push(` ${chalk9.green("\u2713")} ${rel(plan, css.file)}: @import "${spec}"; \uCD94\uAC00(\uAE30\uBCF8 \uD1A0\uD070 CSS, \uBE0C\uB79C\uB4DC \uC55E)`);
4281
+ lines.push(...baseImportLines(after, spec, plan.importPath, rel(plan, css.file)));
3946
4282
  }
3947
4283
  if (css.brandAdded) lines.push(` ${chalk9.green("\u2713")} ${rel(plan, css.file)}: ${brandLine} \uCD94\uAC00`);
3948
4284
  else lines.push(` ${chalk9.gray("-")} ${rel(plan, css.file)}: \uBE0C\uB79C\uB4DC import \uAC00 \uC774\uBBF8 \uC788\uC5B4 \uAC74\uB108\uB700`);
@@ -4002,7 +4338,8 @@ function renderThemeAdd(plan, written) {
4002
4338
  lines.push("", chalk9.bold(`Tailwind \uC124\uC815 (${tw.configFile ?? "tailwind.config"}, \uD30C\uC77C\uC740 \uACE0\uCE58\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4)`));
4003
4339
  if (tw.presetMissing) {
4004
4340
  lines.push(
4005
- chalk9.yellow(` ! AXIS preset \uC774 \uC5C6\uC2B5\uB2C8\uB2E4. presets \uC5D0 \uB123\uC73C\uC138\uC694: presets: [require("${TOKENS_TAILWIND3_PRESET}")]`) + chalk9.gray(` (ESM \uC774\uBA74 import axisPreset from "${TOKENS_TAILWIND3_PRESET}")`)
4341
+ // WI-0072: CommonJS 는 모든 tokens 버전에서 동작하는 `.default` 형태로 안내합니다(1.6.2 이하의 bare require 는 preset 이 빠짐)
4342
+ chalk9.yellow(` ! AXIS preset \uC774 \uC5C6\uC2B5\uB2C8\uB2E4. presets \uC5D0 \uB123\uC73C\uC138\uC694: presets: [${TOKENS_TAILWIND3_CJS_REQUIRE}]`) + chalk9.gray(` (ESM \xB7 TypeScript \uC774\uBA74 import axisPreset from "${TOKENS_TAILWIND3_PRESET}" \uB4A4 presets: [axisPreset])`)
4006
4343
  );
4007
4344
  }
4008
4345
  for (const t of tw.contentMissing) {
@@ -4017,6 +4354,13 @@ function renderThemeAdd(plan, written) {
4017
4354
  lines.push("", chalk9.bold(`\uBE0C\uB79C\uB4DC \uCF1C\uAE30 (ThemeProvider \uB294 ${THEME_PACKAGE} ${THEME_MIN_VERSION} \uC774\uC0C1)`));
4018
4355
  if (act?.found) {
4019
4356
  lines.push(` ${chalk9.gray("-")} ${act.found} \uC5D0 \uBE0C\uB79C\uB4DC\uB97C \uCF1C\uB294 \uCF54\uB4DC(data-brand \xB7 setBrand \uB4F1)\uAC00 \uC788\uC2B5\uB2C8\uB2E4. "${plan.brand}" \uB85C \uCF1C\uB294\uC9C0 \uD655\uC778\uD558\uC138\uC694.`);
4357
+ if (act.markupWithProvider) {
4358
+ lines.push(
4359
+ chalk9.yellow(
4360
+ ` ! <html data-brand> \uC640 ThemeProvider \uB97C \uD568\uAED8 \uC4F0\uBA74 ${THEME_PACKAGE} ${THEME_MARKUP_BRAND_MIN_VERSION} \uC774\uC0C1\uC774\uC5B4\uC57C \uB9C8\uC6B4\uD2B8 \uB54C \uC9C0\uC6CC\uC9C0\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC124\uCE58\uBCF8 \uD655\uC778: axis check`
4361
+ )
4362
+ );
4363
+ }
4020
4364
  } else {
4021
4365
  lines.push(
4022
4366
  ...providerExample(plan.brand).split("\n").map((l) => l ? ` ${l}` : ""),
@@ -4387,7 +4731,7 @@ async function fetchRegistryJson(url, options = {}) {
4387
4731
  }
4388
4732
 
4389
4733
  // src/init/init.ts
4390
- import { accessSync as accessSync2, constants as constants2, existsSync as existsSync6, lstatSync as lstatSync3, readFileSync as readFileSync4, realpathSync as realpathSync3, statSync as statSync4, writeFileSync as writeFileSync2 } from "fs";
4734
+ import { accessSync as accessSync2, constants as constants2, existsSync as existsSync6, lstatSync as lstatSync3, readFileSync as readFileSync6, realpathSync as realpathSync3, statSync as statSync4, writeFileSync as writeFileSync2 } from "fs";
4391
4735
  import path15 from "path";
4392
4736
  import chalk10 from "chalk";
4393
4737
  import fs12 from "fs-extra";
@@ -4644,7 +4988,7 @@ async function resolveInitAnswers(baseDirInput, tailwind4) {
4644
4988
  }
4645
4989
  function animationGuideLine(pkg, tailwind4, installCommand) {
4646
4990
  const name = tailwind4 ? ANIMATION_PLUGIN_TAILWIND4 : ANIMATION_PLUGIN_TAILWIND3;
4647
- if (pkg !== void 0 && (hasDependency2(pkg, ANIMATION_PLUGIN_TAILWIND3) !== void 0 || hasDependency2(pkg, ANIMATION_PLUGIN_TAILWIND4) !== void 0)) {
4991
+ if (pkg !== void 0 && (hasDependency(pkg, ANIMATION_PLUGIN_TAILWIND3) !== void 0 || hasDependency(pkg, ANIMATION_PLUGIN_TAILWIND4) !== void 0)) {
4648
4992
  return void 0;
4649
4993
  }
4650
4994
  const add = `${addCommandFor(installCommand, {}).trimEnd()} ${name}`;
@@ -4659,15 +5003,15 @@ var TAILWIND4_TOKENS_VERSION = TAILWIND4_MIN_AXIS_VERSION;
4659
5003
  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.";
4660
5004
  function readPackageJsonSafe(baseDir) {
4661
5005
  try {
4662
- const text = readFileSync4(path15.join(baseDir, "package.json"), "utf8");
5006
+ const text = readFileSync6(path15.join(baseDir, "package.json"), "utf8");
4663
5007
  const parsed = JSON.parse(text.startsWith(BOM) ? text.slice(1) : text);
4664
- return isPlainObject2(parsed) ? parsed : void 0;
5008
+ return isPlainObject(parsed) ? parsed : void 0;
4665
5009
  } catch {
4666
5010
  return void 0;
4667
5011
  }
4668
5012
  }
4669
5013
  function tailwind4GuideLines(pkg, installCommand, globalCss, baseDir) {
4670
- const used = TAILWIND4_COMPONENT_PACKAGES.filter((name) => pkg !== void 0 && hasDependency2(pkg, name) !== void 0);
5014
+ const used = TAILWIND4_COMPONENT_PACKAGES.filter((name) => pkg !== void 0 && hasDependency(pkg, name) !== void 0);
4671
5015
  const lines = [
4672
5016
  `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).`,
4673
5017
  ' @import "tailwindcss";',
@@ -4680,7 +5024,7 @@ function tailwind4GuideLines(pkg, installCommand, globalCss, baseDir) {
4680
5024
  );
4681
5025
  }
4682
5026
  lines.push(TAILWIND4_CONFLICT_LINE);
4683
- if (pkg === void 0 || hasDependency2(pkg, TOKENS_PACKAGE) === void 0) {
5027
+ if (pkg === void 0 || hasDependency(pkg, TOKENS_PACKAGE) === void 0) {
4684
5028
  const add = addCommandFor(installCommand, { [TOKENS_PACKAGE]: `^${TAILWIND4_TOKENS_VERSION}` });
4685
5029
  lines.push(` ${TOKENS_PACKAGE} \uC124\uCE58: ${add}`);
4686
5030
  }
@@ -4743,7 +5087,7 @@ function planUtilsDependencies(baseDirInput) {
4743
5087
  if (!where.inside) return unwritable(`\uC2E4\uC81C \uC704\uCE58(${where.realPath})\uAC00 \uD504\uB85C\uC81D\uD2B8 \uB514\uB809\uD130\uB9AC \uBC16\uC785\uB2C8\uB2E4`);
4744
5088
  let text;
4745
5089
  try {
4746
- text = readFileSync4(pkgFile, "utf8");
5090
+ text = readFileSync6(pkgFile, "utf8");
4747
5091
  } catch (err) {
4748
5092
  return unwritable(err.message);
4749
5093
  }
@@ -4752,7 +5096,7 @@ function planUtilsDependencies(baseDirInput) {
4752
5096
  let pkg;
4753
5097
  try {
4754
5098
  const parsed = JSON.parse(body);
4755
- if (!isPlainObject2(parsed)) throw new Error("\uCD5C\uC0C1\uC704\uAC00 \uAC1D\uCCB4\uAC00 \uC544\uB2D9\uB2C8\uB2E4");
5099
+ if (!isPlainObject(parsed)) throw new Error("\uCD5C\uC0C1\uC704\uAC00 \uAC1D\uCCB4\uAC00 \uC544\uB2D9\uB2C8\uB2E4");
4756
5100
  pkg = parsed;
4757
5101
  } catch (err) {
4758
5102
  return unwritable(`JSON \uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${err.message}`);
@@ -4762,14 +5106,14 @@ function planUtilsDependencies(baseDirInput) {
4762
5106
  plan.addCommand = addCommandFor(installCommand, plan.ranges);
4763
5107
  const missing = {};
4764
5108
  for (const [name, range] of Object.entries(plan.ranges)) {
4765
- const declared = hasDependency2(pkg, name);
5109
+ const declared = hasDependency(pkg, name);
4766
5110
  if (declared !== void 0) plan.present.push({ name, range: declared });
4767
5111
  else missing[name] = range;
4768
5112
  }
4769
5113
  plan.added = Object.keys(missing);
4770
5114
  plan.addCommand = addCommandFor(installCommand, plan.added.length > 0 ? missing : plan.ranges);
4771
5115
  if (plan.added.length === 0) return { ...plan, action: "present" };
4772
- if (pkg.dependencies !== void 0 && !isPlainObject2(pkg.dependencies)) {
5116
+ if (pkg.dependencies !== void 0 && !isPlainObject(pkg.dependencies)) {
4773
5117
  return unwritable("dependencies \uAC00 \uAC1D\uCCB4\uAC00 \uC544\uB2D9\uB2C8\uB2E4");
4774
5118
  }
4775
5119
  try {
@@ -4786,7 +5130,7 @@ function applyUtilsDependencies(baseDirInput, plan, writeFile = defaultWriteFile
4786
5130
  const w = plan.write;
4787
5131
  if (plan.action !== "add" || !w) return false;
4788
5132
  const baseDir = path15.resolve(baseDirInput);
4789
- const current = existsSync6(w.file) ? readFileSync4(w.file, "utf8") : null;
5133
+ const current = existsSync6(w.file) ? readFileSync6(w.file, "utf8") : null;
4790
5134
  if (current !== w.before) {
4791
5135
  throw new Error(`${w.file} \uC774 \uACC4\uD68D \uB4A4\uC5D0 \uBC14\uB00C\uC5C8\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694.`);
4792
5136
  }
@@ -4802,7 +5146,7 @@ function applyUtilsDependencies(baseDirInput, plan, writeFile = defaultWriteFile
4802
5146
  let restored;
4803
5147
  try {
4804
5148
  writeFile(w.file, w.before);
4805
- 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");
5149
+ if (readFileSync6(w.file, "utf8") !== w.before) throw new Error("\uB418\uB3CC\uB9B0 \uB0B4\uC6A9\uC774 \uC6D0\uB798 \uB0B4\uC6A9\uACFC \uB2E4\uB985\uB2C8\uB2E4");
4806
5150
  restored = "\uC6D0\uB798 \uB0B4\uC6A9\uC73C\uB85C \uB418\uB3CC\uB838\uC2B5\uB2C8\uB2E4";
4807
5151
  } catch (restoreErr) {
4808
5152
  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`;
@@ -4840,7 +5184,7 @@ function reportDependencies(plan, log) {
4840
5184
  async function existingConfig(baseDir) {
4841
5185
  try {
4842
5186
  const parsed = await readAxisConfig(baseDir);
4843
- return isPlainObject2(parsed) ? parsed : null;
5187
+ return isPlainObject(parsed) ? parsed : null;
4844
5188
  } catch {
4845
5189
  return null;
4846
5190
  }
@@ -4913,7 +5257,7 @@ function planUtilsWrite(baseDirInput, utilsPath) {
4913
5257
  if (!target.isFile()) return { action: "reject", reason: `${shown} \uB9C1\uD06C \uB300\uC0C1(${real})\uC774 \uC77C\uBC18 \uD30C\uC77C\uC774 \uC544\uB2D9\uB2C8\uB2E4` };
4914
5258
  let content2;
4915
5259
  try {
4916
- content2 = readFileSync4(utilsPath, "utf8");
5260
+ content2 = readFileSync6(utilsPath, "utf8");
4917
5261
  } catch (e) {
4918
5262
  return { action: "reject", reason: `${shown} \uB9C1\uD06C \uB300\uC0C1(${real})\uC744 \uC77D\uC9C0 \uBABB\uD574 \uBE44\uAD50\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4(${errCode(e)})` };
4919
5263
  }
@@ -4928,7 +5272,7 @@ function planUtilsWrite(baseDirInput, utilsPath) {
4928
5272
  if (!st.isFile()) return { action: "reject", reason: `${shown} \uC774 \uC77C\uBC18 \uD30C\uC77C\uC774 \uC544\uB2C8\uB77C \uC4F0\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4` };
4929
5273
  let content;
4930
5274
  try {
4931
- content = readFileSync4(utilsPath, "utf8");
5275
+ content = readFileSync6(utilsPath, "utf8");
4932
5276
  } catch (e) {
4933
5277
  return { action: "reject", reason: `\uAE30\uC874 ${shown} \uC744 \uC77D\uC9C0 \uBABB\uD574 \uBE44\uAD50\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4(${errCode(e)})` };
4934
5278
  }
@@ -5129,12 +5473,12 @@ import chalk12 from "chalk";
5129
5473
  import prompts3 from "prompts";
5130
5474
 
5131
5475
  // ../axis-registry-core/src/add/add.ts
5132
- import { existsSync as existsSync8, readFileSync as readFileSync6, statSync as statSync5 } from "fs";
5476
+ import { existsSync as existsSync8, readFileSync as readFileSync8, statSync as statSync5 } from "fs";
5133
5477
  import path17 from "path";
5134
5478
  import fs13 from "fs-extra";
5135
5479
 
5136
5480
  // ../axis-registry-core/src/registry/bundled.ts
5137
- import { existsSync as existsSync7, readFileSync as readFileSync5 } from "fs";
5481
+ import { existsSync as existsSync7, readFileSync as readFileSync7 } from "fs";
5138
5482
  import path16 from "path";
5139
5483
  import { fileURLToPath } from "url";
5140
5484
  function findBundledRegistryDir(moduleUrl = import.meta.url) {
@@ -5148,7 +5492,7 @@ function readBundledJson(dir, fileName) {
5148
5492
  const file = path16.join(dir, fileName);
5149
5493
  let text;
5150
5494
  try {
5151
- text = readFileSync5(file, "utf8");
5495
+ text = readFileSync7(file, "utf8");
5152
5496
  } catch {
5153
5497
  throw new Error(`\uB3D9\uBD09 \uB808\uC9C0\uC2A4\uD2B8\uB9AC\uC5D0 ${fileName} \uAC00 \uC5C6\uC2B5\uB2C8\uB2E4(${dir})`);
5154
5498
  }
@@ -5336,7 +5680,7 @@ function createPinnedFetch(options = {}) {
5336
5680
  const judge = options.judge ?? blockedAddressReason;
5337
5681
  const send = options.request ?? httpsRequest;
5338
5682
  const maxBytes = options.maxBytes ?? PINNED_FETCH_MAX_BYTES;
5339
- return (input, init) => new Promise((resolve3, reject) => {
5683
+ return (input, init) => new Promise((resolve4, reject) => {
5340
5684
  let url;
5341
5685
  try {
5342
5686
  url = new URL(input);
@@ -5377,7 +5721,7 @@ function createPinnedFetch(options = {}) {
5377
5721
  if (failed) return;
5378
5722
  const body = Buffer.concat(chunks).toString("utf8");
5379
5723
  const status = res.statusCode ?? 0;
5380
- resolve3({ ok: status >= 200 && status < 300, status, text: async () => body });
5724
+ resolve4({ ok: status >= 200 && status < 300, status, text: async () => body });
5381
5725
  });
5382
5726
  }
5383
5727
  );
@@ -5863,9 +6207,9 @@ function missingDependencies(root, items) {
5863
6207
  const installCommand = detectInstallCommand(root);
5864
6208
  let pkg;
5865
6209
  try {
5866
- const text = readFileSync6(path17.join(root, "package.json"), "utf8").replace(/^\uFEFF/, "");
6210
+ const text = readFileSync8(path17.join(root, "package.json"), "utf8").replace(/^\uFEFF/, "");
5867
6211
  const parsed = JSON.parse(text);
5868
- pkg = isPlainObject2(parsed) ? parsed : void 0;
6212
+ pkg = isPlainObject(parsed) ? parsed : void 0;
5869
6213
  } catch {
5870
6214
  pkg = void 0;
5871
6215
  }
@@ -5874,7 +6218,7 @@ function missingDependencies(root, items) {
5874
6218
  for (const item of items) {
5875
6219
  for (const dep of item.dependencies) {
5876
6220
  const name = dependencyName(dep);
5877
- if (pkg !== void 0 && hasDependency2(pkg, name) !== void 0) continue;
6221
+ if (pkg !== void 0 && hasDependency(pkg, name) !== void 0) continue;
5878
6222
  if (name in specs) continue;
5879
6223
  const explicit = dep.length > name.length ? dep.slice(name.length + 1) : void 0;
5880
6224
  specs[name] = explicit ?? ranges[name];
@@ -5984,7 +6328,7 @@ async function runAdd(cwd, requested, options, ctx) {
5984
6328
  continue;
5985
6329
  }
5986
6330
  try {
5987
- existing.set(file, readFileSync6(file.target, "utf8"));
6331
+ existing.set(file, readFileSync8(file.target, "utf8"));
5988
6332
  } catch (e) {
5989
6333
  readErrors.push(
5990
6334
  `${file.item.name}: \uAE30\uC874 \uD30C\uC77C ${rel2(root, file.target)} \uC744 \uC77D\uC9C0 \uBABB\uD574 \uBE44\uAD50\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4(${e.code ?? e.message})`