@axis-ds/cli 1.1.4 → 1.2.1

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
@@ -1,13 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  MonetClient
4
- } from "./chunk-WRDOGNSG.js";
4
+ } from "./chunk-ZVVACWEW.js";
5
5
  import {
6
6
  V0Client
7
- } from "./chunk-GCOWKKXG.js";
7
+ } from "./chunk-AHQT77FJ.js";
8
8
  import {
9
9
  registerSyncCommand
10
- } from "./chunk-D26GW2HO.js";
10
+ } from "./chunk-QORBOSUA.js";
11
11
  import {
12
12
  fetchTemplateDetail,
13
13
  fetchTemplateIndex
@@ -15,11 +15,12 @@ import {
15
15
 
16
16
  // src/index.ts
17
17
  import { Command } from "commander";
18
- import chalk8 from "chalk";
18
+ import chalk11 from "chalk";
19
19
  import ora6 from "ora";
20
- import fs9 from "fs-extra";
21
- import path9 from "path";
22
- import prompts2 from "prompts";
20
+ import fs11 from "fs-extra";
21
+ import path12 from "path";
22
+ import { createRequire as createRequire2 } from "module";
23
+ import prompts3 from "prompts";
23
24
 
24
25
  // src/library/base-collector.ts
25
26
  import crypto from "crypto";
@@ -483,11 +484,11 @@ var ShadcnCollector = class extends BaseCollector {
483
484
  /**
484
485
  * 파일 타입 추론
485
486
  */
486
- getFileType(path10) {
487
- if (path10.includes("hook") || path10.startsWith("use")) return "hook";
488
- if (path10.includes("util") || path10.includes("lib")) return "util";
489
- if (path10.endsWith(".css")) return "style";
490
- if (path10.endsWith(".d.ts") || path10.includes("types")) return "type";
487
+ getFileType(path13) {
488
+ if (path13.includes("hook") || path13.startsWith("use")) return "hook";
489
+ if (path13.includes("util") || path13.includes("lib")) return "util";
490
+ if (path13.endsWith(".css")) return "style";
491
+ if (path13.endsWith(".d.ts") || path13.includes("types")) return "type";
491
492
  return "component";
492
493
  }
493
494
  };
@@ -1167,8 +1168,8 @@ var Publisher = class {
1167
1168
  };
1168
1169
  } catch (error) {
1169
1170
  spinner.fail("\uB77C\uC774\uBE0C\uB7EC\uB9AC \uBC30\uCE58 \uC2E4\uD328");
1170
- const errorMessage = error instanceof Error ? error.message : "Unknown error";
1171
- errors.push(errorMessage);
1171
+ const errorMessage2 = error instanceof Error ? error.message : "Unknown error";
1172
+ errors.push(errorMessage2);
1172
1173
  return {
1173
1174
  success: false,
1174
1175
  outputDir,
@@ -1473,7 +1474,7 @@ var LibraryCurator = class {
1473
1474
  const index = await this.loadIndex();
1474
1475
  if (!index) {
1475
1476
  console.log(chalk2.yellow("\n\u26A0\uFE0F \uB77C\uC774\uBE0C\uB7EC\uB9AC \uC778\uB371\uC2A4\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4."));
1476
- console.log(chalk2.gray(" axis-cli library collect \uBA85\uB839\uC5B4\uB85C \uC218\uC9D1\uC744 \uBA3C\uC800 \uC2E4\uD589\uD558\uC138\uC694.\n"));
1477
+ console.log(chalk2.gray(" npx @axis-ds/cli library collect \uBA85\uB839\uC5B4\uB85C \uC218\uC9D1\uC744 \uBA3C\uC800 \uC2E4\uD589\uD558\uC138\uC694.\n"));
1477
1478
  return;
1478
1479
  }
1479
1480
  console.log(chalk2.blue("\n\u{1F4CA} Library Curator - \uD1B5\uACC4\n"));
@@ -1503,7 +1504,7 @@ import chalk7 from "chalk";
1503
1504
  import ora5 from "ora";
1504
1505
 
1505
1506
  // src/template/template-apply.ts
1506
- import fs6 from "fs-extra";
1507
+ import fs7 from "fs-extra";
1507
1508
  import path6 from "path";
1508
1509
  import chalk4 from "chalk";
1509
1510
  import ora3 from "ora";
@@ -1571,6 +1572,29 @@ function deepMerge(target, source) {
1571
1572
  }
1572
1573
  }
1573
1574
 
1575
+ // src/config/axis-config.ts
1576
+ import fs6 from "fs-extra";
1577
+ var AXIS_CONFIG_SCHEMA_URL = "https://axis.minu.best/schema.json";
1578
+ var AXIS_CONFIG_FILE = "axis.config.json";
1579
+ function createInitConfig(answers, registry) {
1580
+ return {
1581
+ $schema: AXIS_CONFIG_SCHEMA_URL,
1582
+ componentsDir: answers.componentsDir,
1583
+ tailwindConfig: answers.tailwindConfig,
1584
+ globalCss: answers.globalCss,
1585
+ registry
1586
+ };
1587
+ }
1588
+ function createTemplateConfig(template) {
1589
+ return {
1590
+ $schema: AXIS_CONFIG_SCHEMA_URL,
1591
+ template,
1592
+ componentsDir: "./components/ui",
1593
+ tailwindConfig: "./tailwind.config.ts",
1594
+ globalCss: "./globals.css"
1595
+ };
1596
+ }
1597
+
1574
1598
  // src/template/template-apply.ts
1575
1599
  async function applyTemplate(slug, options) {
1576
1600
  const spinner = ora3(`'${slug}' \uD15C\uD50C\uB9BF \uAC00\uC838\uC624\uB294 \uC911...`).start();
@@ -1586,7 +1610,7 @@ async function applyTemplate(slug, options) {
1586
1610
  const conflicts = [];
1587
1611
  for (const file of detail.files) {
1588
1612
  const dest = path6.join(baseDir, file.path);
1589
- if (await fs6.pathExists(dest)) {
1613
+ if (await fs7.pathExists(dest)) {
1590
1614
  conflicts.push(file.path);
1591
1615
  }
1592
1616
  }
@@ -1626,8 +1650,8 @@ async function applyTemplate(slug, options) {
1626
1650
  const writeSpinner = ora3("\uD30C\uC77C \uC0DD\uC131 \uC911...").start();
1627
1651
  for (const file of detail.files) {
1628
1652
  const dest = path6.join(baseDir, file.path);
1629
- await fs6.ensureDir(path6.dirname(dest));
1630
- await fs6.writeFile(dest, file.content);
1653
+ await fs7.ensureDir(path6.dirname(dest));
1654
+ await fs7.writeFile(dest, file.content);
1631
1655
  }
1632
1656
  writeSpinner.succeed(`${detail.files.length}\uAC1C \uD30C\uC77C \uC0DD\uC131 \uC644\uB8CC`);
1633
1657
  if (detail.postInstall?.length) {
@@ -1688,8 +1712,8 @@ async function initTemplate(slug, options) {
1688
1712
  targetDir = dir;
1689
1713
  }
1690
1714
  const resolved = path6.resolve(targetDir);
1691
- if (await fs6.pathExists(resolved)) {
1692
- const entries = await fs6.readdir(resolved);
1715
+ if (await fs7.pathExists(resolved)) {
1716
+ const entries = await fs7.readdir(resolved);
1693
1717
  if (entries.length > 0) {
1694
1718
  const { proceed } = await prompts({
1695
1719
  type: "confirm",
@@ -1700,19 +1724,13 @@ async function initTemplate(slug, options) {
1700
1724
  if (!proceed) return;
1701
1725
  }
1702
1726
  } else {
1703
- await fs6.ensureDir(resolved);
1727
+ await fs7.ensureDir(resolved);
1704
1728
  }
1705
1729
  await applyTemplate(selectedSlug, { dir: targetDir, yes: true });
1706
1730
  const configPath = path6.join(resolved, "axis.config.json");
1707
- if (!await fs6.pathExists(configPath)) {
1708
- const axisConfig = {
1709
- $schema: "https://axis.minu.best/schema.json",
1710
- template: selectedSlug,
1711
- componentsDir: "./components/ui",
1712
- tailwindConfig: "./tailwind.config.ts",
1713
- globalCss: "./globals.css"
1714
- };
1715
- await fs6.writeJSON(configPath, axisConfig, { spaces: 2 });
1731
+ if (!await fs7.pathExists(configPath)) {
1732
+ const axisConfig = createTemplateConfig(selectedSlug);
1733
+ await fs7.writeJSON(configPath, axisConfig, { spaces: 2 });
1716
1734
  console.log(chalk4.green("axis.config.json \uC0DD\uC131 \uC644\uB8CC"));
1717
1735
  }
1718
1736
  console.log(chalk4.blue(`
@@ -1723,7 +1741,7 @@ async function initTemplate(slug, options) {
1723
1741
  }
1724
1742
 
1725
1743
  // src/template/template-diff.ts
1726
- import fs7 from "fs-extra";
1744
+ import fs8 from "fs-extra";
1727
1745
  import path7 from "path";
1728
1746
  import chalk5 from "chalk";
1729
1747
  import ora4 from "ora";
@@ -1741,11 +1759,11 @@ async function diffTemplate(slug, options) {
1741
1759
  const entries = [];
1742
1760
  for (const file of detail.files) {
1743
1761
  const localPath = path7.join(baseDir, file.path);
1744
- if (!await fs7.pathExists(localPath)) {
1762
+ if (!await fs8.pathExists(localPath)) {
1745
1763
  entries.push({ path: file.path, status: "added" });
1746
1764
  continue;
1747
1765
  }
1748
- const localContent = await fs7.readFile(localPath, "utf-8");
1766
+ const localContent = await fs8.readFile(localPath, "utf-8");
1749
1767
  if (localContent === file.content) {
1750
1768
  entries.push({ path: file.path, status: "unchanged" });
1751
1769
  } else {
@@ -1815,7 +1833,7 @@ async function collectLocalFiles(dir, base) {
1815
1833
  const results = [];
1816
1834
  let entries;
1817
1835
  try {
1818
- entries = await fs7.readdir(dir, { withFileTypes: true });
1836
+ entries = await fs8.readdir(dir, { withFileTypes: true });
1819
1837
  } catch {
1820
1838
  return results;
1821
1839
  }
@@ -1833,15 +1851,261 @@ async function collectLocalFiles(dir, base) {
1833
1851
  }
1834
1852
 
1835
1853
  // src/template/template-check.ts
1836
- import fs8 from "fs-extra";
1854
+ import fs9 from "fs-extra";
1837
1855
  import path8 from "path";
1838
1856
  import chalk6 from "chalk";
1857
+
1858
+ // src/theme/brand-core.ts
1859
+ import { existsSync, readFileSync, statSync } from "fs";
1860
+ import { createRequire } from "module";
1861
+ import { dirname, join, relative, resolve, sep } from "path";
1862
+ var TOKENS_PACKAGE = "@axis-ds/tokens";
1863
+ var BRAND_NAME_PATTERN = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/;
1864
+ var MIN_BRAND_TOKENS_VERSION = "1.3.0";
1865
+ var KEY_TOKENS = [
1866
+ "--primary",
1867
+ "--primary-foreground",
1868
+ "--background",
1869
+ "--foreground",
1870
+ "--ring",
1871
+ "--radius",
1872
+ "--axis-surface-default",
1873
+ "--axis-text-primary",
1874
+ "--axis-text-brand",
1875
+ "--axis-button-bg-default",
1876
+ "--axis-border-focus",
1877
+ "--axis-font-family-sans"
1878
+ ];
1879
+ var BRAND_ADJUSTMENT_REFERENCE = "WI-0025 PRD \uBD80\uB85D B (docs/workitems/WI-0025-brand-theme/prd.md)";
1880
+ function readJsonFile(file) {
1881
+ return JSON.parse(readFileSync(file, "utf8"));
1882
+ }
1883
+ function errorCode(err) {
1884
+ return typeof err === "object" && err !== null && "code" in err ? String(err.code) : void 0;
1885
+ }
1886
+ function findTokensPackageJson(baseDir) {
1887
+ let dir = resolve(baseDir);
1888
+ for (; ; ) {
1889
+ const candidate = join(dir, "node_modules", TOKENS_PACKAGE, "package.json");
1890
+ if (existsSync(candidate)) return candidate;
1891
+ const parent = dirname(dir);
1892
+ if (parent === dir) return void 0;
1893
+ dir = parent;
1894
+ }
1895
+ }
1896
+ function projectRequire(baseDir) {
1897
+ return createRequire(join(resolve(baseDir), "package.json"));
1898
+ }
1899
+ function tokensSpecifier(subpath) {
1900
+ return `${TOKENS_PACKAGE}/${subpath.replace(/^\.\//, "")}`;
1901
+ }
1902
+ function resolveTokens(baseDir) {
1903
+ const pkgJson = findTokensPackageJson(baseDir);
1904
+ if (!pkgJson) return { status: "not-installed" };
1905
+ const pkg = readJsonFile(pkgJson);
1906
+ const version = typeof pkg.version === "string" ? pkg.version : void 0;
1907
+ try {
1908
+ const indexPath = projectRequire(baseDir).resolve(tokensSpecifier("./brands"));
1909
+ return { status: "ok", version, indexPath };
1910
+ } catch (err) {
1911
+ const code = errorCode(err);
1912
+ if (code === "ERR_PACKAGE_PATH_NOT_EXPORTED") return { status: "unsupported", version };
1913
+ if (code === "MODULE_NOT_FOUND") return { status: "not-built", version };
1914
+ throw err;
1915
+ }
1916
+ }
1917
+ function brandImportPath(entry) {
1918
+ return tokensSpecifier(entry.css);
1919
+ }
1920
+ var GLOBAL_CSS_CANDIDATES = ["app/globals.css", "src/app/globals.css", "globals.css"];
1921
+ function isFile(file) {
1922
+ try {
1923
+ return statSync(file).isFile();
1924
+ } catch {
1925
+ return false;
1926
+ }
1927
+ }
1928
+ function findGlobalCss(baseDir, config) {
1929
+ const root = resolve(baseDir);
1930
+ const result = {};
1931
+ const configured = config?.globalCss;
1932
+ if (typeof configured === "string" && configured.trim() !== "") {
1933
+ const file = resolve(root, configured);
1934
+ if (isFile(file)) return { path: file };
1935
+ result.configuredMissing = configured;
1936
+ }
1937
+ for (const candidate of GLOBAL_CSS_CANDIDATES) {
1938
+ const file = join(root, candidate);
1939
+ if (isFile(file)) {
1940
+ result.path = file;
1941
+ break;
1942
+ }
1943
+ }
1944
+ return result;
1945
+ }
1946
+ function findBrandImports(css) {
1947
+ const names = [];
1948
+ const pattern = /@import\s+(?:url\(\s*)?["']?@axis-ds\/tokens\/css\/brands\/([a-z][a-z0-9-]*)(?:\.css)?["']?\s*\)?\s*(?=[;\s]|$)/g;
1949
+ for (const m of stripComments(css).matchAll(pattern)) {
1950
+ names.push(m[1]);
1951
+ }
1952
+ return names;
1953
+ }
1954
+ var AXIS_CONFIG_FILE_NAME = "axis.config.json";
1955
+ function readBrandConfig(baseDir) {
1956
+ let parsed;
1957
+ try {
1958
+ parsed = JSON.parse(readFileSync(join(resolve(baseDir), AXIS_CONFIG_FILE_NAME), "utf8"));
1959
+ } catch {
1960
+ return null;
1961
+ }
1962
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return null;
1963
+ return parsed;
1964
+ }
1965
+ function inspectBrandImport(baseDir) {
1966
+ const config = readBrandConfig(baseDir);
1967
+ const brand = config?.brand;
1968
+ if (typeof brand !== "string" || brand.trim() === "") return null;
1969
+ const root = resolve(baseDir);
1970
+ const location = findGlobalCss(root, config);
1971
+ const base = { brand };
1972
+ if (location.configuredMissing !== void 0) base.configuredMissing = location.configuredMissing;
1973
+ if (!location.path) {
1974
+ return { ...base, state: "css-missing", imports: [] };
1975
+ }
1976
+ const cssFile = relative(root, location.path).split(sep).join("/");
1977
+ const imports = [...new Set(findBrandImports(readFileSync(location.path, "utf8")))];
1978
+ let state;
1979
+ if (imports.includes(brand)) state = "match";
1980
+ else if (imports.length === 0) state = "import-missing";
1981
+ else state = "other-brand";
1982
+ return { ...base, state, cssFile, imports };
1983
+ }
1984
+ function isMissingBuildFile(err) {
1985
+ const code = errorCode(err);
1986
+ return code === "MODULE_NOT_FOUND" || code === "ENOENT";
1987
+ }
1988
+ function readBrandIndex(indexPath) {
1989
+ const data = readJsonFile(indexPath);
1990
+ if (!Array.isArray(data.brands)) {
1991
+ throw new Error(`${indexPath}: "brands" \uBC30\uC5F4\uC774 \uC5C6\uC2B5\uB2C8\uB2E4`);
1992
+ }
1993
+ return data.brands;
1994
+ }
1995
+ function readSummary(baseDir, entry) {
1996
+ const metaPath = projectRequire(baseDir).resolve(tokensSpecifier(entry.meta));
1997
+ const meta = readJsonFile(metaPath);
1998
+ return {
1999
+ name: entry.name,
2000
+ description: typeof meta.description === "string" ? meta.description : "",
2001
+ themes: Array.isArray(meta.themes) ? meta.themes.map(String) : [],
2002
+ a11y: typeof meta.a11y === "object" && meta.a11y !== null ? meta.a11y : {},
2003
+ importPath: brandImportPath(entry)
2004
+ };
2005
+ }
2006
+ function listBrands(baseDir) {
2007
+ const tokens = resolveTokens(baseDir);
2008
+ if (tokens.status !== "ok" || !tokens.indexPath) {
2009
+ return { status: tokens.status, version: tokens.version, brands: [] };
2010
+ }
2011
+ const entries = readBrandIndex(tokens.indexPath);
2012
+ let brands;
2013
+ try {
2014
+ brands = entries.map((entry) => readSummary(baseDir, entry));
2015
+ } catch (err) {
2016
+ if (isMissingBuildFile(err)) return { status: "not-built", version: tokens.version, brands: [] };
2017
+ throw err;
2018
+ }
2019
+ return { status: "ok", version: tokens.version, brands };
2020
+ }
2021
+ function stripComments(css) {
2022
+ return css.replace(/\/\*[\s\S]*?\*\//g, "");
2023
+ }
2024
+ function parseDeclarations(body) {
2025
+ const out = {};
2026
+ for (const m of body.matchAll(/(--[A-Za-z0-9_-]+)\s*:\s*([^;]+);/g)) {
2027
+ out[m[1]] = m[2].trim();
2028
+ }
2029
+ return out;
2030
+ }
2031
+ function isDarkSelector(selector) {
2032
+ return /\.dark\b/.test(selector) || /\[data-theme=["']?dark["']?\]/.test(selector);
2033
+ }
2034
+ function parseBrandCss(css, name) {
2035
+ const result = { light: {}, dark: {} };
2036
+ let lightFound = false;
2037
+ let darkFound = false;
2038
+ const brandAttr = new RegExp(`\\[data-brand=["']?${name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}["']?\\]`);
2039
+ for (const m of stripComments(css).matchAll(/([^{}]+)\{([^{}]*)\}/g)) {
2040
+ const selectors = m[1].split(",").map((s) => s.trim());
2041
+ if (!selectors.some((s) => brandAttr.test(s))) continue;
2042
+ if (selectors.some(isDarkSelector)) {
2043
+ if (!darkFound) {
2044
+ result.dark = parseDeclarations(m[2]);
2045
+ darkFound = true;
2046
+ }
2047
+ } else if (!lightFound) {
2048
+ result.light = parseDeclarations(m[2]);
2049
+ lightFound = true;
2050
+ }
2051
+ }
2052
+ return result;
2053
+ }
2054
+ function pickKeyTokens(decls) {
2055
+ const out = {};
2056
+ for (const key of KEY_TOKENS) {
2057
+ if (Object.prototype.hasOwnProperty.call(decls, key)) out[key] = decls[key];
2058
+ }
2059
+ return out;
2060
+ }
2061
+ function providerExample(name) {
2062
+ return [
2063
+ 'import { ThemeProvider } from "@axis-ds/theme";',
2064
+ "",
2065
+ `<ThemeProvider defaultBrand="${name}">{children}</ThemeProvider>`
2066
+ ].join("\n");
2067
+ }
2068
+ function getBrand(baseDir, name) {
2069
+ const tokens = resolveTokens(baseDir);
2070
+ if (tokens.status !== "ok" || !tokens.indexPath) {
2071
+ return { status: tokens.status, version: tokens.version, brand: null, available: [] };
2072
+ }
2073
+ const entries = readBrandIndex(tokens.indexPath);
2074
+ const available = entries.map((e) => e.name);
2075
+ const entry = entries.find((e) => e.name === name);
2076
+ if (!entry) {
2077
+ return { status: "ok", version: tokens.version, brand: null, available };
2078
+ }
2079
+ let summary;
2080
+ let parsed;
2081
+ try {
2082
+ summary = readSummary(baseDir, entry);
2083
+ const cssPath = projectRequire(baseDir).resolve(summary.importPath);
2084
+ parsed = parseBrandCss(readFileSync(cssPath, "utf8"), name);
2085
+ } catch (err) {
2086
+ if (isMissingBuildFile(err)) return { status: "not-built", version: tokens.version, brand: null, available: [] };
2087
+ throw err;
2088
+ }
2089
+ return {
2090
+ status: "ok",
2091
+ version: tokens.version,
2092
+ available,
2093
+ brand: {
2094
+ ...summary,
2095
+ tokens: { light: pickKeyTokens(parsed.light), dark: pickKeyTokens(parsed.dark) },
2096
+ providerExample: providerExample(name),
2097
+ adjustments: { a11y: summary.a11y, reference: BRAND_ADJUSTMENT_REFERENCE }
2098
+ }
2099
+ };
2100
+ }
2101
+
2102
+ // src/template/template-check.ts
1839
2103
  var SEVERITY_ICON = {
1840
2104
  pass: chalk6.green("PASS"),
1841
2105
  warn: chalk6.yellow("WARN"),
1842
2106
  fail: chalk6.red("FAIL")
1843
2107
  };
1844
- async function runCheck(dir) {
2108
+ async function collectCheckResults(dir) {
1845
2109
  const baseDir = path8.resolve(dir || ".");
1846
2110
  const results = [];
1847
2111
  results.push(await checkFileExists(baseDir, "axis.config.json", "axis.config.json"));
@@ -1849,6 +2113,12 @@ async function runCheck(dir) {
1849
2113
  results.push(await checkGlobalsCss(baseDir));
1850
2114
  results.push(await checkUtils(baseDir));
1851
2115
  results.push(await checkDependencies(baseDir));
2116
+ const brand = checkBrand(baseDir);
2117
+ if (brand) results.push(brand);
2118
+ return results;
2119
+ }
2120
+ async function runCheck(dir) {
2121
+ const results = await collectCheckResults(dir);
1852
2122
  console.log(chalk6.blue("\nAXIS \uD504\uB85C\uC81D\uD2B8 \uAC80\uC99D \uACB0\uACFC:\n"));
1853
2123
  let passCount = 0;
1854
2124
  let warnCount = 0;
@@ -1880,7 +2150,7 @@ async function runCheck(dir) {
1880
2150
  }
1881
2151
  }
1882
2152
  async function checkFileExists(baseDir, fileName, label) {
1883
- const exists = await fs8.pathExists(path8.join(baseDir, fileName));
2153
+ const exists = await fs9.pathExists(path8.join(baseDir, fileName));
1884
2154
  return {
1885
2155
  name: label,
1886
2156
  severity: exists ? "pass" : "fail",
@@ -1890,8 +2160,8 @@ async function checkFileExists(baseDir, fileName, label) {
1890
2160
  async function checkTailwindConfig(baseDir) {
1891
2161
  const tsPath = path8.join(baseDir, "tailwind.config.ts");
1892
2162
  const jsPath = path8.join(baseDir, "tailwind.config.js");
1893
- if (await fs8.pathExists(tsPath)) {
1894
- const content = await fs8.readFile(tsPath, "utf-8");
2163
+ if (await fs9.pathExists(tsPath)) {
2164
+ const content = await fs9.readFile(tsPath, "utf-8");
1895
2165
  const hasTokens = content.includes("--background") || content.includes("hsl(var(");
1896
2166
  return {
1897
2167
  name: "tailwind.config",
@@ -1899,7 +2169,7 @@ async function checkTailwindConfig(baseDir) {
1899
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"
1900
2170
  };
1901
2171
  }
1902
- if (await fs8.pathExists(jsPath)) {
2172
+ if (await fs9.pathExists(jsPath)) {
1903
2173
  return {
1904
2174
  name: "tailwind.config",
1905
2175
  severity: "warn",
@@ -1922,8 +2192,8 @@ async function checkGlobalsCss(baseDir) {
1922
2192
  ];
1923
2193
  for (const candidate of candidates) {
1924
2194
  const fullPath = path8.join(baseDir, candidate);
1925
- if (await fs8.pathExists(fullPath)) {
1926
- const content = await fs8.readFile(fullPath, "utf-8");
2195
+ if (await fs9.pathExists(fullPath)) {
2196
+ const content = await fs9.readFile(fullPath, "utf-8");
1927
2197
  const hasTokens = content.includes("--background") && content.includes("--primary");
1928
2198
  return {
1929
2199
  name: "globals.css",
@@ -1948,8 +2218,8 @@ async function checkUtils(baseDir) {
1948
2218
  ];
1949
2219
  for (const candidate of candidates) {
1950
2220
  const fullPath = path8.join(baseDir, candidate);
1951
- if (await fs8.pathExists(fullPath)) {
1952
- const content = await fs8.readFile(fullPath, "utf-8");
2221
+ if (await fs9.pathExists(fullPath)) {
2222
+ const content = await fs9.readFile(fullPath, "utf-8");
1953
2223
  const hasCn = content.includes("function cn");
1954
2224
  return {
1955
2225
  name: "utils.ts",
@@ -1966,14 +2236,14 @@ async function checkUtils(baseDir) {
1966
2236
  }
1967
2237
  async function checkDependencies(baseDir) {
1968
2238
  const pkgPath = path8.join(baseDir, "package.json");
1969
- if (!await fs8.pathExists(pkgPath)) {
2239
+ if (!await fs9.pathExists(pkgPath)) {
1970
2240
  return {
1971
2241
  name: "package.json",
1972
2242
  severity: "fail",
1973
2243
  message: "package.json \uD30C\uC77C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4"
1974
2244
  };
1975
2245
  }
1976
- const pkg = await fs8.readJSON(pkgPath);
2246
+ const pkg = await fs9.readJSON(pkgPath);
1977
2247
  const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
1978
2248
  const required = ["tailwindcss"];
1979
2249
  const recommended = ["clsx", "tailwind-merge"];
@@ -1999,6 +2269,40 @@ async function checkDependencies(baseDir) {
1999
2269
  message: "\uD544\uC218 \uBC0F \uAD8C\uC7A5 \uC758\uC874\uC131\uC774 \uBAA8\uB450 \uC124\uCE58\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4"
2000
2270
  };
2001
2271
  }
2272
+ function checkBrand(baseDir) {
2273
+ const check = inspectBrandImport(baseDir);
2274
+ return check ? brandCheckResult(check) : null;
2275
+ }
2276
+ function brandCheckResult(check) {
2277
+ const { brand } = check;
2278
+ const suffix = check.configuredMissing !== void 0 ? ` (globalCss ${check.configuredMissing} \uC5C6\uC74C)` : "";
2279
+ switch (check.state) {
2280
+ case "match":
2281
+ return {
2282
+ name: "brand",
2283
+ severity: "pass",
2284
+ message: `brand "${brand}" import \uAC00 ${check.cssFile}\uC5D0 \uC788\uC2B5\uB2C8\uB2E4${suffix}`
2285
+ };
2286
+ case "css-missing":
2287
+ return {
2288
+ name: "brand",
2289
+ severity: "warn",
2290
+ message: `brand "${brand}" \uAC00 \uC124\uC815\uB410\uC9C0\uB9CC CSS \uD30C\uC77C\uC744 \uCC3E\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4${suffix}`
2291
+ };
2292
+ case "import-missing":
2293
+ return {
2294
+ name: "brand",
2295
+ severity: "warn",
2296
+ message: `brand "${brand}" import \uAC00 ${check.cssFile}\uC5D0 \uC5C6\uC2B5\uB2C8\uB2E4 \u2192 'axis theme add ${brand}'${suffix}`
2297
+ };
2298
+ case "other-brand":
2299
+ return {
2300
+ name: "brand",
2301
+ severity: "warn",
2302
+ message: `brand "${brand}" \uC640 import(${check.imports.join(", ")})\uAC00 \uB2E4\uB985\uB2C8\uB2E4${suffix}`
2303
+ };
2304
+ }
2305
+ }
2002
2306
 
2003
2307
  // src/template/index.ts
2004
2308
  function registerTemplateCommand(program2) {
@@ -2102,72 +2406,936 @@ function registerCheckCommand(program2) {
2102
2406
  });
2103
2407
  }
2104
2408
 
2105
- // src/index.ts
2106
- var REGISTRY_URL = process.env.AXIS_REGISTRY_URL || "https://axis.minu.best/r";
2107
- var program = new Command();
2108
- program.name("axis").description("AXIS Design System CLI - shadcn \uD638\uD658 \uCEF4\uD3EC\uB10C\uD2B8 \uC124\uCE58 \uB3C4\uAD6C").version("0.1.0");
2109
- program.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) => {
2110
- console.log(chalk8.blue("\n\u{1F3A8} AXIS Design System \uCD08\uAE30\uD654\n"));
2111
- const config = options.yes ? {
2112
- componentsDir: "./src/components/ui",
2113
- tailwindConfig: "./tailwind.config.ts",
2114
- globalCss: "./src/app/globals.css"
2115
- } : await prompts2([
2116
- {
2117
- type: "text",
2118
- name: "componentsDir",
2119
- message: "\uCEF4\uD3EC\uB10C\uD2B8 \uB514\uB809\uD1A0\uB9AC:",
2120
- initial: "./src/components/ui"
2121
- },
2122
- {
2123
- type: "text",
2124
- name: "tailwindConfig",
2125
- message: "Tailwind \uC124\uC815 \uD30C\uC77C:",
2126
- initial: "./tailwind.config.ts"
2127
- },
2128
- {
2129
- type: "text",
2130
- name: "globalCss",
2131
- message: "\uAE00\uB85C\uBC8C CSS \uD30C\uC77C:",
2132
- initial: "./src/app/globals.css"
2133
- }
2134
- ]);
2135
- const axisConfig = {
2136
- $schema: "https://axis.minu.best/schema.json",
2137
- componentsDir: config.componentsDir,
2138
- tailwindConfig: config.tailwindConfig,
2139
- globalCss: config.globalCss,
2140
- registry: REGISTRY_URL
2409
+ // src/theme/index.ts
2410
+ import chalk8 from "chalk";
2411
+ import path10 from "path";
2412
+
2413
+ // src/theme/theme-add.ts
2414
+ import { accessSync, constants, existsSync as existsSync2, readFileSync as readFileSync2, realpathSync, unlinkSync, writeFileSync } from "fs";
2415
+ import path9 from "path";
2416
+ var TOKENS_DEPENDENCY_RANGE = `^${MIN_BRAND_TOKENS_VERSION}`;
2417
+ var THEME_PACKAGE = "@axis-ds/theme";
2418
+ function readText(file) {
2419
+ return existsSync2(file) ? readFileSync2(file, "utf8") : null;
2420
+ }
2421
+ function eolOf(text) {
2422
+ return text.includes("\r\n") ? "\r\n" : "\n";
2423
+ }
2424
+ function indentOf(text) {
2425
+ const m = /\n([ \t]+)\S/.exec(text);
2426
+ if (!m) return 2;
2427
+ return m[1].includes(" ") ? " " : m[1].length;
2428
+ }
2429
+ function formatJsonLike(original, value) {
2430
+ const eol = eolOf(original);
2431
+ const endsWithNewline = /\r?\n$/.test(original);
2432
+ let out = JSON.stringify(value, null, indentOf(original));
2433
+ if (eol === "\r\n") out = out.replace(/\n/g, "\r\n");
2434
+ return endsWithNewline ? out + eol : out;
2435
+ }
2436
+ function insertImportLine(css, line) {
2437
+ const bom = css.startsWith("\uFEFF") ? "\uFEFF" : "";
2438
+ const body = bom ? css.slice(1) : css;
2439
+ const eol = eolOf(body);
2440
+ const lines = body.split(/\r?\n/);
2441
+ let insertAt = 0;
2442
+ let inComment = false;
2443
+ for (let i = 0; i < lines.length; i++) {
2444
+ let rest = lines[i].trim();
2445
+ if (inComment) {
2446
+ const end = rest.indexOf("*/");
2447
+ if (end === -1) continue;
2448
+ inComment = false;
2449
+ rest = rest.slice(end + 2).trim();
2450
+ }
2451
+ while (rest.startsWith("/*")) {
2452
+ const end = rest.indexOf("*/", 2);
2453
+ if (end === -1) {
2454
+ inComment = true;
2455
+ rest = "";
2456
+ break;
2457
+ }
2458
+ rest = rest.slice(end + 2).trim();
2459
+ }
2460
+ if (rest === "") continue;
2461
+ if (/^@(charset|import)\b/i.test(rest)) {
2462
+ insertAt = i + 1;
2463
+ continue;
2464
+ }
2465
+ break;
2466
+ }
2467
+ lines.splice(insertAt, 0, line);
2468
+ return bom + lines.join(eol);
2469
+ }
2470
+ function compareVersions(a, b) {
2471
+ const parse = (v) => {
2472
+ const m = /^(\d+)\.(\d+)\.(\d+)(-.+)?$/.exec(v.trim());
2473
+ return m ? { nums: [Number(m[1]), Number(m[2]), Number(m[3])], pre: Boolean(m[4]) } : void 0;
2474
+ };
2475
+ const pa = parse(a);
2476
+ const pb = parse(b);
2477
+ if (!pa || !pb) return void 0;
2478
+ for (let i = 0; i < 3; i++) {
2479
+ if (pa.nums[i] !== pb.nums[i]) return pa.nums[i] < pb.nums[i] ? -1 : 1;
2480
+ }
2481
+ if (pa.pre !== pb.pre) return pa.pre ? -1 : 1;
2482
+ return 0;
2483
+ }
2484
+ function realPathInside(baseDir, file) {
2485
+ const realBase = realpathSync(baseDir);
2486
+ const realPath = realpathSync(file);
2487
+ const relPath = path9.relative(realBase, realPath);
2488
+ const inside = relPath !== "" && !relPath.startsWith("..") && !path9.isAbsolute(relPath);
2489
+ return { inside, realPath };
2490
+ }
2491
+ function isStylesheet(realPath) {
2492
+ return path9.extname(realPath).toLowerCase() === ".css";
2493
+ }
2494
+ 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";
2498
+ return "pnpm install";
2499
+ }
2500
+ function hasDependency(pkg, name) {
2501
+ for (const field of ["dependencies", "devDependencies"]) {
2502
+ const deps = pkg[field];
2503
+ if (typeof deps === "object" && deps !== null && name in deps) {
2504
+ return String(deps[name]);
2505
+ }
2506
+ }
2507
+ return void 0;
2508
+ }
2509
+ function isPlainObject(value) {
2510
+ return typeof value === "object" && value !== null && !Array.isArray(value);
2511
+ }
2512
+ function planThemeAdd(baseDirInput, brand) {
2513
+ const baseDir = path9.resolve(baseDirInput);
2514
+ const plan = {
2515
+ baseDir,
2516
+ brand,
2517
+ importPath: brandImportPath({ css: `./css/brands/${brand}` }),
2518
+ tokens: { status: "not-installed" },
2519
+ errors: [],
2520
+ unverifiedBrand: false,
2521
+ configChanged: false,
2522
+ installCommand: detectInstallCommand(baseDir),
2523
+ writes: []
2141
2524
  };
2142
- await fs9.writeJSON("axis.config.json", axisConfig, { spaces: 2 });
2143
- console.log(chalk8.green("\u2713 axis.config.json \uC0DD\uC131 \uC644\uB8CC"));
2144
- const utilsPath = path9.join(config.componentsDir, "utils.ts");
2145
- await fs9.ensureDir(path9.dirname(utilsPath));
2146
- await fs9.writeFile(
2147
- utilsPath,
2148
- `import { type ClassValue, clsx } from "clsx";
2525
+ const configFile = path9.join(baseDir, AXIS_CONFIG_FILE);
2526
+ const configText = readText(configFile);
2527
+ if (configText === null) {
2528
+ plan.errors.push({ kind: "no-config" });
2529
+ return plan;
2530
+ }
2531
+ let config;
2532
+ try {
2533
+ const parsed = JSON.parse(configText);
2534
+ if (!isPlainObject(parsed)) throw new Error("\uCD5C\uC0C1\uC704\uAC00 \uAC1D\uCCB4\uAC00 \uC544\uB2D9\uB2C8\uB2E4");
2535
+ config = parsed;
2536
+ } catch (err) {
2537
+ plan.errors.push({ kind: "invalid-config", message: err.message });
2538
+ return plan;
2539
+ }
2540
+ if (!BRAND_NAME_PATTERN.test(brand)) {
2541
+ plan.errors.push({ kind: "invalid-name", brand });
2542
+ return plan;
2543
+ }
2544
+ plan.tokens = resolveTokens(baseDir);
2545
+ if (plan.tokens.status === "ok" && plan.tokens.indexPath) {
2546
+ const data = JSON.parse(readFileSync2(plan.tokens.indexPath, "utf8"));
2547
+ const entries = Array.isArray(data.brands) ? data.brands : [];
2548
+ const entry = entries.find((e) => e.name === brand);
2549
+ if (!entry) {
2550
+ plan.errors.push({
2551
+ kind: "unknown-brand",
2552
+ brand,
2553
+ available: entries.map((e) => e.name),
2554
+ version: plan.tokens.version
2555
+ });
2556
+ return plan;
2557
+ }
2558
+ plan.importPath = brandImportPath(entry);
2559
+ } else {
2560
+ plan.unverifiedBrand = true;
2561
+ }
2562
+ const location = findGlobalCss(baseDir, config);
2563
+ if (location.path) {
2564
+ const where = realPathInside(baseDir, location.path);
2565
+ if (!where.inside) {
2566
+ plan.errors.push({ kind: "css-outside-project", file: location.path, realPath: where.realPath });
2567
+ plan.writes = [];
2568
+ return plan;
2569
+ }
2570
+ if (!isStylesheet(where.realPath)) {
2571
+ plan.errors.push({ kind: "css-not-stylesheet", file: location.path, realPath: where.realPath });
2572
+ plan.writes = [];
2573
+ return plan;
2574
+ }
2575
+ const before = readFileSync2(location.path, "utf8");
2576
+ const imported = findBrandImports(before);
2577
+ const otherBrands = [...new Set(imported.filter((n) => n !== brand))];
2578
+ if (imported.includes(brand)) {
2579
+ plan.css = { file: location.path, configuredMissing: location.configuredMissing, action: "exists", otherBrands };
2580
+ } else {
2581
+ plan.css = { file: location.path, configuredMissing: location.configuredMissing, action: "add", otherBrands };
2582
+ plan.writes.push({
2583
+ file: location.path,
2584
+ before,
2585
+ after: insertImportLine(before, `@import "${plan.importPath}";`)
2586
+ });
2587
+ }
2588
+ } else {
2589
+ plan.css = { configuredMissing: location.configuredMissing, action: "manual", otherBrands: [] };
2590
+ }
2591
+ const pkgFile = path9.join(baseDir, "package.json");
2592
+ const pkgText = readText(pkgFile);
2593
+ const installed = plan.tokens.version;
2594
+ const upgrade = installed !== void 0 && (compareVersions(installed, MIN_BRAND_TOKENS_VERSION) ?? 0) < 0;
2595
+ if (pkgText === null) {
2596
+ plan.dependency = { action: "no-package-json", upgrade, themeMissing: false };
2597
+ } else {
2598
+ let pkg;
2599
+ try {
2600
+ const parsed = JSON.parse(pkgText);
2601
+ if (!isPlainObject(parsed)) throw new Error("\uCD5C\uC0C1\uC704\uAC00 \uAC1D\uCCB4\uAC00 \uC544\uB2D9\uB2C8\uB2E4");
2602
+ pkg = parsed;
2603
+ } catch (err) {
2604
+ plan.errors.push({ kind: "invalid-package-json", message: err.message });
2605
+ plan.writes = [];
2606
+ return plan;
2607
+ }
2608
+ const themeMissing = hasDependency(pkg, THEME_PACKAGE) === void 0;
2609
+ const declared = hasDependency(pkg, TOKENS_PACKAGE);
2610
+ if (declared !== void 0) {
2611
+ plan.dependency = { action: "present", declaredRange: declared, upgrade, themeMissing };
2612
+ } else {
2613
+ const deps = isPlainObject(pkg.dependencies) ? { ...pkg.dependencies } : {};
2614
+ deps[TOKENS_PACKAGE] = TOKENS_DEPENDENCY_RANGE;
2615
+ const next = { ...pkg, dependencies: deps };
2616
+ plan.dependency = { action: "add", upgrade, themeMissing };
2617
+ plan.writes.push({ file: pkgFile, before: pkgText, after: formatJsonLike(pkgText, next) });
2618
+ }
2619
+ }
2620
+ if (config.brand !== brand) {
2621
+ plan.configChanged = true;
2622
+ plan.writes.push({
2623
+ file: configFile,
2624
+ before: configText,
2625
+ after: formatJsonLike(configText, { ...config, brand })
2626
+ });
2627
+ }
2628
+ return plan;
2629
+ }
2630
+ var ThemeApplyError = class extends Error {
2631
+ constructor(message, failedFile, restored, restoreFailed) {
2632
+ super(message);
2633
+ this.failedFile = failedFile;
2634
+ this.restored = restored;
2635
+ this.restoreFailed = restoreFailed;
2636
+ this.name = "ThemeApplyError";
2637
+ }
2638
+ };
2639
+ function errorMessage(err) {
2640
+ return err instanceof Error ? err.message : String(err);
2641
+ }
2642
+ function applyThemeAdd(plan) {
2643
+ if (plan.errors.length > 0) {
2644
+ throw new Error("\uC624\uB958\uAC00 \uC788\uB294 \uACC4\uD68D\uC740 \uC801\uC6A9\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4");
2645
+ }
2646
+ for (const w of plan.writes) {
2647
+ const current = readText(w.file);
2648
+ if (current !== w.before) {
2649
+ throw new Error(`${w.file} \uC774 \uACC4\uD68D \uB4A4\uC5D0 \uBC14\uB00C\uC5C8\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694.`);
2650
+ }
2651
+ const where = realPathInside(plan.baseDir, w.before === null ? path9.dirname(w.file) : w.file);
2652
+ if (!where.inside && !(w.before === null && path9.dirname(w.file) === plan.baseDir)) {
2653
+ throw new Error(`${w.file} \uC758 \uC2E4\uC81C \uC704\uCE58(${where.realPath})\uAC00 \uD504\uB85C\uC81D\uD2B8 \uB514\uB809\uD130\uB9AC \uBC16\uC785\uB2C8\uB2E4. \uC544\uBB34\uAC83\uB3C4 \uC4F0\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.`);
2654
+ }
2655
+ if (!w.file.endsWith(".json") && !isStylesheet(where.realPath)) {
2656
+ throw new Error(`${w.file} \uC758 \uC2E4\uC81C \uB300\uC0C1(${where.realPath})\uC774 CSS \uD30C\uC77C\uC774 \uC544\uB2D9\uB2C8\uB2E4. \uC544\uBB34\uAC83\uB3C4 \uC4F0\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.`);
2657
+ }
2658
+ if (w.file.endsWith(".json")) {
2659
+ JSON.parse(w.after);
2660
+ } else if (findBrandImports(w.after).filter((n) => n === plan.brand).length !== 1) {
2661
+ throw new Error(`${w.file}: \uBE0C\uB79C\uB4DC import \uAC00 \uC815\uD655\uD788 1\uC904\uC774 \uC544\uB2D9\uB2C8\uB2E4`);
2662
+ }
2663
+ try {
2664
+ accessSync(w.before === null ? path9.dirname(w.file) : w.file, constants.W_OK);
2665
+ } catch (err) {
2666
+ throw new Error(`${w.file} \uC5D0 \uC4F8 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4(${errorMessage(err)}).`);
2667
+ }
2668
+ }
2669
+ const done = [];
2670
+ for (const w of plan.writes) {
2671
+ try {
2672
+ writeFileSync(w.file, w.after);
2673
+ done.push(w);
2674
+ } catch (err) {
2675
+ const restored = [];
2676
+ const restoreFailed = [];
2677
+ for (const d of done.reverse()) {
2678
+ try {
2679
+ if (d.before === null) unlinkSync(d.file);
2680
+ else writeFileSync(d.file, d.before);
2681
+ restored.push(d.file);
2682
+ } catch {
2683
+ restoreFailed.push(d.file);
2684
+ }
2685
+ }
2686
+ throw new ThemeApplyError(
2687
+ `${w.file} \uB97C \uC4F0\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4(${errorMessage(err)}).`,
2688
+ w.file,
2689
+ restored,
2690
+ restoreFailed
2691
+ );
2692
+ }
2693
+ }
2694
+ return done.map((w) => w.file);
2695
+ }
2696
+
2697
+ // src/theme/index.ts
2698
+ var TOKENS_INSTALL_COMMAND = `pnpm add ${TOKENS_PACKAGE}@^${MIN_BRAND_TOKENS_VERSION}`;
2699
+ function tokensStatusGuide(status, version) {
2700
+ switch (status) {
2701
+ case "not-installed":
2702
+ return [
2703
+ chalk8.yellow(`${TOKENS_PACKAGE} \uAC00 \uC124\uCE58\uB3FC \uC788\uC9C0 \uC54A\uC544 \uBE0C\uB79C\uB4DC\uB97C \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.`),
2704
+ ` \uC124\uCE58: ${chalk8.cyan(TOKENS_INSTALL_COMMAND)}`
2705
+ ];
2706
+ case "unsupported":
2707
+ return [
2708
+ chalk8.yellow(
2709
+ `${TOKENS_PACKAGE} ${version ?? "(\uBC84\uC804 \uBAA8\uB984)"} \uC740 \uBE0C\uB79C\uB4DC\uB97C \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4(${MIN_BRAND_TOKENS_VERSION} \uC774\uC0C1 \uD544\uC694).`
2710
+ ),
2711
+ ` \uC5C5\uADF8\uB808\uC774\uB4DC: ${chalk8.cyan(TOKENS_INSTALL_COMMAND)}`
2712
+ ];
2713
+ case "not-built":
2714
+ return [
2715
+ chalk8.yellow(
2716
+ `${TOKENS_PACKAGE}${version ? ` ${version}` : ""} \uB294 \uC788\uC9C0\uB9CC \uBE4C\uB4DC \uC0B0\uCD9C\uBB3C\uC774 \uC5C6\uC5B4 \uBE0C\uB79C\uB4DC\uB97C \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.`
2717
+ ),
2718
+ ` \uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4\uBA74 ${chalk8.cyan(`pnpm --filter ${TOKENS_PACKAGE} build`)}, \uC544\uB2C8\uBA74 \uC7AC\uC124\uCE58: ${chalk8.cyan(TOKENS_INSTALL_COMMAND)}`
2719
+ ];
2720
+ }
2721
+ }
2722
+ function renderThemeList(result) {
2723
+ if (result.status !== "ok") {
2724
+ return { lines: ["", ...tokensStatusGuide(result.status, result.version), ""], exitCode: 1 };
2725
+ }
2726
+ if (result.brands.length === 0) {
2727
+ return {
2728
+ lines: ["", chalk8.yellow(`\uC124\uCE58\uB41C ${TOKENS_PACKAGE} ${result.version ?? ""} \uC5D0 \uBE0C\uB79C\uB4DC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.`), ""],
2729
+ exitCode: 0
2730
+ };
2731
+ }
2732
+ const width = Math.max(...result.brands.map((b) => b.name.length));
2733
+ const lines = [
2734
+ "",
2735
+ chalk8.blue(`AXIS \uBE0C\uB79C\uB4DC (${result.brands.length}\uAC1C, ${TOKENS_PACKAGE} ${result.version ?? ""})`),
2736
+ ""
2737
+ ];
2738
+ for (const b of result.brands) {
2739
+ lines.push(
2740
+ ` ${chalk8.cyan(b.name.padEnd(width))} ${b.description} ${chalk8.gray(`(${b.themes.join(" \xB7 ")})`)}`
2741
+ );
2742
+ }
2743
+ lines.push("", chalk8.gray("\uC0AC\uC6A9\uBC95: axis theme info <brand>"), "");
2744
+ return { lines, exitCode: 0 };
2745
+ }
2746
+ function a11yValue(value) {
2747
+ return value === null || value === void 0 || value === "" ? "-" : String(value);
2748
+ }
2749
+ function tokenTable(brand) {
2750
+ const rows = KEY_TOKENS.filter(
2751
+ (k) => k in brand.tokens.light || k in brand.tokens.dark
2752
+ ).map((k) => [k, brand.tokens.light[k] ?? "-", brand.tokens.dark[k] ?? "-"]);
2753
+ const missing = KEY_TOKENS.filter((k) => !(k in brand.tokens.light) && !(k in brand.tokens.dark));
2754
+ const lines = [];
2755
+ if (rows.length > 0) {
2756
+ const header = ["\uD1A0\uD070", "\uB77C\uC774\uD2B8", "\uB2E4\uD06C"];
2757
+ const w0 = Math.max(header[0].length, ...rows.map((r) => r[0].length));
2758
+ const w1 = Math.max(header[1].length, ...rows.map((r) => r[1].length));
2759
+ lines.push(chalk8.gray(` ${header[0].padEnd(w0)} ${header[1].padEnd(w1)} ${header[2]}`));
2760
+ for (const [k, l, d] of rows) {
2761
+ lines.push(` ${k.padEnd(w0)} ${l.padEnd(w1)} ${d}`);
2762
+ }
2763
+ }
2764
+ if (missing.length > 0) {
2765
+ lines.push(chalk8.gray(` \uBE0C\uB79C\uB4DC\uAC00 \uB36E\uC5B4\uC4F0\uC9C0 \uC54A\uC74C: ${missing.join(", ")}`));
2766
+ }
2767
+ return lines;
2768
+ }
2769
+ function renderThemeInfo(result, name) {
2770
+ if (result.status !== "ok") {
2771
+ return { lines: ["", ...tokensStatusGuide(result.status, result.version), ""], exitCode: 1 };
2772
+ }
2773
+ const brand = result.brand;
2774
+ if (!brand) {
2775
+ return {
2776
+ lines: [
2777
+ "",
2778
+ chalk8.red(`\uBE0C\uB79C\uB4DC '${name}' \uAC00 \uC124\uCE58\uB41C ${TOKENS_PACKAGE} ${result.version ?? ""} \uC5D0 \uC5C6\uC2B5\uB2C8\uB2E4.`),
2779
+ ` \uC124\uCE58\uB41C \uBE0C\uB79C\uB4DC: ${result.available.length > 0 ? result.available.join(", ") : "(\uC5C6\uC74C)"}`,
2780
+ chalk8.gray(" \uBAA9\uB85D: axis theme list"),
2781
+ ""
2782
+ ],
2783
+ exitCode: 1
2784
+ };
2785
+ }
2786
+ const lines = [
2787
+ "",
2788
+ chalk8.blue(`\uBE0C\uB79C\uB4DC ${brand.name}`),
2789
+ ` \uC124\uBA85: ${brand.description}`,
2790
+ ` \uD14C\uB9C8: ${brand.themes.join(" \xB7 ")}`,
2791
+ "",
2792
+ chalk8.bold("Import (globals.css, @charset \xB7 \uB2E4\uB978 @import \uB2E4\uC74C)"),
2793
+ ` @import "${brand.importPath}";`,
2794
+ "",
2795
+ chalk8.bold("Provider (@axis-ds/theme 1.3.0 \uC774\uC0C1)"),
2796
+ ...brand.providerExample.split("\n").map((l) => l ? ` ${l}` : ""),
2797
+ chalk8.gray(
2798
+ ` ThemeProvider \uB098 <html data-brand="${brand.name}"> \uAC00 \uC5C6\uC73C\uBA74 import \uB9CC\uC73C\uB85C\uB294 \uD654\uBA74\uC774 \uBC14\uB00C\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.`
2799
+ ),
2800
+ "",
2801
+ chalk8.bold("\uC8FC\uC694 \uD1A0\uD070"),
2802
+ ...tokenTable(brand),
2803
+ "",
2804
+ chalk8.bold("\uBCF4\uC815 \uB0B4\uC5ED"),
2805
+ ` a11y \uC0C1\uD0DC: ${a11yValue(brand.adjustments.a11y.status)}`,
2806
+ ` \uC810\uAC80\uC77C: ${a11yValue(brand.adjustments.a11y.checkedAt)}`,
2807
+ ` \uAC8C\uC774\uD2B8: ${a11yValue(brand.adjustments.a11y.gate)}`,
2808
+ ` \uADFC\uAC70 \uBB38\uC11C: ${brand.adjustments.reference}`,
2809
+ chalk8.gray(" \uBCF4\uC815 \uC804 \xB7 \uD6C4 \uAC12\uC740 \uC774 \uBC84\uC804\uC5D0\uC11C \uCD9C\uB825\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4."),
2810
+ ""
2811
+ ];
2812
+ return { lines, exitCode: 0 };
2813
+ }
2814
+ function rel(plan, file) {
2815
+ return path10.relative(plan.baseDir, file) || file;
2816
+ }
2817
+ function renderThemeAdd(plan, written) {
2818
+ const error = plan.errors[0];
2819
+ if (error) {
2820
+ const lines2 = [""];
2821
+ switch (error.kind) {
2822
+ case "no-config":
2823
+ lines2.push(
2824
+ chalk8.red("axis.config.json \uC774 \uC5C6\uC2B5\uB2C8\uB2E4. \uC544\uBB34\uAC83\uB3C4 \uBC14\uAFB8\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4."),
2825
+ ` \uBA3C\uC800 ${chalk8.cyan("axis init")} \uC744 \uC2E4\uD589\uD558\uC138\uC694.`
2826
+ );
2827
+ break;
2828
+ case "invalid-config":
2829
+ lines2.push(chalk8.red(`axis.config.json \uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4(${error.message}). \uC544\uBB34\uAC83\uB3C4 \uBC14\uAFB8\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.`));
2830
+ break;
2831
+ case "invalid-package-json":
2832
+ lines2.push(chalk8.red(`package.json \uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4(${error.message}). \uC544\uBB34\uAC83\uB3C4 \uBC14\uAFB8\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.`));
2833
+ break;
2834
+ case "invalid-name":
2835
+ lines2.push(
2836
+ chalk8.red(`\uBE0C\uB79C\uB4DC \uC774\uB984 '${error.brand}' \uAC00 \uADDC\uCE59(\uC18C\uBB38\uC790 \xB7 \uC22B\uC790 \xB7 \uD558\uC774\uD508, \uC608: ontology)\uC5D0 \uB9DE\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.`)
2837
+ );
2838
+ break;
2839
+ case "css-outside-project":
2840
+ lines2.push(
2841
+ chalk8.red(
2842
+ `CSS \uD30C\uC77C ${error.file} \uC758 \uC2E4\uC81C \uC704\uCE58(${error.realPath})\uAC00 \uD504\uB85C\uC81D\uD2B8 \uB514\uB809\uD130\uB9AC \uBC16\uC785\uB2C8\uB2E4. \uC544\uBB34\uAC83\uB3C4 \uBC14\uAFB8\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.`
2843
+ ),
2844
+ ` axis.config.json \uC758 globalCss \uB97C \uD504\uB85C\uC81D\uD2B8 \uC548 \uD30C\uC77C\uB85C \uACE0\uCE58\uAC70\uB098, \uADF8 \uD30C\uC77C\uC5D0 \uC9C1\uC811 \uB123\uC73C\uC138\uC694: @import "${plan.importPath}";`
2845
+ );
2846
+ break;
2847
+ case "css-not-stylesheet":
2848
+ lines2.push(
2849
+ chalk8.red(`${error.file} \uC758 \uC2E4\uC81C \uB300\uC0C1(${error.realPath})\uC774 CSS \uD30C\uC77C(.css)\uC774 \uC544\uB2D9\uB2C8\uB2E4. \uC544\uBB34\uAC83\uB3C4 \uBC14\uAFB8\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.`),
2850
+ ` axis.config.json \uC758 globalCss \uB97C \uC804\uC5ED CSS \uD30C\uC77C\uB85C \uACE0\uCE58\uAC70\uB098, \uADF8 \uD30C\uC77C\uC5D0 \uC9C1\uC811 \uB123\uC73C\uC138\uC694: @import "${plan.importPath}";`
2851
+ );
2852
+ break;
2853
+ case "unknown-brand":
2854
+ lines2.push(
2855
+ chalk8.red(`\uBE0C\uB79C\uB4DC '${error.brand}' \uAC00 \uC124\uCE58\uB41C ${TOKENS_PACKAGE} ${error.version ?? ""} \uC5D0 \uC5C6\uC2B5\uB2C8\uB2E4.`),
2856
+ ` \uC124\uCE58\uB41C \uBE0C\uB79C\uB4DC: ${error.available.length > 0 ? error.available.join(", ") : "(\uC5C6\uC74C)"}`,
2857
+ chalk8.gray(" \uBAA9\uB85D: axis theme list")
2858
+ );
2859
+ break;
2860
+ }
2861
+ lines2.push("");
2862
+ return { lines: lines2, exitCode: 1 };
2863
+ }
2864
+ const lines = ["", chalk8.blue(`\uBE0C\uB79C\uB4DC ${plan.brand} \uC801\uC6A9`), ""];
2865
+ if (plan.unverifiedBrand) {
2866
+ lines.push(
2867
+ chalk8.yellow(
2868
+ ` ! ${TOKENS_PACKAGE} \uB97C \uC77D\uC744 \uC218 \uC5C6\uC5B4(${plan.tokens.status}) \uC774\uB984 \uADDC\uCE59\uB9CC \uD655\uC778\uD588\uC2B5\uB2C8\uB2E4. \uC124\uCE58 \uD6C4 axis theme list \uB85C '${plan.brand}' \uAC00 \uC788\uB294\uC9C0 \uD655\uC778\uD558\uC138\uC694.`
2869
+ )
2870
+ );
2871
+ }
2872
+ const css = plan.css;
2873
+ if (css?.configuredMissing) {
2874
+ lines.push(
2875
+ chalk8.yellow(
2876
+ css.file ? ` ! axis.config.json \uC758 globalCss(${css.configuredMissing})\uAC00 \uC5C6\uC5B4 ${rel(plan, css.file)} \uC5D0 \uCD94\uAC00\uD569\uB2C8\uB2E4.` : ` ! axis.config.json \uC758 globalCss(${css.configuredMissing})\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.`
2877
+ )
2878
+ );
2879
+ }
2880
+ if (css?.action === "add" && css.file) {
2881
+ lines.push(` ${chalk8.green("\u2713")} ${rel(plan, css.file)}: @import "${plan.importPath}"; \uCD94\uAC00`);
2882
+ } else if (css?.action === "exists" && css.file) {
2883
+ lines.push(` ${chalk8.gray("-")} ${rel(plan, css.file)}: import \uAC00 \uC774\uBBF8 \uC788\uC5B4 \uAC74\uB108\uB700`);
2884
+ } else {
2885
+ lines.push(
2886
+ chalk8.yellow(" ! CSS \uC9C4\uC785\uC810(globalCss \xB7 app/globals.css \xB7 src/app/globals.css \xB7 globals.css)\uC744 \uCC3E\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4."),
2887
+ ` \uC804\uC5ED CSS \uB9E8 \uC55E(@charset \xB7 \uB2E4\uB978 @import \uB2E4\uC74C)\uC5D0 \uC9C1\uC811 \uB123\uC73C\uC138\uC694: @import "${plan.importPath}";`
2888
+ );
2889
+ }
2890
+ if (css && css.otherBrands.length > 0) {
2891
+ lines.push(
2892
+ chalk8.yellow(
2893
+ ` ! \uB2E4\uB978 \uBE0C\uB79C\uB4DC import(${css.otherBrands.join(", ")})\uB294 \uADF8\uB300\uB85C \uB450\uC5C8\uC2B5\uB2C8\uB2E4. \uC4F0\uC9C0 \uC54A\uC73C\uBA74 \uC774\uC804 \uBE0C\uB79C\uB4DC import \uB97C \uC9C0\uC6CC\uB3C4 \uB429\uB2C8\uB2E4.`
2894
+ )
2895
+ );
2896
+ }
2897
+ const dep = plan.dependency;
2898
+ if (dep?.action === "add") {
2899
+ lines.push(
2900
+ ` ${chalk8.green("\u2713")} package.json: dependencies \uC5D0 "${TOKENS_PACKAGE}": "${TOKENS_DEPENDENCY_RANGE}" \uCD94\uAC00`,
2901
+ ` \uC124\uCE58\uB294 \uC2E4\uD589\uD558\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. \uC124\uCE58: ${chalk8.cyan(plan.installCommand)}`
2902
+ );
2903
+ } else if (dep?.action === "present") {
2904
+ lines.push(` ${chalk8.gray("-")} package.json: ${TOKENS_PACKAGE} ${dep.declaredRange} \uAC00 \uC774\uBBF8 \uC788\uC5B4 \uBC94\uC704\uB97C \uBC14\uAFB8\uC9C0 \uC54A\uC74C`);
2905
+ } else if (dep?.action === "no-package-json") {
2906
+ lines.push(
2907
+ chalk8.yellow(` ! package.json \uC774 \uC5C6\uC5B4 \uC758\uC874\uC131\uC744 \uCD94\uAC00\uD558\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. \uC124\uCE58: ${TOKENS_INSTALL_COMMAND}`)
2908
+ );
2909
+ }
2910
+ if (dep?.upgrade) {
2911
+ lines.push(
2912
+ chalk8.yellow(
2913
+ ` ! \uC124\uCE58\uB41C ${TOKENS_PACKAGE} ${plan.tokens.version} \uC740 \uBE0C\uB79C\uB4DC\uB97C \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4(${MIN_BRAND_TOKENS_VERSION} \uC774\uC0C1 \uD544\uC694).`
2914
+ ),
2915
+ ` \uC5C5\uADF8\uB808\uC774\uB4DC: ${chalk8.cyan(TOKENS_INSTALL_COMMAND)}`
2916
+ );
2917
+ }
2918
+ if (plan.configChanged) {
2919
+ lines.push(` ${chalk8.green("\u2713")} axis.config.json: "brand": "${plan.brand}" \uAE30\uB85D`);
2920
+ } else {
2921
+ lines.push(` ${chalk8.gray("-")} axis.config.json: brand \uAC00 \uC774\uBBF8 "${plan.brand}"`);
2922
+ }
2923
+ lines.push(
2924
+ "",
2925
+ chalk8.bold(`Provider (${THEME_PACKAGE} 1.3.0 \uC774\uC0C1)`),
2926
+ ...providerExample(plan.brand).split("\n").map((l) => l ? ` ${l}` : ""),
2927
+ chalk8.gray(
2928
+ ` ThemeProvider \uB098 <html data-brand="${plan.brand}"> \uAC00 \uC5C6\uC73C\uBA74 import \uB9CC\uC73C\uB85C\uB294 \uD654\uBA74\uC774 \uBC14\uB00C\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.`
2929
+ )
2930
+ );
2931
+ if (dep?.themeMissing) {
2932
+ lines.push(` ${THEME_PACKAGE} \uC124\uCE58: ${chalk8.cyan(`pnpm add ${THEME_PACKAGE}@^1.3.0`)}`);
2933
+ }
2934
+ lines.push("", chalk8.gray(written.length > 0 ? `\uD30C\uC77C ${written.length}\uAC1C\uB97C \uBC14\uAFE8\uC2B5\uB2C8\uB2E4.` : "\uBC14\uAFBC \uD30C\uC77C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4."), "");
2935
+ return { lines, exitCode: 0 };
2936
+ }
2937
+ function renderThemeAddFailure(plan, err) {
2938
+ const lines = [""];
2939
+ if (err instanceof ThemeApplyError) {
2940
+ lines.push(chalk8.red(err.message));
2941
+ if (err.restored.length > 0) {
2942
+ lines.push(` \uBA3C\uC800 \uC4F4 \uD30C\uC77C\uC740 \uC6D0\uB798 \uB0B4\uC6A9\uC73C\uB85C \uB418\uB3CC\uB838\uC2B5\uB2C8\uB2E4: ${err.restored.map((f) => rel(plan, f)).join(", ")}`);
2943
+ }
2944
+ if (err.restoreFailed.length > 0) {
2945
+ lines.push(
2946
+ chalk8.red(` \uB418\uB3CC\uB9AC\uC9C0 \uBABB\uD574 \uBC14\uB010 \uCC44 \uB0A8\uC740 \uD30C\uC77C: ${err.restoreFailed.map((f) => rel(plan, f)).join(", ")}`)
2947
+ );
2948
+ }
2949
+ if (err.restored.length === 0 && err.restoreFailed.length === 0) {
2950
+ lines.push(" \uBC14\uB010 \uD30C\uC77C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.");
2951
+ }
2952
+ } else {
2953
+ lines.push(chalk8.red(err instanceof Error ? err.message : String(err)), " \uBC14\uB010 \uD30C\uC77C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.");
2954
+ }
2955
+ lines.push("");
2956
+ return { lines, exitCode: 1 };
2957
+ }
2958
+ function print(output) {
2959
+ for (const line of output.lines) console.log(line);
2960
+ if (output.exitCode !== 0) process.exitCode = output.exitCode;
2961
+ }
2962
+ function registerThemeCommand(program2) {
2963
+ const themeCmd = program2.command("theme").description("\uBE0C\uB79C\uB4DC \uD14C\uB9C8 (@axis-ds/tokens \uBE0C\uB79C\uB4DC)");
2964
+ themeCmd.command("list").alias("ls").description("\uC124\uCE58\uB41C @axis-ds/tokens \uC758 \uBE0C\uB79C\uB4DC \uBAA9\uB85D").option("-d, --dir <path>", "\uB300\uC0C1 \uB514\uB809\uD1A0\uB9AC").action((options) => {
2965
+ const baseDir = path10.resolve(options.dir || ".");
2966
+ print(renderThemeList(listBrands(baseDir)));
2967
+ });
2968
+ themeCmd.command("info <brand>").description("\uBE0C\uB79C\uB4DC \uC0C1\uC138: import \uACBD\uB85C \xB7 Provider \uC608\uC2DC \xB7 \uC8FC\uC694 \uD1A0\uD070 \xB7 \uBCF4\uC815 \uB0B4\uC5ED").option("-d, --dir <path>", "\uB300\uC0C1 \uB514\uB809\uD1A0\uB9AC").action((name, options) => {
2969
+ const baseDir = path10.resolve(options.dir || ".");
2970
+ print(renderThemeInfo(getBrand(baseDir, name), name));
2971
+ });
2972
+ themeCmd.command("add <brand>").description("\uBE0C\uB79C\uB4DC \uC801\uC6A9: CSS import \xB7 package.json \uC758\uC874\uC131 \xB7 axis.config.json brand (\uC124\uCE58\uB294 \uC548\uB0B4\uB9CC)").option("-d, --dir <path>", "\uB300\uC0C1 \uB514\uB809\uD1A0\uB9AC").action((name, options) => {
2973
+ const baseDir = path10.resolve(options.dir || ".");
2974
+ const plan = planThemeAdd(baseDir, name);
2975
+ let written = [];
2976
+ if (plan.errors.length === 0) {
2977
+ try {
2978
+ written = applyThemeAdd(plan);
2979
+ } catch (err) {
2980
+ print(renderThemeAddFailure(plan, err));
2981
+ return;
2982
+ }
2983
+ }
2984
+ print(renderThemeAdd(plan, written));
2985
+ });
2986
+ }
2987
+
2988
+ // src/init/index.ts
2989
+ import chalk10 from "chalk";
2990
+ import prompts2 from "prompts";
2991
+
2992
+ // src/init/init.ts
2993
+ import { accessSync as accessSync2, constants as constants2, existsSync as existsSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
2994
+ import path11 from "path";
2995
+ import chalk9 from "chalk";
2996
+ import fs10 from "fs-extra";
2997
+ var CLSX_RANGE = "^2.1.1";
2998
+ var TAILWIND_MERGE_RANGES = {
2999
+ tailwind4: "^3.4.0",
3000
+ tailwind3: "^2.6.0"
3001
+ };
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
+ function selectUtilsDependencies(tailwind) {
3095
+ return {
3096
+ clsx: CLSX_RANGE,
3097
+ "tailwind-merge": tailwind.major !== void 0 && tailwind.major >= 4 ? TAILWIND_MERGE_RANGES.tailwind4 : TAILWIND_MERGE_RANGES.tailwind3
3098
+ };
3099
+ }
3100
+ function tailwindWarnings(tailwind, installCommand) {
3101
+ const out = [];
3102
+ if (tailwind.source === "none" && tailwind.value !== void 0) {
3103
+ out.push(
3104
+ `! tailwindcss \uC120\uC5B8(${tailwind.value})\uC740 \uD310\uC815 \uBD88\uAC00 - \uAE30\uBCF8\uAC12 \uC0AC\uC6A9(Tailwind 3, tailwind-merge ${TAILWIND_MERGE_RANGES.tailwind3}). Tailwind 4 \uC774\uC0C1\uC774\uBA74 tailwind-merge \uB97C ${TAILWIND_MERGE_RANGES.tailwind4} \uC73C\uB85C \uBC14\uAFB8\uC138\uC694.`
3105
+ );
3106
+ }
3107
+ if (tailwind.mismatch) {
3108
+ out.push(
3109
+ `! \uC124\uCE58\uBCF8 tailwindcss ${tailwind.value}(major ${tailwind.major})\uC640 package.json \uC120\uC5B8 ${tailwind.mismatch.declared}(major ${tailwind.mismatch.declaredMajor})\uAC00 \uB2E4\uB984 - \uC124\uCE58\uBCF8\uC744 \uB530\uB790\uC2B5\uB2C8\uB2E4. ${installCommand} \uB4A4 tailwind-merge \uBC94\uC704\uB97C \uB2E4\uC2DC \uD655\uC778\uD558\uC138\uC694.`
3110
+ );
3111
+ }
3112
+ return out;
3113
+ }
3114
+ function describeTailwindBasis(tailwind) {
3115
+ if (tailwind.source === "installed") return `\uC124\uCE58\uB41C tailwindcss ${tailwind.value}`;
3116
+ if (tailwind.source === "declared") return `package.json \uC758 tailwindcss ${tailwind.value}`;
3117
+ if (tailwind.value !== void 0) {
3118
+ return `package.json \uC758 tailwindcss ${tailwind.value} \uB85C \uBC84\uC804\uC744 \uD310\uC815\uD558\uC9C0 \uBABB\uD574 \uAE30\uBCF8\uAC12(Tailwind 3)`;
3119
+ }
3120
+ return "tailwindcss \uB97C \uCC3E\uC9C0 \uBABB\uD574 \uAE30\uBCF8\uAC12(Tailwind 3)";
3121
+ }
3122
+ var UTILS_TS_CONTENT = `import { type ClassValue, clsx } from "clsx";
2149
3123
  import { twMerge } from "tailwind-merge";
2150
3124
 
2151
3125
  export function cn(...inputs: ClassValue[]) {
2152
3126
  return twMerge(clsx(inputs));
2153
3127
  }
2154
- `
3128
+ `;
3129
+ var INIT_DEFAULTS = {
3130
+ componentsDir: "./src/components/ui",
3131
+ tailwindConfig: "./tailwind.config.ts",
3132
+ globalCss: "./src/app/globals.css"
3133
+ };
3134
+ var INIT_NEXT_STEP_COMMAND = "npx @axis-ds/cli add button";
3135
+ var BOM = "\uFEFF";
3136
+ function addCommandFor(installCommand, deps) {
3137
+ const specs = Object.entries(deps).map(([name, range]) => `"${name}@${range}"`).join(" ");
3138
+ if (installCommand.startsWith("yarn")) return `yarn add ${specs}`;
3139
+ if (installCommand.startsWith("npm")) return `npm install ${specs}`;
3140
+ return `pnpm add ${specs}`;
3141
+ }
3142
+ function planUtilsDependencies(baseDirInput) {
3143
+ const baseDir = path11.resolve(baseDirInput);
3144
+ const installCommand = detectInstallCommand(baseDir);
3145
+ const tailwind0 = detectTailwind(baseDir);
3146
+ const ranges0 = selectUtilsDependencies(tailwind0);
3147
+ const plan = {
3148
+ action: "no-package-json",
3149
+ added: [],
3150
+ present: [],
3151
+ ranges: ranges0,
3152
+ tailwind: tailwind0,
3153
+ installCommand,
3154
+ addCommand: addCommandFor(installCommand, ranges0)
3155
+ };
3156
+ const pkgFile = path11.join(baseDir, "package.json");
3157
+ if (!existsSync3(pkgFile)) return plan;
3158
+ const unwritable = (reason) => ({ ...plan, action: "unwritable", reason });
3159
+ let where;
3160
+ try {
3161
+ where = realPathInside(baseDir, pkgFile);
3162
+ } catch (err) {
3163
+ return unwritable(err.message);
3164
+ }
3165
+ 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
+ let text;
3167
+ try {
3168
+ text = readFileSync3(pkgFile, "utf8");
3169
+ } catch (err) {
3170
+ return unwritable(err.message);
3171
+ }
3172
+ const bom = text.startsWith(BOM) ? BOM : "";
3173
+ const body = bom ? text.slice(1) : text;
3174
+ let pkg;
3175
+ try {
3176
+ const parsed = JSON.parse(body);
3177
+ if (!isPlainObject(parsed)) throw new Error("\uCD5C\uC0C1\uC704\uAC00 \uAC1D\uCCB4\uAC00 \uC544\uB2D9\uB2C8\uB2E4");
3178
+ pkg = parsed;
3179
+ } catch (err) {
3180
+ return unwritable(`JSON \uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${err.message}`);
3181
+ }
3182
+ plan.tailwind = detectTailwind(baseDir, pkg);
3183
+ plan.ranges = selectUtilsDependencies(plan.tailwind);
3184
+ plan.addCommand = addCommandFor(installCommand, plan.ranges);
3185
+ const missing = {};
3186
+ for (const [name, range] of Object.entries(plan.ranges)) {
3187
+ const declared = hasDependency(pkg, name);
3188
+ if (declared !== void 0) plan.present.push({ name, range: declared });
3189
+ else missing[name] = range;
3190
+ }
3191
+ plan.added = Object.keys(missing);
3192
+ plan.addCommand = addCommandFor(installCommand, plan.added.length > 0 ? missing : plan.ranges);
3193
+ if (plan.added.length === 0) return { ...plan, action: "present" };
3194
+ if (pkg.dependencies !== void 0 && !isPlainObject(pkg.dependencies)) {
3195
+ return unwritable("dependencies \uAC00 \uAC1D\uCCB4\uAC00 \uC544\uB2D9\uB2C8\uB2E4");
3196
+ }
3197
+ try {
3198
+ accessSync2(pkgFile, constants2.W_OK);
3199
+ } catch (err) {
3200
+ return unwritable(`\uC4F8 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4(${err.message})`);
3201
+ }
3202
+ const deps = { ...pkg.dependencies ?? {}, ...missing };
3203
+ const after = bom + formatJsonLike(body, { ...pkg, dependencies: deps });
3204
+ return { ...plan, action: "add", write: { file: pkgFile, before: text, after } };
3205
+ }
3206
+ var defaultWriteFile = (file, data) => writeFileSync2(file, data);
3207
+ function applyUtilsDependencies(baseDirInput, plan, writeFile = defaultWriteFile) {
3208
+ const w = plan.write;
3209
+ if (plan.action !== "add" || !w) return false;
3210
+ const baseDir = path11.resolve(baseDirInput);
3211
+ const current = existsSync3(w.file) ? readFileSync3(w.file, "utf8") : null;
3212
+ if (current !== w.before) {
3213
+ throw new Error(`${w.file} \uC774 \uACC4\uD68D \uB4A4\uC5D0 \uBC14\uB00C\uC5C8\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694.`);
3214
+ }
3215
+ const where = realPathInside(baseDir, w.file);
3216
+ if (!where.inside) {
3217
+ throw new Error(`${w.file} \uC758 \uC2E4\uC81C \uC704\uCE58(${where.realPath})\uAC00 \uD504\uB85C\uC81D\uD2B8 \uB514\uB809\uD130\uB9AC \uBC16\uC785\uB2C8\uB2E4. \uC4F0\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.`);
3218
+ }
3219
+ JSON.parse(w.after.startsWith(BOM) ? w.after.slice(1) : w.after);
3220
+ try {
3221
+ writeFile(w.file, w.after);
3222
+ } catch (err) {
3223
+ const cause = err.message;
3224
+ let restored;
3225
+ try {
3226
+ 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");
3228
+ restored = "\uC6D0\uB798 \uB0B4\uC6A9\uC73C\uB85C \uB418\uB3CC\uB838\uC2B5\uB2C8\uB2E4";
3229
+ } catch (restoreErr) {
3230
+ 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`;
3231
+ }
3232
+ throw new Error(`${w.file} \uC744 \uC4F0\uB294 \uB3C4\uC911 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4(${cause}). ${restored}.`);
3233
+ }
3234
+ return true;
3235
+ }
3236
+ function reportDependencies(plan, log) {
3237
+ const presentText = plan.present.map((p) => `${p.name} (${p.range})`).join(", ");
3238
+ const basis = ` tailwind-merge \uBC94\uC704 \uAE30\uC900: ${describeTailwindBasis(plan.tailwind)}`;
3239
+ const logBasis = () => {
3240
+ log(chalk9.gray(basis));
3241
+ for (const w of tailwindWarnings(plan.tailwind, plan.installCommand)) log(chalk9.yellow(` ${w}`));
3242
+ };
3243
+ if (plan.action === "add") {
3244
+ const addedText = plan.added.map((n) => `${n}@${plan.ranges[n]}`).join(", ");
3245
+ log(chalk9.green(`\u2713 package.json dependencies \uC5D0 \uCD94\uAC00: ${addedText}`));
3246
+ if (plan.present.length > 0) log(chalk9.gray(` \uC774\uBBF8 \uC788\uC74C(\uBC84\uC804 \uC720\uC9C0): ${presentText}`));
3247
+ if (plan.added.includes("tailwind-merge")) logBasis();
3248
+ log(chalk9.yellow(` \uC124\uCE58\uB294 \uC2E4\uD589\uD558\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. \uC124\uCE58: ${chalk9.cyan(plan.installCommand)}`));
3249
+ } else if (plan.action === "present") {
3250
+ log(chalk9.green(`\u2713 utils.ts \uC758\uC874\uC131\uC774 package.json \uC5D0 \uC774\uBBF8 \uC788\uC2B5\uB2C8\uB2E4(\uBC84\uC804 \uC720\uC9C0): ${presentText}`));
3251
+ log(chalk9.yellow(` \uC124\uCE58\uB294 \uC2E4\uD589\uD558\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. \uC124\uCE58: ${chalk9.cyan(plan.installCommand)}`));
3252
+ } else if (plan.action === "no-package-json") {
3253
+ log(chalk9.yellow("! package.json \uC774 \uC5C6\uC5B4 utils.ts \uC758\uC874\uC131(clsx, tailwind-merge)\uC744 \uCD94\uAC00\uD558\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4."));
3254
+ log(chalk9.yellow(` \uC124\uCE58: ${chalk9.cyan(plan.addCommand)}`));
3255
+ logBasis();
3256
+ } else {
3257
+ log(chalk9.yellow(`! package.json \uC744 \uBC14\uAFB8\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4(${plan.reason}).`));
3258
+ log(chalk9.yellow(` utils.ts \uC758\uC874\uC131 \uC124\uCE58: ${chalk9.cyan(plan.addCommand)}`));
3259
+ if (plan.addCommand.includes('"tailwind-merge@')) logBasis();
3260
+ }
3261
+ }
3262
+ async function runInit(baseDirInput, answers, registryUrl, log = console.log) {
3263
+ const baseDir = path11.resolve(baseDirInput);
3264
+ const axisConfig = createInitConfig(
3265
+ {
3266
+ componentsDir: answers.componentsDir,
3267
+ tailwindConfig: answers.tailwindConfig,
3268
+ globalCss: answers.globalCss
3269
+ },
3270
+ registryUrl
2155
3271
  );
2156
- console.log(chalk8.green("\u2713 utils.ts \uC0DD\uC131 \uC644\uB8CC"));
2157
- console.log(chalk8.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:"));
2158
- console.log(chalk8.cyan(" npx axis-cli add button\n"));
2159
- });
3272
+ await fs10.writeJSON(path11.join(baseDir, "axis.config.json"), axisConfig, { spaces: 2 });
3273
+ log(chalk9.green("\u2713 axis.config.json \uC0DD\uC131 \uC644\uB8CC"));
3274
+ const utilsPath = path11.resolve(baseDir, answers.componentsDir, "utils.ts");
3275
+ await fs10.ensureDir(path11.dirname(utilsPath));
3276
+ await fs10.writeFile(utilsPath, UTILS_TS_CONTENT);
3277
+ log(chalk9.green("\u2713 utils.ts \uC0DD\uC131 \uC644\uB8CC"));
3278
+ const plan = planUtilsDependencies(baseDir);
3279
+ try {
3280
+ applyUtilsDependencies(baseDir, plan);
3281
+ } catch (err) {
3282
+ log(chalk9.red(`\u2717 package.json \uC744 \uC4F0\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4: ${err.message}`));
3283
+ log(chalk9.yellow(" axis.config.json \uACFC utils.ts \uB294 \uC774\uBBF8 \uB9CC\uB4E4\uC5B4\uC84C\uC2B5\uB2C8\uB2E4."));
3284
+ log(chalk9.yellow(` utils.ts \uC758\uC874\uC131 \uC124\uCE58: ${chalk9.cyan(plan.addCommand)}`));
3285
+ process.exitCode = 1;
3286
+ return;
3287
+ }
3288
+ reportDependencies(plan, log);
3289
+ 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
+ log(chalk9.cyan(` ${INIT_NEXT_STEP_COMMAND}
3291
+ `));
3292
+ }
3293
+
3294
+ // src/init/index.ts
3295
+ function registerInitCommand(program2, registryUrl) {
3296
+ 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
+ console.log(chalk10.blue("\n\u{1F3A8} AXIS Design System \uCD08\uAE30\uD654\n"));
3298
+ const config = options.yes ? { ...INIT_DEFAULTS } : await prompts2([
3299
+ {
3300
+ type: "text",
3301
+ name: "componentsDir",
3302
+ message: "\uCEF4\uD3EC\uB10C\uD2B8 \uB514\uB809\uD1A0\uB9AC:",
3303
+ initial: INIT_DEFAULTS.componentsDir
3304
+ },
3305
+ {
3306
+ type: "text",
3307
+ name: "tailwindConfig",
3308
+ message: "Tailwind \uC124\uC815 \uD30C\uC77C:",
3309
+ initial: INIT_DEFAULTS.tailwindConfig
3310
+ },
3311
+ {
3312
+ type: "text",
3313
+ name: "globalCss",
3314
+ message: "\uAE00\uB85C\uBC8C CSS \uD30C\uC77C:",
3315
+ initial: INIT_DEFAULTS.globalCss
3316
+ }
3317
+ ]);
3318
+ await runInit(process.cwd(), config, registryUrl);
3319
+ });
3320
+ }
3321
+
3322
+ // src/index.ts
3323
+ var { version: CLI_VERSION } = createRequire2(import.meta.url)("../package.json");
3324
+ var REGISTRY_URL = process.env.AXIS_REGISTRY_URL || "https://axis.minu.best/r";
3325
+ var program = new Command();
3326
+ program.name("axis").description("AXIS Design System CLI - shadcn \uD638\uD658 \uCEF4\uD3EC\uB10C\uD2B8 \uC124\uCE58 \uB3C4\uAD6C").version(CLI_VERSION);
3327
+ registerInitCommand(program, REGISTRY_URL);
2160
3328
  program.command("add <component>").description("\uCEF4\uD3EC\uB10C\uD2B8 \uCD94\uAC00").option("--agentic", "Agentic UI \uCEF4\uD3EC\uB10C\uD2B8 \uCD94\uAC00").option("-y, --yes", "\uD655\uC778 \uC5C6\uC774 \uB36E\uC5B4\uC4F0\uAE30").action(async (component, options) => {
2161
3329
  const spinner = ora6(`${component} \uCEF4\uD3EC\uB10C\uD2B8 \uAC00\uC838\uC624\uB294 \uC911...`).start();
2162
3330
  try {
2163
- const configPath = path9.resolve("axis.config.json");
2164
- if (!await fs9.pathExists(configPath)) {
3331
+ const configPath = path12.resolve("axis.config.json");
3332
+ if (!await fs11.pathExists(configPath)) {
2165
3333
  spinner.fail(
2166
3334
  "axis.config.json\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.\n \uD574\uACB0: \uD504\uB85C\uC81D\uD2B8 \uB8E8\uD2B8\uC5D0\uC11C 'npx @axis-ds/cli init'\uC744 \uC2E4\uD589\uD558\uC138\uC694.\n \uCC38\uACE0: https://axis.minu.best/docs/guides/quick-start"
2167
3335
  );
2168
3336
  process.exit(1);
2169
3337
  }
2170
- const config = await fs9.readJSON(configPath);
3338
+ const config = await fs11.readJSON(configPath);
2171
3339
  const category = options.agentic ? "agentic" : "ui";
2172
3340
  const componentInfo = await getComponentInfo(component, category);
2173
3341
  if (!componentInfo) {
@@ -2180,10 +3348,10 @@ program.command("add <component>").description("\uCEF4\uD3EC\uB10C\uD2B8 \uCD94\
2180
3348
  }
2181
3349
  spinner.text = `${component} \uCEF4\uD3EC\uB10C\uD2B8 \uC124\uCE58 \uC911...`;
2182
3350
  for (const file of componentInfo.files) {
2183
- const filePath = path9.join(config.componentsDir, file.path);
2184
- if (await fs9.pathExists(filePath)) {
3351
+ const filePath = path12.join(config.componentsDir, file.path);
3352
+ if (await fs11.pathExists(filePath)) {
2185
3353
  if (!options.yes) {
2186
- const { overwrite } = await prompts2({
3354
+ const { overwrite } = await prompts3({
2187
3355
  type: "confirm",
2188
3356
  name: "overwrite",
2189
3357
  message: `${file.path}\uC774(\uAC00) \uC774\uBBF8 \uC874\uC7AC\uD569\uB2C8\uB2E4. \uB36E\uC5B4\uC4F0\uC2DC\uACA0\uC2B5\uB2C8\uAE4C?`,
@@ -2192,13 +3360,13 @@ program.command("add <component>").description("\uCEF4\uD3EC\uB10C\uD2B8 \uCD94\
2192
3360
  if (!overwrite) continue;
2193
3361
  }
2194
3362
  }
2195
- await fs9.ensureDir(path9.dirname(filePath));
2196
- await fs9.writeFile(filePath, file.content);
3363
+ await fs11.ensureDir(path12.dirname(filePath));
3364
+ await fs11.writeFile(filePath, file.content);
2197
3365
  }
2198
- spinner.succeed(chalk8.green(`${component} \uCEF4\uD3EC\uB10C\uD2B8 \uCD94\uAC00 \uC644\uB8CC`));
3366
+ spinner.succeed(chalk11.green(`${component} \uCEF4\uD3EC\uB10C\uD2B8 \uCD94\uAC00 \uC644\uB8CC`));
2199
3367
  if (componentInfo.dependencies.length > 0) {
2200
- console.log(chalk8.yellow("\n\uD544\uC694\uD55C \uC758\uC874\uC131:"));
2201
- console.log(chalk8.cyan(` pnpm add ${componentInfo.dependencies.join(" ")}`));
3368
+ console.log(chalk11.yellow("\n\uD544\uC694\uD55C \uC758\uC874\uC131:"));
3369
+ console.log(chalk11.cyan(` pnpm add ${componentInfo.dependencies.join(" ")}`));
2202
3370
  }
2203
3371
  } catch (error) {
2204
3372
  spinner.fail(
@@ -2210,7 +3378,7 @@ program.command("add <component>").description("\uCEF4\uD3EC\uB10C\uD2B8 \uCD94\
2210
3378
  }
2211
3379
  });
2212
3380
  program.command("list").description("\uC0AC\uC6A9 \uAC00\uB2A5\uD55C \uCEF4\uD3EC\uB10C\uD2B8 \uBAA9\uB85D").option("--category <type>", "\uCE74\uD14C\uACE0\uB9AC \uD544\uD130 (ui, agentic)").action(async (options) => {
2213
- console.log(chalk8.blue("\n\u{1F4E6} AXIS Design System \uCEF4\uD3EC\uB10C\uD2B8\n"));
3381
+ console.log(chalk11.blue("\n\u{1F4E6} AXIS Design System \uCEF4\uD3EC\uB10C\uD2B8\n"));
2214
3382
  const components = {
2215
3383
  ui: [
2216
3384
  { name: "button", description: "\uAE30\uBCF8 \uBC84\uD2BC \uCEF4\uD3EC\uB10C\uD2B8" },
@@ -2238,9 +3406,9 @@ program.command("list").description("\uC0AC\uC6A9 \uAC00\uB2A5\uD55C \uCEF4\uD3E
2238
3406
  ]
2239
3407
  };
2240
3408
  const showCategory = (category, items) => {
2241
- console.log(chalk8.bold(category === "ui" ? "Core UI" : "Agentic UI"));
3409
+ console.log(chalk11.bold(category === "ui" ? "Core UI" : "Agentic UI"));
2242
3410
  items.forEach((c) => {
2243
- console.log(` ${chalk8.cyan(c.name.padEnd(20))} ${chalk8.gray(c.description)}`);
3411
+ console.log(` ${chalk11.cyan(c.name.padEnd(20))} ${chalk11.gray(c.description)}`);
2244
3412
  });
2245
3413
  console.log();
2246
3414
  };
@@ -2250,8 +3418,8 @@ program.command("list").description("\uC0AC\uC6A9 \uAC00\uB2A5\uD55C \uCEF4\uD3E
2250
3418
  if (!options.category || options.category === "agentic") {
2251
3419
  showCategory("agentic", components.agentic);
2252
3420
  }
2253
- console.log(chalk8.gray("\uC0AC\uC6A9\uBC95: npx axis-cli add <component-name>"));
2254
- console.log(chalk8.gray("Agentic: npx axis-cli add <component-name> --agentic\n"));
3421
+ console.log(chalk11.gray("\uC0AC\uC6A9\uBC95: npx @axis-ds/cli add <component-name>"));
3422
+ console.log(chalk11.gray("Agentic: npx @axis-ds/cli add <component-name> --agentic\n"));
2255
3423
  });
2256
3424
  var monetCmd = program.command("monet").description("Monet Design \uCEF4\uD3EC\uB10C\uD2B8 \uAD00\uB9AC (https://monet.design)");
2257
3425
  monetCmd.command("list").alias("ls").description("Monet \uCE74\uD14C\uACE0\uB9AC \uBAA9\uB85D").action(async () => {
@@ -2271,24 +3439,24 @@ monetCmd.command("import").alias("i").description("\uD074\uB9BD\uBCF4\uB4DC\uC5D
2271
3439
  await client.importFromClipboard();
2272
3440
  });
2273
3441
  monetCmd.command("setup").description("Monet MCP \uC11C\uBC84 \uC124\uC815 \uC548\uB0B4").action(() => {
2274
- console.log(chalk8.blue("\n\u{1F527} Monet MCP \uC11C\uBC84 \uC124\uC815\n"));
2275
- console.log(chalk8.bold("1. API \uD0A4 \uBC1C\uAE09:"));
2276
- console.log(chalk8.cyan(" https://monet.design/mcp\n"));
2277
- console.log(chalk8.bold("2. \uD658\uACBD \uBCC0\uC218 \uC124\uC815:"));
2278
- console.log(chalk8.gray(" .env \uD30C\uC77C\uC5D0 \uCD94\uAC00:"));
2279
- console.log(chalk8.cyan(" MONET_API_KEY=your-api-key-here\n"));
2280
- console.log(chalk8.bold("3. Claude Code MCP \uC124\uC815:"));
2281
- console.log(chalk8.gray(" .claude/mcp.json\uC5D0\uC11C monet \uC11C\uBC84 \uD65C\uC131\uD654:\n"));
3442
+ console.log(chalk11.blue("\n\u{1F527} Monet MCP \uC11C\uBC84 \uC124\uC815\n"));
3443
+ console.log(chalk11.bold("1. API \uD0A4 \uBC1C\uAE09:"));
3444
+ console.log(chalk11.cyan(" https://monet.design/mcp\n"));
3445
+ console.log(chalk11.bold("2. \uD658\uACBD \uBCC0\uC218 \uC124\uC815:"));
3446
+ console.log(chalk11.gray(" .env \uD30C\uC77C\uC5D0 \uCD94\uAC00:"));
3447
+ console.log(chalk11.cyan(" MONET_API_KEY=your-api-key-here\n"));
3448
+ console.log(chalk11.bold("3. Claude Code MCP \uC124\uC815:"));
3449
+ console.log(chalk11.gray(" .claude/mcp.json\uC5D0\uC11C monet \uC11C\uBC84 \uD65C\uC131\uD654:\n"));
2282
3450
  console.log(
2283
- chalk8.cyan(` "monet": {
3451
+ chalk11.cyan(` "monet": {
2284
3452
  "url": "https://www.monet.design/api/remote/mcp",
2285
3453
  "headers": { "Authorization": "Bearer \${MONET_API_KEY}" },
2286
3454
  "disabled": false
2287
3455
  }
2288
3456
  `)
2289
3457
  );
2290
- console.log(chalk8.bold("4. Claude Code \uC7AC\uC2DC\uC791 \uD6C4 \uC0AC\uC6A9:"));
2291
- console.log(chalk8.gray(' "monet\uC5D0\uC11C hero \uCEF4\uD3EC\uB10C\uD2B8 \uCC3E\uC544\uC918"\n'));
3458
+ console.log(chalk11.bold("4. Claude Code \uC7AC\uC2DC\uC791 \uD6C4 \uC0AC\uC6A9:"));
3459
+ console.log(chalk11.gray(' "monet\uC5D0\uC11C hero \uCEF4\uD3EC\uB10C\uD2B8 \uCC3E\uC544\uC918"\n'));
2292
3460
  });
2293
3461
  var v0Cmd = program.command("v0").description("V0 (v0.app) \uCF54\uB4DC \uBCC0\uD658 \uBC0F \uD1B5\uD569");
2294
3462
  v0Cmd.command("convert <file>").alias("c").description("V0 \uCF54\uB4DC\uB97C AXIS \uC2A4\uD0C0\uC77C\uB85C \uBCC0\uD658").option("-o, --output <path>", "\uCD9C\uB825 \uD30C\uC77C \uACBD\uB85C").action(async (file, options) => {
@@ -2325,18 +3493,18 @@ libraryCmd.command("collect").alias("c").description("\uC678\uBD80 \uC18C\uC2A4\
2325
3493
  total += result.collected;
2326
3494
  failed += result.failed;
2327
3495
  }
2328
- console.log(chalk8.blue(`
3496
+ console.log(chalk11.blue(`
2329
3497
  \u{1F4CA} \uC218\uC9D1 \uC644\uB8CC: ${total}\uAC1C \uCEF4\uD3EC\uB10C\uD2B8`));
2330
3498
  if (failed > 0) {
2331
- console.log(chalk8.yellow(` \uC2E4\uD328: ${failed}\uAC1C`));
3499
+ console.log(chalk11.yellow(` \uC2E4\uD328: ${failed}\uAC1C`));
2332
3500
  }
2333
3501
  });
2334
3502
  libraryCmd.command("list").alias("ls").description("\uB77C\uC774\uBE0C\uB7EC\uB9AC \uCEF4\uD3EC\uB10C\uD2B8 \uBAA9\uB85D").option("-c, --category <category>", "\uCE74\uD14C\uACE0\uB9AC \uD544\uD130").option("-s, --source <source>", "\uC18C\uC2A4 \uD544\uD130").action(async (options) => {
2335
3503
  const curator = new LibraryCurator();
2336
3504
  const index = await curator.loadIndex();
2337
3505
  if (!index) {
2338
- console.log(chalk8.yellow("\n\u26A0\uFE0F \uB77C\uC774\uBE0C\uB7EC\uB9AC \uC778\uB371\uC2A4\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4."));
2339
- console.log(chalk8.gray(" \uD574\uACB0: npx @axis-ds/cli library collect \uBA85\uB839\uC5B4\uB85C \uC218\uC9D1\uC744 \uBA3C\uC800 \uC2E4\uD589\uD558\uC138\uC694.\n"));
3506
+ console.log(chalk11.yellow("\n\u26A0\uFE0F \uB77C\uC774\uBE0C\uB7EC\uB9AC \uC778\uB371\uC2A4\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4."));
3507
+ console.log(chalk11.gray(" \uD574\uACB0: npx @axis-ds/cli library collect \uBA85\uB839\uC5B4\uB85C \uC218\uC9D1\uC744 \uBA3C\uC800 \uC2E4\uD589\uD558\uC138\uC694.\n"));
2340
3508
  return;
2341
3509
  }
2342
3510
  let components = index.components;
@@ -2346,7 +3514,7 @@ libraryCmd.command("list").alias("ls").description("\uB77C\uC774\uBE0C\uB7EC\uB9
2346
3514
  if (options.source) {
2347
3515
  components = components.filter((c) => c.source.type === options.source);
2348
3516
  }
2349
- console.log(chalk8.blue(`
3517
+ console.log(chalk11.blue(`
2350
3518
  \u{1F4E6} Library Components (${components.length}\uAC1C)
2351
3519
  `));
2352
3520
  const byCategory = /* @__PURE__ */ new Map();
@@ -2358,14 +3526,14 @@ libraryCmd.command("list").alias("ls").description("\uB77C\uC774\uBE0C\uB7EC\uB9
2358
3526
  byCategory.get(cat).push(comp);
2359
3527
  }
2360
3528
  for (const [category, items] of byCategory) {
2361
- console.log(chalk8.bold(`${category} (${items.length})`));
3529
+ console.log(chalk11.bold(`${category} (${items.length})`));
2362
3530
  for (const item of items.slice(0, 10)) {
2363
3531
  console.log(
2364
- ` ${chalk8.cyan(item.name.padEnd(25))} ${chalk8.gray(item.source.type.padEnd(8))} ${chalk8.gray(item.description.slice(0, 40))}`
3532
+ ` ${chalk11.cyan(item.name.padEnd(25))} ${chalk11.gray(item.source.type.padEnd(8))} ${chalk11.gray(item.description.slice(0, 40))}`
2365
3533
  );
2366
3534
  }
2367
3535
  if (items.length > 10) {
2368
- console.log(chalk8.gray(` ... \uC678 ${items.length - 10}\uAC1C`));
3536
+ console.log(chalk11.gray(` ... \uC678 ${items.length - 10}\uAC1C`));
2369
3537
  }
2370
3538
  console.log();
2371
3539
  }
@@ -2377,21 +3545,21 @@ libraryCmd.command("search <query>").alias("s").description("\uCEF4\uD3EC\uB10C\
2377
3545
  source: options.source
2378
3546
  });
2379
3547
  if (results.length === 0) {
2380
- console.log(chalk8.yellow(`
3548
+ console.log(chalk11.yellow(`
2381
3549
  '${query}'\uC5D0 \uB300\uD55C \uAC80\uC0C9 \uACB0\uACFC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.
2382
3550
  `));
2383
3551
  return;
2384
3552
  }
2385
- console.log(chalk8.blue(`
3553
+ console.log(chalk11.blue(`
2386
3554
  \u{1F50D} '${query}' \uAC80\uC0C9 \uACB0\uACFC (${results.length}\uAC1C)
2387
3555
  `));
2388
3556
  for (const comp of results.slice(0, 20)) {
2389
3557
  console.log(
2390
- ` ${chalk8.cyan(comp.name.padEnd(25))} ${chalk8.gray(comp.source.type.padEnd(8))} ${chalk8.gray(comp.category.padEnd(12))} ${chalk8.gray(comp.description.slice(0, 30))}`
3558
+ ` ${chalk11.cyan(comp.name.padEnd(25))} ${chalk11.gray(comp.source.type.padEnd(8))} ${chalk11.gray(comp.category.padEnd(12))} ${chalk11.gray(comp.description.slice(0, 30))}`
2391
3559
  );
2392
3560
  }
2393
3561
  if (results.length > 20) {
2394
- console.log(chalk8.gray(`
3562
+ console.log(chalk11.gray(`
2395
3563
  ... \uC678 ${results.length - 20}\uAC1C`));
2396
3564
  }
2397
3565
  console.log();
@@ -2405,12 +3573,12 @@ libraryCmd.command("publish").description("\uC0AC\uC774\uD2B8\uC5D0 \uB77C\uC774
2405
3573
  const publisher2 = new Publisher();
2406
3574
  const index = await curator.loadIndex();
2407
3575
  if (!index) {
2408
- console.log(chalk8.yellow("\n\u26A0\uFE0F \uB77C\uC774\uBE0C\uB7EC\uB9AC \uC778\uB371\uC2A4\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4."));
2409
- console.log(chalk8.gray(" \uD574\uACB0: npx @axis-ds/cli library collect \uBA85\uB839\uC5B4\uB85C \uC218\uC9D1\uC744 \uBA3C\uC800 \uC2E4\uD589\uD558\uC138\uC694.\n"));
3576
+ console.log(chalk11.yellow("\n\u26A0\uFE0F \uB77C\uC774\uBE0C\uB7EC\uB9AC \uC778\uB371\uC2A4\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4."));
3577
+ console.log(chalk11.gray(" \uD574\uACB0: npx @axis-ds/cli library collect \uBA85\uB839\uC5B4\uB85C \uC218\uC9D1\uC744 \uBA3C\uC800 \uC2E4\uD589\uD558\uC138\uC694.\n"));
2410
3578
  return;
2411
3579
  }
2412
- console.log(chalk8.blue("\n\u{1F4E4} Library \uBC30\uCE58\n"));
2413
- console.log(chalk8.gray(`\uCD1D ${index.stats.total}\uAC1C \uCEF4\uD3EC\uB10C\uD2B8
3580
+ console.log(chalk11.blue("\n\u{1F4E4} Library \uBC30\uCE58\n"));
3581
+ console.log(chalk11.gray(`\uCD1D ${index.stats.total}\uAC1C \uCEF4\uD3EC\uB10C\uD2B8
2414
3582
  `));
2415
3583
  if (options.clean) {
2416
3584
  await publisher2.clean(options.output);
@@ -2421,17 +3589,17 @@ libraryCmd.command("publish").description("\uC0AC\uC774\uD2B8\uC5D0 \uB77C\uC774
2421
3589
  generateSearchIndex: true
2422
3590
  });
2423
3591
  if (result.success) {
2424
- console.log(chalk8.green(`
3592
+ console.log(chalk11.green(`
2425
3593
  \u2713 \uBC30\uCE58 \uC644\uB8CC`));
2426
- console.log(chalk8.gray(` - \uCD9C\uB825 \uB514\uB809\uD1A0\uB9AC: ${result.outputDir}`));
2427
- console.log(chalk8.gray(` - \uC0DD\uC131\uB41C \uD30C\uC77C: ${result.files.length}\uAC1C`));
2428
- console.log(chalk8.gray(` - \uCE74\uD14C\uACE0\uB9AC: ${result.stats.categoriesPublished}\uAC1C`));
2429
- console.log(chalk8.gray(` - \uAC80\uC0C9 \uC778\uB371\uC2A4: ${result.stats.searchIndexSize}\uAC1C \uD56D\uBAA9`));
3594
+ console.log(chalk11.gray(` - \uCD9C\uB825 \uB514\uB809\uD1A0\uB9AC: ${result.outputDir}`));
3595
+ console.log(chalk11.gray(` - \uC0DD\uC131\uB41C \uD30C\uC77C: ${result.files.length}\uAC1C`));
3596
+ console.log(chalk11.gray(` - \uCE74\uD14C\uACE0\uB9AC: ${result.stats.categoriesPublished}\uAC1C`));
3597
+ console.log(chalk11.gray(` - \uAC80\uC0C9 \uC778\uB371\uC2A4: ${result.stats.searchIndexSize}\uAC1C \uD56D\uBAA9`));
2430
3598
  } else {
2431
- console.log(chalk8.red(`
3599
+ console.log(chalk11.red(`
2432
3600
  \u2717 \uBC30\uCE58 \uC2E4\uD328`));
2433
3601
  for (const error of result.errors) {
2434
- console.log(chalk8.red(` - ${error}`));
3602
+ console.log(chalk11.red(` - ${error}`));
2435
3603
  }
2436
3604
  }
2437
3605
  console.log();
@@ -2439,6 +3607,7 @@ libraryCmd.command("publish").description("\uC0AC\uC774\uD2B8\uC5D0 \uB77C\uC774
2439
3607
  registerSyncCommand(program);
2440
3608
  registerTemplateCommand(program);
2441
3609
  registerCheckCommand(program);
3610
+ registerThemeCommand(program);
2442
3611
  async function getComponentInfo(name, category) {
2443
3612
  const localComponents = {
2444
3613
  button: {