@axis-ds/mcp 1.3.5 → 1.4.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
@@ -10,61 +10,67 @@ import { z } from "zod";
10
10
  import { readFileSync } from "fs";
11
11
  import { join, dirname } from "path";
12
12
  import { fileURLToPath } from "url";
13
+
14
+ // src/types.ts
15
+ var TOKEN_CATEGORIES = [
16
+ "color",
17
+ "typography",
18
+ "spacing",
19
+ "radius",
20
+ "shadow",
21
+ "density",
22
+ "component"
23
+ ];
24
+
25
+ // src/registry/loader.ts
13
26
  var __filename = fileURLToPath(import.meta.url);
14
27
  var __dirname = dirname(__filename);
15
28
  var DATA_DIR = join(__dirname, "data");
16
- var cachedRegistry = null;
29
+ var cachedComponents = null;
30
+ var cachedTokens = null;
17
31
  function loadComponents() {
18
- const filePath = join(DATA_DIR, "components.json");
19
- const content = readFileSync(filePath, "utf-8");
20
- const data = JSON.parse(content);
21
- return data.components;
32
+ if (!cachedComponents) {
33
+ const filePath = join(DATA_DIR, "components.json");
34
+ const content = readFileSync(filePath, "utf-8");
35
+ const data = JSON.parse(content);
36
+ cachedComponents = data.components;
37
+ }
38
+ return cachedComponents;
22
39
  }
23
40
  function loadTokens() {
24
- const filePath = join(DATA_DIR, "tokens.json");
25
- const content = readFileSync(filePath, "utf-8");
26
- const data = JSON.parse(content);
27
- return data.tokens;
28
- }
29
- function getRegistry() {
30
- if (!cachedRegistry) {
31
- cachedRegistry = {
32
- components: loadComponents(),
33
- tokens: loadTokens()
34
- };
41
+ if (!cachedTokens) {
42
+ const filePath = join(DATA_DIR, "tokens.json");
43
+ const content = readFileSync(filePath, "utf-8");
44
+ const data = JSON.parse(content);
45
+ cachedTokens = { source: data.source, tokens: data.tokens };
35
46
  }
36
- return cachedRegistry;
47
+ return cachedTokens;
37
48
  }
38
49
  function getComponentMeta(name) {
39
- const registry = getRegistry();
40
- return registry.components.find(
50
+ return loadComponents().find(
41
51
  (c) => c.name.toLowerCase() === name.toLowerCase()
42
52
  );
43
53
  }
44
54
  function listTokens(category) {
45
- const registry = getRegistry();
55
+ const { tokens } = loadTokens();
46
56
  if (category) {
47
- return registry.tokens.filter((t) => t.category === category);
57
+ return tokens.filter((t) => t.category === category);
48
58
  }
49
- return registry.tokens;
59
+ return tokens;
50
60
  }
51
61
  function getToken(path11) {
52
- const registry = getRegistry();
53
- return registry.tokens.find(
54
- (t) => t.path.toLowerCase() === path11.toLowerCase()
62
+ const q = path11.trim().toLowerCase();
63
+ return loadTokens().tokens.find(
64
+ (t) => t.path.toLowerCase() === q || (t.aliases ?? []).some((a) => a.toLowerCase() === q) || t.cssVariable.toLowerCase() === q
55
65
  );
56
66
  }
67
+ function getTokenSource() {
68
+ return loadTokens().source;
69
+ }
57
70
  function getTokenStats() {
58
- const registry = getRegistry();
59
- const stats = {
60
- color: 0,
61
- typography: 0,
62
- spacing: 0,
63
- radius: 0,
64
- shadow: 0,
65
- animation: 0
66
- };
67
- for (const token of registry.tokens) {
71
+ const { tokens } = loadTokens();
72
+ const stats = Object.fromEntries(TOKEN_CATEGORIES.map((c) => [c, 0]));
73
+ for (const token of tokens) {
68
74
  stats[token.category]++;
69
75
  }
70
76
  return stats;
@@ -867,10 +873,45 @@ var RegistryClient = class {
867
873
  // ../axis-registry-core/src/project.ts
868
874
  import { existsSync as existsSync2, readFileSync as readFileSync3, statSync } from "fs";
869
875
  import path3 from "path";
870
- function detectInstallCommand(baseDir) {
871
- if (existsSync2(path3.join(baseDir, "pnpm-lock.yaml"))) return "pnpm install";
872
- if (existsSync2(path3.join(baseDir, "yarn.lock"))) return "yarn install";
873
- if (existsSync2(path3.join(baseDir, "package-lock.json"))) return "npm install";
876
+ var LOCKFILE_COMMANDS = [
877
+ ["pnpm-lock.yaml", "pnpm install"],
878
+ ["yarn.lock", "yarn install"],
879
+ ["package-lock.json", "npm install"]
880
+ ];
881
+ function lockfileCommandAt(dir) {
882
+ return LOCKFILE_COMMANDS.find(([file]) => existsSync2(path3.join(dir, file)))?.[1];
883
+ }
884
+ function isWorkspaceRootDir(dir) {
885
+ if (isFile(path3.join(dir, "pnpm-workspace.yaml"))) return true;
886
+ let parsed;
887
+ try {
888
+ parsed = JSON.parse(readFileSync3(path3.join(dir, "package.json"), "utf8"));
889
+ } catch {
890
+ return false;
891
+ }
892
+ if (!isPlainObject(parsed)) return false;
893
+ const ws = parsed.workspaces;
894
+ return Array.isArray(ws) || isPlainObject(ws) && Array.isArray(ws.packages);
895
+ }
896
+ function findWorkspaceRoot(baseDirInput) {
897
+ let dir = path3.resolve(baseDirInput);
898
+ for (; ; ) {
899
+ if (isWorkspaceRootDir(dir)) return dir;
900
+ if (existsSync2(path3.join(dir, ".git"))) return void 0;
901
+ const parent = path3.dirname(dir);
902
+ if (parent === dir) return void 0;
903
+ dir = parent;
904
+ }
905
+ }
906
+ function detectInstallCommand(baseDirInput) {
907
+ const baseDir = path3.resolve(baseDirInput);
908
+ const own = lockfileCommandAt(baseDir);
909
+ if (own !== void 0) return own;
910
+ const root = findWorkspaceRoot(baseDir);
911
+ if (root !== void 0 && root !== baseDir) {
912
+ const fromRoot = lockfileCommandAt(root);
913
+ if (fromRoot !== void 0) return fromRoot;
914
+ }
874
915
  return "pnpm install";
875
916
  }
876
917
  function hasDependency(pkg, name) {
@@ -969,8 +1010,8 @@ function compareExactVersions(a, b) {
969
1010
  }
970
1011
 
971
1012
  // ../axis-registry-core/src/template/tailwind-core.ts
972
- import { existsSync as existsSync3, lstatSync, readdirSync, readFileSync as readFileSync4 } from "fs";
973
- import { extname, join as join2, resolve } from "path";
1013
+ import { existsSync as existsSync3, lstatSync, readdirSync, readFileSync as readFileSync4, realpathSync } from "fs";
1014
+ import { basename, dirname as dirname2, extname, isAbsolute, join as join2, relative, resolve, sep } from "path";
974
1015
  function hasDependency2(pkg, name) {
975
1016
  for (const field of ["dependencies", "devDependencies"]) {
976
1017
  const deps = pkg[field];
@@ -1052,22 +1093,17 @@ function majorFromVersion(version) {
1052
1093
  }
1053
1094
  function detectTailwind(baseDirInput, pkg) {
1054
1095
  const baseDir = resolve(baseDirInput);
1055
- const installedFile = join2(baseDir, "node_modules", "tailwindcss", "package.json");
1056
1096
  const declared = pkg ? hasDependency2(pkg, "tailwindcss") : void 0;
1057
1097
  const bounds = declared !== void 0 ? tailwindMajorBounds(declared) : void 0;
1058
1098
  const declaredMajor = bounds?.lower;
1059
- try {
1060
- const installed = JSON.parse(readFileSync4(installedFile, "utf8"));
1061
- const version = isPlainObject2(installed) ? installed.version : void 0;
1062
- const major = majorFromVersion(version);
1063
- if (major !== void 0) {
1064
- const found = { major, source: "installed", value: String(version) };
1065
- if (declared !== void 0 && bounds !== void 0 && !majorWithin(major, bounds)) {
1066
- found.mismatch = { declared, declaredMajor: bounds.lower };
1067
- }
1068
- return found;
1099
+ const version = isPnpProject(baseDir) ? void 0 : findInstalledPackage(baseDir, "tailwindcss")?.version;
1100
+ const major = majorFromVersion(version);
1101
+ if (version !== void 0 && major !== void 0) {
1102
+ const found = { major, source: "installed", value: version };
1103
+ if (declared !== void 0 && bounds !== void 0 && !majorWithin(major, bounds)) {
1104
+ found.mismatch = { declared, declaredMajor: bounds.lower };
1069
1105
  }
1070
- } catch {
1106
+ return found;
1071
1107
  }
1072
1108
  if (declared !== void 0) {
1073
1109
  if (declaredMajor !== void 0) return { major: declaredMajor, source: "declared", value: declared };
@@ -1210,19 +1246,9 @@ function rangeLowerAtLeast(range, min) {
1210
1246
  if (!lower || !target) return void 0;
1211
1247
  return compareLower(lower, target) >= 0;
1212
1248
  }
1213
- function exactVersion(version) {
1214
- if (typeof version !== "string") return void 0;
1215
- const v = version.trim();
1216
- if (!/^v?\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/.test(v) || /^v?0\.0\.0-/.test(v)) return void 0;
1217
- return v;
1218
- }
1219
- function installedVersion(baseDir, name) {
1220
- try {
1221
- const parsed = JSON.parse(readFileSync4(join2(baseDir, "node_modules", ...name.split("/"), "package.json"), "utf8"));
1222
- return isPlainObject2(parsed) ? exactVersion(parsed.version) : void 0;
1223
- } catch {
1224
- return void 0;
1225
- }
1249
+ function installedAxisVersion(baseDir, name) {
1250
+ if (isPnpProject(baseDir)) return void 0;
1251
+ return findInstalledPackage(baseDir, name)?.version;
1226
1252
  }
1227
1253
  function axisPackagesBelowTailwind4(pkg, baseDirInput) {
1228
1254
  if (!pkg) return [];
@@ -1232,7 +1258,7 @@ function axisPackagesBelowTailwind4(pkg, baseDirInput) {
1232
1258
  for (const name of TAILWIND4_AXIS_PACKAGES) {
1233
1259
  const range = hasDependency2(pkg, name);
1234
1260
  if (range === void 0 || range.trim().startsWith("workspace:")) continue;
1235
- const installed = baseDir !== void 0 ? installedVersion(baseDir, name) : void 0;
1261
+ const installed = baseDir !== void 0 ? installedAxisVersion(baseDir, name) : void 0;
1236
1262
  const installedLower = installed !== void 0 ? lowerOf(installed) : void 0;
1237
1263
  if (installed !== void 0 && installedLower !== void 0) {
1238
1264
  if (compareLower(installedLower, min) < 0) out.push({ name, range, status: "below", source: "installed", installed });
@@ -1528,6 +1554,92 @@ function contentGlobToRegExp(glob) {
1528
1554
  }
1529
1555
  return new RegExp(`^${re}$`);
1530
1556
  }
1557
+ function leadingParentSegments(p) {
1558
+ const s = p.trim().replace(/\\/g, "/").replace(/^\.\//, "");
1559
+ return (/^(?:\.\.\/)*/.exec(s)?.[0].length ?? 0) / 3;
1560
+ }
1561
+ function isAbsoluteGlob(glob) {
1562
+ const t = glob.trim();
1563
+ return t.startsWith("/") || /^[A-Za-z]:[\\/]/.test(t);
1564
+ }
1565
+ var MAX_BRACE_EXPANSION = 256;
1566
+ function expandBraces(glob) {
1567
+ const open = glob.indexOf("{");
1568
+ if (open === -1) return [glob];
1569
+ let depth = 0;
1570
+ let close = -1;
1571
+ const commas = [];
1572
+ for (let i = open; i < glob.length; i++) {
1573
+ const c = glob[i];
1574
+ if (c === "{") depth++;
1575
+ else if (c === "}") {
1576
+ depth--;
1577
+ if (depth === 0) {
1578
+ close = i;
1579
+ break;
1580
+ }
1581
+ } else if (c === "," && depth === 1) commas.push(i);
1582
+ }
1583
+ const head = glob.slice(0, open + 1);
1584
+ if (close === -1 || commas.length === 0) {
1585
+ return expandBraces(glob.slice(open + 1))?.map((r) => head + r);
1586
+ }
1587
+ const parts = [];
1588
+ let from = open + 1;
1589
+ for (const c of [...commas, close]) {
1590
+ parts.push(glob.slice(from, c));
1591
+ from = c + 1;
1592
+ }
1593
+ const prefix = glob.slice(0, open);
1594
+ const suffix = glob.slice(close + 1);
1595
+ const out = [];
1596
+ for (const part of parts) {
1597
+ const expanded = expandBraces(prefix + part + suffix);
1598
+ if (expanded === void 0) return void 0;
1599
+ out.push(...expanded);
1600
+ if (out.length > MAX_BRACE_EXPANSION) return void 0;
1601
+ }
1602
+ return out;
1603
+ }
1604
+ function realpathPosix(p) {
1605
+ let cur = p;
1606
+ const tail = [];
1607
+ for (let i = 0; i < 64; i++) {
1608
+ try {
1609
+ return [realpathSync(cur), ...tail].join(sep).split(sep).join("/");
1610
+ } catch {
1611
+ const parent = dirname2(cur);
1612
+ if (parent === cur) return void 0;
1613
+ tail.unshift(basename(cur));
1614
+ cur = parent;
1615
+ }
1616
+ }
1617
+ return void 0;
1618
+ }
1619
+ function contentGlobBranchCovers(glob, sample, baseDir) {
1620
+ if (isAbsoluteGlob(glob)) {
1621
+ const re = contentGlobToRegExp(glob.trim().replace(/\\/g, "/"));
1622
+ const absSample = resolve(baseDir, sample);
1623
+ if (re.test(absSample.split(sep).join("/"))) return true;
1624
+ const real = realpathPosix(absSample);
1625
+ return real !== void 0 && re.test(real);
1626
+ }
1627
+ return leadingParentSegments(glob) === leadingParentSegments(sample) && contentGlobToRegExp(glob).test(sample);
1628
+ }
1629
+ function contentGlobCovers(glob, sample, baseDir) {
1630
+ const branches = expandBraces(glob.trim()) ?? [glob];
1631
+ return branches.some((b) => contentGlobBranchCovers(b, sample, baseDir));
1632
+ }
1633
+ var CONTENT_PARENT_PATH_NOTE = "\uC0C1\uC704 \uACBD\uB85C\uB294 Tailwind 3 \uAC00 \uBE4C\uB4DC\uB97C \uC2E4\uD589\uD55C \uB514\uB809\uD130\uB9AC \uAE30\uC900\uC73C\uB85C \uD480\uB824\uC694. \uBAA8\uB178\uB808\uD3EC \uB8E8\uD2B8 \uB4F1 \uC571 \uB514\uB809\uD130\uB9AC \uBC16\uC5D0\uC11C \uBE4C\uB4DC\uD558\uBA74 content: { relative: true, files: [...] } \uB85C \uC124\uC815 \uD30C\uC77C \uAE30\uC900\uC73C\uB85C \uBC14\uAFB8\uC138\uC694";
1634
+ function packageContentTarget(baseDir, name) {
1635
+ const found = isPnpProject(baseDir) ? void 0 : findInstalledPackage(baseDir, name);
1636
+ const rel2 = found === void 0 ? void 0 : relative(baseDir, found.dir);
1637
+ const relDir = rel2 === void 0 || rel2 === "" || isAbsolute(rel2) ? `node_modules/${name}` : rel2.split(sep).join("/");
1638
+ return {
1639
+ sample: `${relDir}/dist/index.js`,
1640
+ suggest: `${relDir.startsWith("../") ? "" : "./"}${relDir}/dist/**/*.{js,mjs}`
1641
+ };
1642
+ }
1531
1643
  function balancedSlice(src, start) {
1532
1644
  const open = src[start];
1533
1645
  const close = open === "[" ? "]" : "}";
@@ -1589,17 +1701,17 @@ function inspectTailwindContent(baseDirInput) {
1589
1701
  }
1590
1702
  for (const name of TAILWIND4_COMPONENT_PACKAGES) {
1591
1703
  if (pkg !== void 0 && hasDependency2(pkg, name) !== void 0) {
1592
- targets.push({ label: name, sample: `node_modules/${name}/dist/index.js`, suggest: `./node_modules/${name}/dist/**/*.{js,mjs}` });
1704
+ targets.push({ label: name, ...packageContentTarget(baseDir, name) });
1593
1705
  }
1594
1706
  }
1595
1707
  if (targets.length === 0) return null;
1596
1708
  const read = readTailwindContent(readFileSync4(join2(baseDir, configFile), "utf8"));
1597
- const patterns = (read?.globs ?? []).filter((g) => !g.trim().startsWith("!")).map(contentGlobToRegExp);
1709
+ const globs = (read?.globs ?? []).filter((g) => !g.trim().startsWith("!"));
1598
1710
  return {
1599
1711
  configFile,
1600
1712
  unreadable: read === void 0,
1601
1713
  dynamic: read?.dynamic ?? false,
1602
- targets: targets.map((t) => ({ ...t, covered: patterns.some((re) => re.test(t.sample)) }))
1714
+ targets: targets.map((t) => ({ ...t, covered: globs.some((g) => contentGlobCovers(g, t.sample, baseDir)) }))
1603
1715
  };
1604
1716
  }
1605
1717
  function checkTailwindContent(baseDir) {
@@ -1614,17 +1726,18 @@ function checkTailwindContent(baseDir) {
1614
1726
  };
1615
1727
  }
1616
1728
  const list = missing.map((t) => `${t.label} \u2192 "${t.suggest}"`).join(" \xB7 ");
1729
+ const note = missing.some((t) => t.suggest.startsWith("../")) ? ` (${CONTENT_PARENT_PATH_NOTE})` : "";
1617
1730
  if (r.unreadable || r.dynamic) {
1618
1731
  return {
1619
1732
  name: "tailwind.content",
1620
1733
  severity: "warn",
1621
- message: `${r.configFile}\uC758 content \uB97C \uC815\uC801\uC73C\uB85C \uB2E4 \uC77D\uC9C0 \uBABB\uD574 \uD655\uC778\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4: ${list}`
1734
+ message: `${r.configFile}\uC758 content \uB97C \uC815\uC801\uC73C\uB85C \uB2E4 \uC77D\uC9C0 \uBABB\uD574 \uD655\uC778\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4: ${list}${note}`
1622
1735
  };
1623
1736
  }
1624
1737
  return {
1625
1738
  name: "tailwind.content",
1626
1739
  severity: "fail",
1627
- message: `${r.configFile}\uC758 content \uAC00 \uCEF4\uD3EC\uB10C\uD2B8 \uACBD\uB85C\uB97C \uB36E\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4(\uD074\uB798\uC2A4\uAC00 \uC0DD\uC131\uB418\uC9C0 \uC54A\uC74C): ${list}`
1740
+ message: `${r.configFile}\uC758 content \uAC00 \uCEF4\uD3EC\uB10C\uD2B8 \uACBD\uB85C\uB97C \uB36E\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4(\uD074\uB798\uC2A4\uAC00 \uC0DD\uC131\uB418\uC9C0 \uC54A\uC74C): ${list}${note}`
1628
1741
  };
1629
1742
  }
1630
1743
  var ANIMATION_PLUGIN_TAILWIND3 = "tailwindcss-animate";
@@ -1778,7 +1891,7 @@ function selectUtilsDependencies(tailwind) {
1778
1891
  }
1779
1892
 
1780
1893
  // ../axis-registry-core/src/add/safe-write.ts
1781
- import { constants as fsConstants, existsSync as existsSync4, lstatSync as lstatSync2, realpathSync, statSync as statSync2 } from "fs";
1894
+ import { constants as fsConstants, existsSync as existsSync4, lstatSync as lstatSync2, realpathSync as realpathSync2, statSync as statSync2 } from "fs";
1782
1895
  import path4 from "path";
1783
1896
  import fs2 from "fs-extra";
1784
1897
  var NEW_FILE_FLAGS = fsConstants.O_WRONLY | fsConstants.O_CREAT | fsConstants.O_EXCL | (fsConstants.O_NOFOLLOW ?? 0);
@@ -1805,12 +1918,12 @@ function nearestExisting(p) {
1805
1918
  return cur;
1806
1919
  }
1807
1920
  function escapeReason(root, target, options = {}) {
1808
- const realRoot = realpathSync(root);
1921
+ const realRoot = realpathSync2(root);
1809
1922
  if (!isSameOrInside(path4.resolve(root), path4.resolve(target)) || path4.resolve(target) === path4.resolve(root)) {
1810
1923
  return `\uACBD\uB85C\uAC00 \uD504\uB85C\uC81D\uD2B8 \uB514\uB809\uD130\uB9AC \uBC16\uC785\uB2C8\uB2E4(${target})`;
1811
1924
  }
1812
1925
  const anchor = nearestExisting(path4.dirname(target));
1813
- const realAnchor = realpathSync(anchor);
1926
+ const realAnchor = realpathSync2(anchor);
1814
1927
  if (!isSameOrInside(realRoot, realAnchor)) {
1815
1928
  return `\uC0C1\uC704 \uB514\uB809\uD130\uB9AC\uC758 \uC2E4\uC81C \uC704\uCE58(${realAnchor})\uAC00 \uD504\uB85C\uC81D\uD2B8 \uB514\uB809\uD130\uB9AC \uBC16\uC785\uB2C8\uB2E4`;
1816
1929
  }
@@ -1825,7 +1938,7 @@ function escapeReason(root, target, options = {}) {
1825
1938
  const shown = path4.relative(path4.resolve(root), path4.resolve(target)).split(path4.sep).join("/");
1826
1939
  let realTarget;
1827
1940
  try {
1828
- realTarget = realpathSync(target);
1941
+ realTarget = realpathSync2(target);
1829
1942
  } catch {
1830
1943
  return `\uAE30\uC874 \uD30C\uC77C ${shown} \uC774 \uAE68\uC9C4 \uC2EC\uBCFC\uB9AD \uB9C1\uD06C\uB77C \uB530\uB77C\uAC08 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4(\uB9C1\uD06C\uB97C \uC9C0\uC6B0\uAC70\uB098 \uACE0\uCE5C \uB4A4 \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694)`;
1831
1944
  }
@@ -1858,8 +1971,8 @@ function isSymlink(p) {
1858
1971
  function outsideLinkTarget(root, target) {
1859
1972
  if (!isSymlink(target)) return null;
1860
1973
  try {
1861
- const realTarget = realpathSync(target);
1862
- return isSameOrInside(realpathSync(root), realTarget) ? null : realTarget;
1974
+ const realTarget = realpathSync2(target);
1975
+ return isSameOrInside(realpathSync2(root), realTarget) ? null : realTarget;
1863
1976
  } catch {
1864
1977
  return null;
1865
1978
  }
@@ -1876,10 +1989,10 @@ function hardLinkMessage(shownPath, nlink) {
1876
1989
  return `\uAE30\uC874 \uD30C\uC77C ${shownPath} \uC774 \uB2E4\uB978 \uACBD\uB85C\uC640 \uD558\uB4DC\uB9C1\uD06C\uB85C \uC774\uC5B4\uC9C4 \uD30C\uC77C\uC774\uB77C(\uB9C1\uD06C \uC218 ${nlink}) \uB36E\uC5B4\uC4F0\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uB36E\uC5B4\uC4F0\uBA74 \uC774\uC5B4\uC9C4 \uB2E4\uB978 \uACBD\uB85C\uC758 \uB0B4\uC6A9\uB3C4 \uBC14\uB01D\uB2C8\uB2E4. \uD558\uB4DC\uB9C1\uD06C\uB97C \uB04A\uC740(\uD30C\uC77C\uC744 \uBCF5\uC0AC\uD574 \uBC14\uAFBC) \uB4A4 \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694`;
1877
1990
  }
1878
1991
  function writtenOutside(root, target) {
1879
- const realRoot = realpathSync(root);
1992
+ const realRoot = realpathSync2(root);
1880
1993
  let realTarget;
1881
1994
  try {
1882
- realTarget = realpathSync(target);
1995
+ realTarget = realpathSync2(target);
1883
1996
  } catch {
1884
1997
  return target;
1885
1998
  }
@@ -1913,8 +2026,8 @@ async function writeNoFollow(target, content, mode) {
1913
2026
  return actual;
1914
2027
  }
1915
2028
  function checkParentInside(root, target) {
1916
- const realRoot = realpathSync(root);
1917
- const realParent = realpathSync(path4.dirname(target));
2029
+ const realRoot = realpathSync2(root);
2030
+ const realParent = realpathSync2(path4.dirname(target));
1918
2031
  if (!isSameOrInside(realRoot, realParent)) {
1919
2032
  return `\uBD80\uBAA8 \uB514\uB809\uD130\uB9AC\uC758 \uC2E4\uC81C \uC704\uCE58(${realParent})\uAC00 \uD504\uB85C\uC81D\uD2B8 \uB514\uB809\uD130\uB9AC \uBC16\uC785\uB2C8\uB2E4`;
1920
2033
  }
@@ -2727,20 +2840,36 @@ function formatComponentDetail(result) {
2727
2840
  }
2728
2841
  return lines.join("\n");
2729
2842
  }
2730
- function formatTokenDetail(token) {
2843
+ function cssUsage(token) {
2844
+ const shadcnColor = !token.cssVariable.startsWith("--axis-") && token.value.startsWith("hsl(");
2845
+ return shadcnColor ? `hsl(var(${token.cssVariable}))` : `var(${token.cssVariable})`;
2846
+ }
2847
+ function formatTokenNotFound(path11) {
2848
+ return [
2849
+ `\uD1A0\uD070\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: \`${path11}\``,
2850
+ "",
2851
+ "- \uACBD\uB85C\uB294 `axis.list_tokens` \uB85C \uD655\uC778\uD558\uC138\uC694. \uACBD\uB85C \xB7 tokens \uC774\uB984 \uAE30\uBC18 \uACBD\uB85C(\uC608: `control.h.md`) \xB7 CSS \uBCC0\uC218 \uC774\uB984(\uC608: `--axis-control-h-md`)\uC744 \uBC1B\uC2B5\uB2C8\uB2E4.",
2852
+ "- \uBE0C\uB79C\uB4DC \uAC12\uC740 `axis.list_brands` \xB7 `axis.get_brand` \uB85C \uC870\uD68C\uD558\uC138\uC694."
2853
+ ].join("\n");
2854
+ }
2855
+ function formatTokenDetail(token, query = "") {
2731
2856
  if (!token) {
2732
- return "\uD1A0\uD070\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.";
2857
+ return formatTokenNotFound(query);
2733
2858
  }
2734
2859
  const lines = [];
2735
2860
  lines.push(`# \uD1A0\uD070: ${token.path}`);
2736
2861
  lines.push("");
2737
2862
  lines.push(`- **\uAC12**: \`${token.value}\``);
2863
+ if (token.dark !== void 0) {
2864
+ lines.push(`- **\uB2E4\uD06C \uAC12**: \`${token.dark}\`${token.dark === token.value ? " (\uB77C\uC774\uD2B8\uC640 \uAC19\uC74C)" : ""}`);
2865
+ }
2738
2866
  lines.push(`- **\uCE74\uD14C\uACE0\uB9AC**: ${token.category}`);
2739
2867
  if (token.description) {
2740
2868
  lines.push(`- **\uC124\uBA85**: ${token.description}`);
2741
2869
  }
2742
- if (token.cssVariable) {
2743
- lines.push(`- **CSS \uBCC0\uC218**: \`var(${token.cssVariable})\``);
2870
+ lines.push(`- **CSS \uBCC0\uC218**: \`${token.cssVariable}\` (\uC0AC\uC6A9: \`${cssUsage(token)}\`)`);
2871
+ if (token.aliases && token.aliases.length > 0) {
2872
+ lines.push(`- **\uD568\uAED8 \uBC1B\uB294 \uACBD\uB85C**: ${token.aliases.map((a) => `\`${a}\``).join(", ")}`);
2744
2873
  }
2745
2874
  return lines.join("\n");
2746
2875
  }
@@ -2776,7 +2905,8 @@ function handleListTokens(params) {
2776
2905
  tokens,
2777
2906
  totalCount: tokens.length,
2778
2907
  stats,
2779
- category
2908
+ category,
2909
+ sourceVersion: getTokenSource()?.version
2780
2910
  };
2781
2911
  }
2782
2912
  function formatComponentList(result) {
@@ -2821,41 +2951,51 @@ function formatComponentList(result) {
2821
2951
  lines.push("\uC124\uCE58: `axis.install_component` \uC5D0 `name`(\uB610\uB294 `names`)\uACFC \uD504\uB85C\uC81D\uD2B8 \uB8E8\uD2B8 `targetDir` \uB97C \uC8FC\uC138\uC694. \uC774\uB984\uC740 \uC704 \uD45C\uC758 \uC774\uB984 \uADF8\uB300\uB85C\uC785\uB2C8\uB2E4(agentic \uC740 `agentic-` \uC811\uB450 \uD3EC\uD568).");
2822
2952
  return lines.join("\n");
2823
2953
  }
2954
+ var TOKEN_CATEGORY_LABELS = {
2955
+ color: "Color",
2956
+ typography: "Typography",
2957
+ spacing: "Spacing",
2958
+ radius: "Radius",
2959
+ shadow: "Shadow",
2960
+ density: "Density (\uBC00\uB3C4)",
2961
+ component: "Component"
2962
+ };
2963
+ var cell = (v) => v.replace(/\|/g, "\\|");
2824
2964
  function formatTokenList(result) {
2825
2965
  const lines = [];
2966
+ const total = TOKEN_CATEGORIES.reduce((n, c) => n + result.stats[c], 0);
2826
2967
  lines.push("# AXIS Design System \uD1A0\uD070 \uBAA9\uB85D");
2827
2968
  lines.push("");
2969
+ if (result.sourceVersion) {
2970
+ lines.push(`- **\uCD9C\uCC98**: @axis-ds/tokens ${result.sourceVersion} \uBE4C\uB4DC \uC0B0\uCD9C\uBB3C\uC5D0\uC11C \uC0DD\uC131(\uB77C\uC774\uD2B8 :root \xB7 \uB2E4\uD06C .dark)`);
2971
+ }
2972
+ lines.push("- **\uBE0C\uB79C\uB4DC \uAC12**: `axis.list_brands` \xB7 `axis.get_brand` \uB85C \uC870\uD68C\uD558\uC138\uC694(\uB300\uC0C1 \uD504\uB85C\uC81D\uD2B8\uC5D0 \uC124\uCE58\uB41C tokens \uB97C \uC77D\uC74C)");
2973
+ lines.push("");
2828
2974
  lines.push("## \uCE74\uD14C\uACE0\uB9AC\uBCC4 \uD1B5\uACC4");
2829
2975
  lines.push("| \uCE74\uD14C\uACE0\uB9AC | \uAC1C\uC218 |");
2830
2976
  lines.push("|----------|------|");
2831
- lines.push(`| Color | ${result.stats.color} |`);
2832
- lines.push(`| Typography | ${result.stats.typography} |`);
2833
- lines.push(`| Spacing | ${result.stats.spacing} |`);
2834
- lines.push(`| Radius | ${result.stats.radius} |`);
2835
- lines.push(`| Shadow | ${result.stats.shadow} |`);
2836
- lines.push(`| Animation | ${result.stats.animation} |`);
2837
- lines.push(`| **\uD569\uACC4** | **${result.totalCount}** |`);
2977
+ for (const c of TOKEN_CATEGORIES) {
2978
+ lines.push(`| ${TOKEN_CATEGORY_LABELS[c]} | ${result.stats[c]} |`);
2979
+ }
2980
+ lines.push(`| **\uD569\uACC4** | **${total}** |`);
2838
2981
  lines.push("");
2839
2982
  if (result.category) {
2840
- lines.push(`## ${result.category} \uD1A0\uD070`);
2983
+ lines.push(`## ${result.category} \uD1A0\uD070 (${result.totalCount}\uAC1C)`);
2841
2984
  } else {
2842
2985
  lines.push("## \uC804\uCCB4 \uD1A0\uD070");
2843
2986
  }
2844
2987
  lines.push("");
2845
- const grouped = {};
2846
- for (const token of result.tokens) {
2847
- if (!grouped[token.category]) {
2848
- grouped[token.category] = [];
2849
- }
2850
- grouped[token.category].push(token);
2851
- }
2852
- for (const [category, tokens] of Object.entries(grouped)) {
2853
- lines.push(`### ${category.charAt(0).toUpperCase() + category.slice(1)}`);
2854
- lines.push("| \uACBD\uB85C | \uAC12 | \uC124\uBA85 |");
2855
- lines.push("|------|-----|------|");
2988
+ for (const c of TOKEN_CATEGORIES) {
2989
+ const tokens = result.tokens.filter((t) => t.category === c);
2990
+ if (tokens.length === 0) continue;
2991
+ lines.push(`### ${TOKEN_CATEGORY_LABELS[c]}`);
2992
+ lines.push("| \uACBD\uB85C | \uAC12 | \uB2E4\uD06C | CSS | \uC124\uBA85 |");
2993
+ lines.push("|------|-----|------|-----|------|");
2856
2994
  for (const t of tokens) {
2857
- const desc = t.description || "-";
2858
- lines.push(`| \`${t.path}\` | \`${t.value}\` | ${desc} |`);
2995
+ const dark = t.dark === void 0 ? "-" : t.dark === t.value ? "(\uAC19\uC74C)" : `\`${cell(t.dark)}\``;
2996
+ lines.push(
2997
+ `| \`${t.path}\` | \`${cell(t.value)}\` | ${dark} | \`${cssUsage(t)}\` | ${t.description ? cell(t.description) : "-"} |`
2998
+ );
2859
2999
  }
2860
3000
  lines.push("");
2861
3001
  }
@@ -4409,7 +4549,7 @@ import path9 from "path";
4409
4549
  // src/tools/brand-core.ts
4410
4550
  import { existsSync as existsSync8, readFileSync as readFileSync8, statSync as statSync5 } from "fs";
4411
4551
  import { createRequire } from "module";
4412
- import { dirname as dirname3, join as join4, relative, resolve as resolve3, sep } from "path";
4552
+ import { dirname as dirname4, join as join4, relative as relative2, resolve as resolve3, sep as sep2 } from "path";
4413
4553
  var TOKENS_PACKAGE = "@axis-ds/tokens";
4414
4554
  var MIN_BRAND_TOKENS_VERSION = "1.3.0";
4415
4555
  var TOKENS_DEPENDENCY_MIN_VERSION = "1.6.0";
@@ -4439,7 +4579,7 @@ function findTokensPackageJson(baseDir) {
4439
4579
  for (; ; ) {
4440
4580
  const candidate = join4(dir, "node_modules", TOKENS_PACKAGE, "package.json");
4441
4581
  if (existsSync8(candidate)) return candidate;
4442
- const parent = dirname3(dir);
4582
+ const parent = dirname4(dir);
4443
4583
  if (parent === dir) return void 0;
4444
4584
  dir = parent;
4445
4585
  }
@@ -4523,7 +4663,7 @@ function inspectBrandImport(baseDir) {
4523
4663
  if (!location.path) {
4524
4664
  return { ...base, state: "css-missing", imports: [] };
4525
4665
  }
4526
- const cssFile = relative(root, location.path).split(sep).join("/");
4666
+ const cssFile = relative2(root, location.path).split(sep2).join("/");
4527
4667
  const imports = [...new Set(findBrandImports(readFileSync8(location.path, "utf8")))];
4528
4668
  let state;
4529
4669
  if (imports.includes(brand)) state = "match";
@@ -4639,7 +4779,7 @@ function findBrandActivation(baseDir) {
4639
4779
  const providerTexts = [];
4640
4780
  for (const m of text.matchAll(/from\s+["']\.\/(providers?)["']/g)) {
4641
4781
  for (const ext of [".tsx", ".jsx", ".ts", ".js"]) {
4642
- const rel2 = `${dirname3(candidate)}/${m[1]}${ext}`;
4782
+ const rel2 = `${dirname4(candidate)}/${m[1]}${ext}`;
4643
4783
  const p = join4(root, rel2);
4644
4784
  if (isFile2(p)) providerTexts.push({ rel: rel2, text: stripJsLikeComments(readFileSync8(p, "utf8")) });
4645
4785
  }
@@ -4722,6 +4862,16 @@ function declaredAxisPackages(pkg) {
4722
4862
  }
4723
4863
  return out;
4724
4864
  }
4865
+ function workspaceRootPackage(baseDir) {
4866
+ const root = findWorkspaceRoot(baseDir);
4867
+ if (root === void 0 || root === baseDir) return void 0;
4868
+ try {
4869
+ const parsed = JSON.parse(readFileSync9(join5(root, "package.json"), "utf8"));
4870
+ return isPlainObject(parsed) ? parsed : void 0;
4871
+ } catch {
4872
+ return void 0;
4873
+ }
4874
+ }
4725
4875
  function checkDependencies(baseDirInput) {
4726
4876
  const baseDir = resolve4(baseDirInput);
4727
4877
  let pkg;
@@ -4735,13 +4885,17 @@ function checkDependencies(baseDirInput) {
4735
4885
  }
4736
4886
  return { name: "dependencies", severity: "fail", message: "package.json \uC744 \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4(JSON \uD655\uC778)" };
4737
4887
  }
4738
- const missingRequired = REQUIRED_DEPENDENCIES.filter((d) => !hasDependency(pkg, d));
4888
+ const rootPkg = workspaceRootPackage(baseDir);
4889
+ const fromRoot = (d) => !hasDependency(pkg, d) && rootPkg !== void 0 && Boolean(hasDependency(rootPkg, d));
4890
+ const missingRequired = REQUIRED_DEPENDENCIES.filter((d) => !hasDependency(pkg, d) && !fromRoot(d));
4739
4891
  if (missingRequired.length > 0) {
4740
4892
  return { name: "dependencies", severity: "fail", message: `\uD544\uC218 \uC758\uC874\uC131 \uB204\uB77D: ${missingRequired.join(", ")}` };
4741
4893
  }
4742
- const missingRecommended = RECOMMENDED_DEPENDENCIES.filter((d) => !hasDependency(pkg, d));
4894
+ const missingRecommended = RECOMMENDED_DEPENDENCIES.filter((d) => !hasDependency(pkg, d) && !fromRoot(d));
4895
+ const rootDeclared = [...REQUIRED_DEPENDENCIES, ...RECOMMENDED_DEPENDENCIES].filter((d) => fromRoot(d));
4896
+ const rootNote = rootDeclared.length > 0 ? `\uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uB8E8\uD2B8\uC5D0 \uC120\uC5B8: ${rootDeclared.join(", ")}` : void 0;
4743
4897
  const targets = [
4744
- ...[...REQUIRED_DEPENDENCIES, ...RECOMMENDED_DEPENDENCIES].filter((d) => hasDependency(pkg, d) !== void 0),
4898
+ ...[...REQUIRED_DEPENDENCIES, ...RECOMMENDED_DEPENDENCIES].filter((d) => hasDependency(pkg, d) !== void 0 || fromRoot(d)),
4745
4899
  ...declaredAxisPackages(pkg)
4746
4900
  ];
4747
4901
  const pnp = isPnpProject(baseDir);
@@ -4751,11 +4905,14 @@ function checkDependencies(baseDirInput) {
4751
4905
  if (notInstalled.length > 0) {
4752
4906
  problems.push(`\uC120\uC5B8\uB410\uC9C0\uB9CC \uC124\uCE58\uB418\uC9C0 \uC54A\uC740 \uC758\uC874\uC131: ${notInstalled.join(", ")} \u2192 ${detectInstallCommand(baseDir)}`);
4753
4907
  }
4754
- if (problems.length > 0) return { name: "dependencies", severity: "warn", message: problems.join(" / ") };
4908
+ if (problems.length > 0) {
4909
+ return { name: "dependencies", severity: "warn", message: problems.join(" / ") + (rootNote ? ` (${rootNote})` : "") };
4910
+ }
4911
+ const note = rootNote ? `, ${rootNote}` : "";
4755
4912
  return {
4756
4913
  name: "dependencies",
4757
4914
  severity: "pass",
4758
- 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)`
4915
+ 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${note})` : `\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${note})`
4759
4916
  };
4760
4917
  }
4761
4918
 
@@ -5233,7 +5390,7 @@ var server = new McpServer({
5233
5390
  version: SERVER_VERSION
5234
5391
  });
5235
5392
  var ComponentCategorySchema = z.enum(["core", "agentic", "form", "layout", "ui"]).optional().describe("\uCEF4\uD3EC\uB10C\uD2B8 \uCE74\uD14C\uACE0\uB9AC \uD544\uD130 (ui = Core UI \uC804\uCCB4, agentic = Agentic UI)");
5236
- var TokenCategorySchema = z.enum(["color", "typography", "spacing", "radius", "shadow", "animation"]).optional().describe("\uD1A0\uD070 \uCE74\uD14C\uACE0\uB9AC \uD544\uD130");
5393
+ var TokenCategorySchema = z.enum(TOKEN_CATEGORIES).optional().describe("\uD1A0\uD070 \uCE74\uD14C\uACE0\uB9AC \uD544\uD130 (density = \uCEE8\uD2B8\uB864 \uB192\uC774 \xB7 \uAE00\uC790 \uD06C\uAE30 \uB4F1 \uBC00\uB3C4 \uD1A0\uD070, component = \uCEF4\uD3EC\uB10C\uD2B8 \uD1A0\uD070)");
5237
5394
  server.tool(
5238
5395
  "axis.search_components",
5239
5396
  "AXIS \uB514\uC790\uC778 \uC2DC\uC2A4\uD15C\uC5D0\uC11C \uCEF4\uD3EC\uB10C\uD2B8\uB97C \uAC80\uC0C9\uD569\uB2C8\uB2E4.",
@@ -5338,7 +5495,7 @@ server.tool(
5338
5495
  );
5339
5496
  server.tool(
5340
5497
  "axis.list_tokens",
5341
- "AXIS \uB514\uC790\uC778 \uC2DC\uC2A4\uD15C\uC758 \uB514\uC790\uC778 \uD1A0\uD070 \uBAA9\uB85D\uC744 \uC870\uD68C\uD569\uB2C8\uB2E4.",
5498
+ "AXIS \uB514\uC790\uC778 \uC2DC\uC2A4\uD15C\uC758 \uB514\uC790\uC778 \uD1A0\uD070 \uBAA9\uB85D(\uB77C\uC774\uD2B8 \xB7 \uB2E4\uD06C \uAC12, CSS \uBCC0\uC218)\uC744 \uC870\uD68C\uD569\uB2C8\uB2E4. \uAC12\uC740 @axis-ds/tokens \uBE4C\uB4DC \uC0B0\uCD9C\uBB3C\uC5D0\uC11C \uC0DD\uC131\uD569\uB2C8\uB2E4.",
5342
5499
  {
5343
5500
  category: TokenCategorySchema
5344
5501
  },
@@ -5372,21 +5529,23 @@ server.tool(
5372
5529
  );
5373
5530
  server.tool(
5374
5531
  "axis.get_token",
5375
- "AXIS \uB514\uC790\uC778 \uC2DC\uC2A4\uD15C \uD1A0\uD070\uC758 \uC0C1\uC138 \uC815\uBCF4\uB97C \uC870\uD68C\uD569\uB2C8\uB2E4.",
5532
+ "AXIS \uB514\uC790\uC778 \uC2DC\uC2A4\uD15C \uD1A0\uD070\uC758 \uC0C1\uC138 \uC815\uBCF4(\uB77C\uC774\uD2B8 \xB7 \uB2E4\uD06C \uAC12, CSS \uBCC0\uC218)\uB97C \uC870\uD68C\uD569\uB2C8\uB2E4. \uC5C6\uB294 \uACBD\uB85C\uB294 isError \uB85C \uB2F5\uD569\uB2C8\uB2E4.",
5376
5533
  {
5377
- path: z.string().describe("\uD1A0\uD070 \uACBD\uB85C (\uC608: colors.primary, spacing.4)")
5534
+ path: z.string().describe("\uD1A0\uD070 \uACBD\uB85C (\uC608: colors.primary, spacing.4, control.h.md) \uB610\uB294 CSS \uBCC0\uC218 \uC774\uB984 (\uC608: --axis-control-h-md)")
5378
5535
  },
5379
5536
  async ({ path: path11 }) => {
5380
5537
  try {
5381
5538
  const token = handleGetToken({ path: path11 });
5382
- const formatted = formatTokenDetail(token);
5539
+ const formatted = formatTokenDetail(token, path11);
5383
5540
  return {
5384
5541
  content: [
5385
5542
  {
5386
5543
  type: "text",
5387
5544
  text: formatted
5388
5545
  }
5389
- ]
5546
+ ],
5547
+ // WI-0076: 없는 토큰은 일반 텍스트가 아니라 오류로 답합니다(응답 계약 변경)
5548
+ ...token ? {} : { isError: true }
5390
5549
  };
5391
5550
  } catch (error) {
5392
5551
  const message = error instanceof Error ? error.message : "\uC54C \uC218 \uC5C6\uB294 \uC624\uB958";