@axis-ds/mcp 1.4.5 → 1.4.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +632 -116
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -77,7 +77,7 @@ function getTokenStats() {
77
77
  }
78
78
 
79
79
  // ../axis-registry-core/src/add/add.ts
80
- import { existsSync as existsSync5, readFileSync as readFileSync5, statSync as statSync3 } from "fs";
80
+ import { existsSync as existsSync5, readFileSync as readFileSync5, statSync as statSync4 } from "fs";
81
81
  import path5 from "path";
82
82
  import fs3 from "fs-extra";
83
83
 
@@ -871,7 +871,7 @@ var RegistryClient = class {
871
871
  };
872
872
 
873
873
  // ../axis-registry-core/src/project.ts
874
- import { existsSync as existsSync2, readFileSync as readFileSync3, realpathSync, statSync } from "fs";
874
+ import { existsSync as existsSync2, readdirSync, readFileSync as readFileSync3, realpathSync, statSync } from "fs";
875
875
  import path3 from "path";
876
876
  function resolveBaseDir(baseDirInput) {
877
877
  const resolved = path3.resolve(baseDirInput);
@@ -1062,6 +1062,32 @@ function isFile(file) {
1062
1062
  return false;
1063
1063
  }
1064
1064
  }
1065
+ function selectGlobalCss(baseDir, configured, candidates, options = {}) {
1066
+ const result = {};
1067
+ if (typeof configured === "string" && configured.trim() !== "") {
1068
+ const file = path3.resolve(baseDir, configured);
1069
+ if (!isFile(file)) result.configuredMissing = configured;
1070
+ else if (options.requireStylesheet && path3.extname(file).toLowerCase() !== ".css") result.configuredRejected = configured;
1071
+ else return { path: file, rel: path3.relative(baseDir, file).split(path3.sep).join("/") };
1072
+ }
1073
+ for (const candidate of candidates) {
1074
+ const file = path3.join(baseDir, candidate);
1075
+ if (isFile(file)) {
1076
+ result.path = file;
1077
+ result.rel = candidate;
1078
+ break;
1079
+ }
1080
+ }
1081
+ return result;
1082
+ }
1083
+ function globalCssSelectionNote(selection) {
1084
+ if (selection.configuredMissing !== void 0) return ` (globalCss ${selection.configuredMissing} \uC5C6\uC74C)`;
1085
+ if (selection.configuredRejected !== void 0) return ` (globalCss ${selection.configuredRejected}: .css \uD30C\uC77C\uC774 \uC544\uB2D8)`;
1086
+ return "";
1087
+ }
1088
+ function cssImportViaNote(files) {
1089
+ return files !== void 0 && files.length > 0 ? ` (${files.join(" \xB7 ")} \uC758 import)` : "";
1090
+ }
1065
1091
  var ROOT_LAYOUT_FILES = [
1066
1092
  "app/layout.tsx",
1067
1093
  "app/layout.jsx",
@@ -1105,15 +1131,174 @@ function findInstalledPackage(baseDirInput, name) {
1105
1131
  }
1106
1132
  }
1107
1133
  function isPnpProject(baseDirInput) {
1134
+ return pnpProjectRoot(baseDirInput) !== void 0;
1135
+ }
1136
+ function pnpProjectRoot(baseDirInput) {
1108
1137
  let dir = resolveBaseDir(baseDirInput);
1109
1138
  for (; ; ) {
1110
- if (isFile(path3.join(dir, ".pnp.cjs")) || isFile(path3.join(dir, ".pnp.js"))) return true;
1111
- if (existsSync2(path3.join(dir, ".git"))) return false;
1139
+ if (isFile(path3.join(dir, ".pnp.cjs")) || isFile(path3.join(dir, ".pnp.js"))) return dir;
1140
+ if (existsSync2(path3.join(dir, ".git"))) return void 0;
1112
1141
  const parent = path3.dirname(dir);
1113
- if (parent === dir) return false;
1142
+ if (parent === dir) return void 0;
1114
1143
  dir = parent;
1115
1144
  }
1116
1145
  }
1146
+ var TAILWIND4_MIN_AXIS_VERSION = "1.4.0";
1147
+ var COMPONENT_TAILWIND_CSS_MIN_VERSION = TAILWIND4_MIN_AXIS_VERSION;
1148
+ function componentCssResolution(baseDir, pkg, name) {
1149
+ if (pkg === void 0) return { kind: "undeclared" };
1150
+ const own = hasDependency(pkg, name);
1151
+ if (own !== void 0) return { kind: "app", range: own };
1152
+ const pnpRoot = pnpRootOnlyDependency(baseDir, pkg, name);
1153
+ if (pnpRoot !== void 0) return { kind: "pnp-root-only", range: pnpRoot.range };
1154
+ const declared = declaredDependency(baseDir, pkg, name);
1155
+ if (declared?.source !== "root") return { kind: "undeclared" };
1156
+ if (!rootDeclarationsAllowed(baseDir, pkg)) return { kind: "app-lockfile", range: declared.range };
1157
+ const installed = findInstalledPackage(baseDir, name);
1158
+ if (installed === void 0) return { kind: "root-not-installed", range: declared.range };
1159
+ if (isFile(path3.join(installed.dir, "tailwind.css"))) {
1160
+ return installed.version !== void 0 ? { kind: "root-ok", range: declared.range, installedVersion: installed.version } : { kind: "root-ok", range: declared.range };
1161
+ }
1162
+ const installedVersion = installed.version ?? "?";
1163
+ const current = installedVersion !== "?" && (compareExactVersions(installedVersion, COMPONENT_TAILWIND_CSS_MIN_VERSION) ?? -1) >= 0;
1164
+ return current ? { kind: "root-missing-file", range: declared.range, installedVersion } : { kind: "root-old", range: declared.range, installedVersion };
1165
+ }
1166
+ function componentCssResolvable(resolution) {
1167
+ return resolution.kind === "app" || resolution.kind === "root-ok";
1168
+ }
1169
+ function tokensCssResolution(baseDir, pkg, name = "@axis-ds/tokens") {
1170
+ const own = pkg !== void 0 ? hasDependency(pkg, name) : void 0;
1171
+ if (own !== void 0) return { kind: "app", range: own };
1172
+ const pnpRoot = pnpRootOnlyDependency(baseDir, pkg, name);
1173
+ if (pnpRoot !== void 0) return { kind: "pnp-root-only", range: pnpRoot.range };
1174
+ if (!isPnpProject(baseDir) && findInstalledPackage(baseDir, name) !== void 0) return { kind: "installed" };
1175
+ const declared = rootDeclarationsAllowed(baseDir, pkg) ? declaredDependency(baseDir, pkg, name) : void 0;
1176
+ return declared?.source === "root" ? { kind: "not-installed", source: "root", range: declared.range } : { kind: "not-installed", source: "none" };
1177
+ }
1178
+ function outsideCssPackageResolution(baseDir, cssDir, name, file) {
1179
+ if (isPnpProject(baseDir)) return "unknown";
1180
+ const usable = (p) => p !== void 0 && (file === void 0 || isFile(path3.join(p.dir, file)));
1181
+ if (!usable(findInstalledPackage(baseDir, name))) return "unknown";
1182
+ return usable(findInstalledPackage(cssDir, name)) ? "resolved" : "unresolved";
1183
+ }
1184
+ function findPnpUnpluggedPackages(baseDirInput, name, range) {
1185
+ const root = pnpProjectRoot(baseDirInput);
1186
+ if (root === void 0) return [];
1187
+ const unplugged = path3.join(root, ".yarn", "unplugged");
1188
+ let entries;
1189
+ try {
1190
+ entries = readdirSync(unplugged).sort();
1191
+ } catch {
1192
+ return [];
1193
+ }
1194
+ const found = [];
1195
+ for (const entry of entries) {
1196
+ const pkgDir = path3.join(unplugged, entry, "node_modules", ...name.split("/"));
1197
+ let version;
1198
+ try {
1199
+ const parsed = JSON.parse(readFileSync3(path3.join(pkgDir, "package.json"), "utf8"));
1200
+ version = isPlainObject(parsed) && parsed.name === name ? exactVersionOf(parsed.version) : void 0;
1201
+ } catch {
1202
+ version = void 0;
1203
+ }
1204
+ if (version !== void 0 && versionSatisfiesRange(version, range) === true) found.push(pkgDir);
1205
+ }
1206
+ return found;
1207
+ }
1208
+ function parsePartialVersion(token) {
1209
+ const m = /^v?(\d+|[xX*])(?:\.(\d+|[xX*]))?(?:\.(\d+|[xX*]))?(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/.exec(token.trim());
1210
+ if (!m) return void 0;
1211
+ const num = (s) => s === void 0 || /^[xX*]$/.test(s) ? void 0 : Number(s);
1212
+ const major = num(m[1]);
1213
+ const minor = major === void 0 ? void 0 : num(m[2]);
1214
+ const patch = minor === void 0 ? void 0 : num(m[3]);
1215
+ return { major, minor, patch, pre: patch === void 0 ? void 0 : m[4] };
1216
+ }
1217
+ function coreOf(v) {
1218
+ return v.replace(/^v/, "").replace(/[-+].*$/, "");
1219
+ }
1220
+ function intervalsOfToken(token) {
1221
+ const t = token.trim();
1222
+ if (t === "" || t === "*" || /^[xX]$/.test(t)) return [{ preCores: [] }];
1223
+ const op = /^(\^|~>?|>=|<=|>|<|=)?\s*(.+)$/.exec(t);
1224
+ if (!op) return void 0;
1225
+ const p = parsePartialVersion(op[2]);
1226
+ if (!p) return void 0;
1227
+ const full = (maj, min, pat, pre) => `${maj}.${min}.${pat}${pre ? `-${pre}` : ""}`;
1228
+ const preCores = p.pre !== void 0 ? [full(p.major ?? 0, p.minor ?? 0, p.patch ?? 0)] : [];
1229
+ const lower = full(p.major ?? 0, p.minor ?? 0, p.patch ?? 0, p.pre);
1230
+ const kind = op[1] ?? "";
1231
+ if (p.major === void 0) return kind === "" || kind === "=" || kind === ">=" ? [{ preCores }] : void 0;
1232
+ const next = p.minor === void 0 ? full(p.major + 1, 0, 0) : p.patch === void 0 ? full(p.major, p.minor + 1, 0) : void 0;
1233
+ switch (kind) {
1234
+ case "":
1235
+ case "=":
1236
+ return [next === void 0 ? { min: { v: lower, inclusive: true }, max: { v: lower, inclusive: true }, preCores } : { min: { v: lower, inclusive: true }, max: { v: next, inclusive: false, coreOnly: true }, preCores }];
1237
+ case ">=":
1238
+ return [{ min: { v: lower, inclusive: true }, preCores }];
1239
+ case ">":
1240
+ return [next === void 0 ? { min: { v: lower, inclusive: false }, preCores } : { min: { v: next, inclusive: true }, preCores }];
1241
+ case "<":
1242
+ return [{ max: { v: lower, inclusive: false, coreOnly: p.pre === void 0 }, preCores }];
1243
+ case "<=":
1244
+ return [next === void 0 ? { max: { v: lower, inclusive: true }, preCores } : { max: { v: next, inclusive: false, coreOnly: true }, preCores }];
1245
+ case "~":
1246
+ case "~>": {
1247
+ const upper = p.minor === void 0 ? full(p.major + 1, 0, 0) : full(p.major, p.minor + 1, 0);
1248
+ return [{ min: { v: lower, inclusive: true }, max: { v: upper, inclusive: false, coreOnly: true }, preCores }];
1249
+ }
1250
+ case "^": {
1251
+ const upper = p.major > 0 || p.minor === void 0 ? full(p.major + 1, 0, 0) : p.minor > 0 || p.patch === void 0 ? full(0, p.minor + 1, 0) : full(0, 0, p.patch + 1);
1252
+ return [{ min: { v: lower, inclusive: true }, max: { v: upper, inclusive: false, coreOnly: true }, preCores }];
1253
+ }
1254
+ }
1255
+ return void 0;
1256
+ }
1257
+ function satisfiesInterval(version, iv) {
1258
+ if (iv.min !== void 0) {
1259
+ const c = compareExactVersions(version, iv.min.v);
1260
+ if (c === void 0) return void 0;
1261
+ if (c < 0 || c === 0 && !iv.min.inclusive) return false;
1262
+ }
1263
+ if (iv.max !== void 0) {
1264
+ const c = iv.max.coreOnly ? compareExactVersions(coreOf(version), coreOf(iv.max.v)) : compareExactVersions(version, iv.max.v);
1265
+ if (c === void 0) return void 0;
1266
+ if (c > 0 || c === 0 && !iv.max.inclusive) return false;
1267
+ }
1268
+ return true;
1269
+ }
1270
+ function versionSatisfiesRange(version, range) {
1271
+ if (exactVersionOf(version) === void 0) return void 0;
1272
+ const alternatives = range.trim().split("||");
1273
+ let unknown = false;
1274
+ for (const alt of alternatives) {
1275
+ const a = alt.trim();
1276
+ let intervals;
1277
+ const hyphen = /^(\S+)\s+-\s+(\S+)$/.exec(a);
1278
+ if (hyphen) {
1279
+ const lo = intervalsOfToken(`>=${hyphen[1]}`);
1280
+ const hi = intervalsOfToken(`<=${hyphen[2]}`);
1281
+ intervals = lo && hi ? [...lo, ...hi] : void 0;
1282
+ } else {
1283
+ const tokens = a === "" ? [""] : a.replace(/(>=|<=|>|<|=|\^|~>?)\s+/g, "$1").split(/\s+/);
1284
+ const parts = tokens.map(intervalsOfToken);
1285
+ intervals = parts.every((x) => x !== void 0) ? parts.flat() : void 0;
1286
+ }
1287
+ if (intervals === void 0) {
1288
+ unknown = true;
1289
+ continue;
1290
+ }
1291
+ const pre = /-/.test(version.replace(/\+.*$/, ""));
1292
+ if (pre && !intervals.some((iv) => iv.preCores.includes(coreOf(version)))) continue;
1293
+ const results = intervals.map((iv) => satisfiesInterval(version, iv));
1294
+ if (results.some((x) => x === void 0)) {
1295
+ unknown = true;
1296
+ continue;
1297
+ }
1298
+ if (results.every((x) => x === true)) return true;
1299
+ }
1300
+ return unknown ? void 0 : false;
1301
+ }
1117
1302
  function compareExactVersions(a, b) {
1118
1303
  const parse = (v) => {
1119
1304
  const m = /^v?(\d+)\.(\d+)\.(\d+)(-[0-9A-Za-z.-]+)?/.exec(v.trim());
@@ -1127,7 +1312,7 @@ function compareExactVersions(a, b) {
1127
1312
  }
1128
1313
 
1129
1314
  // ../axis-registry-core/src/template/tailwind-core.ts
1130
- import { existsSync as existsSync3, lstatSync, readdirSync, readFileSync as readFileSync4, realpathSync as realpathSync2 } from "fs";
1315
+ import { existsSync as existsSync3, lstatSync, readdirSync as readdirSync2, readFileSync as readFileSync4, realpathSync as realpathSync2, statSync as statSync2 } from "fs";
1131
1316
  import { basename, dirname as dirname2, extname, isAbsolute, join as join2, relative, resolve, sep } from "path";
1132
1317
  function declaredRange(baseDir, pkg, name) {
1133
1318
  return declaredDependency(baseDir, pkg, name)?.range;
@@ -1255,6 +1440,157 @@ var TOKENS_CSS_IMPORT = /@import\s+(?:url\(\s*)?["'](@axis-ds\/tokens\/css(?:\/s
1255
1440
  function findTokensCssImport(css) {
1256
1441
  return TOKENS_CSS_IMPORT.exec(stripCssComments(css))?.[1];
1257
1442
  }
1443
+ var CSS_IMPORT_DEPTH_LIMIT = 32;
1444
+ var CSS_IMPORT_CYCLE_DEPTH_LIMIT = 100;
1445
+ var RELATIVE_CSS_IMPORT = /@import\s*(?:"(\.{1,2}\/[^"\n]*)"|'(\.{1,2}\/[^'\n]*)')(?=([^;{}]*))/g;
1446
+ function isConditionalCssImport(tail) {
1447
+ return tail !== void 0 && tail.trim() !== "";
1448
+ }
1449
+ function resolveRelativeCssImport(fromDir, spec) {
1450
+ if (spec.endsWith("/")) return void 0;
1451
+ const target = resolve(fromDir, spec);
1452
+ if (regularFile(target)) return target;
1453
+ if (regularFile(`${target}.css`)) return `${target}.css`;
1454
+ return void 0;
1455
+ }
1456
+ var CSS_IMPORT_SPEC = /@import\s+(?:url\(\s*)?(["'])([^"'\n]+)\1/g;
1457
+ function isPackageCssSpec(spec) {
1458
+ return !spec.startsWith("./") && !spec.startsWith("../") && !spec.startsWith("/") && !/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(spec);
1459
+ }
1460
+ function cssImportCycleIssue(files) {
1461
+ if (files.length === 1) return `${files[0]} \uC774 \uC790\uAE30 \uC790\uC2E0\uC744 @import \uD574 \uBE4C\uB4DC\uAC00 \uC21C\uD658\uC73C\uB85C \uC2E4\uD328\uD569\uB2C8\uB2E4 \u2192 \uC21C\uD658\uD558\uB294 @import \uB97C \uC5C6\uC560\uC138\uC694`;
1462
+ return `${files.join(" \xB7 ")} \uC774 \uC11C\uB85C @import \uD574 \uBE4C\uB4DC\uAC00 \uC21C\uD658\uC73C\uB85C \uC2E4\uD328\uD569\uB2C8\uB2E4 \u2192 \uC21C\uD658\uD558\uB294 @import \uB97C \uC5C6\uC560\uC138\uC694`;
1463
+ }
1464
+ function findImportCycle(start, edges) {
1465
+ const state = /* @__PURE__ */ new Map();
1466
+ const trail = [start];
1467
+ const stack = [{ node: start, next: 0 }];
1468
+ state.set(start, "open");
1469
+ while (stack.length > 0) {
1470
+ const top = stack[stack.length - 1];
1471
+ const out = edges.get(top.node) ?? [];
1472
+ if (top.next >= out.length) {
1473
+ state.set(top.node, "done");
1474
+ stack.pop();
1475
+ trail.pop();
1476
+ continue;
1477
+ }
1478
+ const to = out[top.next++];
1479
+ const s = state.get(to);
1480
+ if (s === "open") return trail.slice(trail.indexOf(to));
1481
+ if (s === "done") continue;
1482
+ state.set(to, "open");
1483
+ trail.push(to);
1484
+ stack.push({ node: to, next: 0 });
1485
+ }
1486
+ return void 0;
1487
+ }
1488
+ function regularFile(file) {
1489
+ try {
1490
+ return statSync2(file).isFile();
1491
+ } catch {
1492
+ return false;
1493
+ }
1494
+ }
1495
+ function expandGlobalCss(baseDirInput, entryPath, entryRel, entryCssDir) {
1496
+ const baseDir = resolveBaseDir(baseDirInput);
1497
+ const entry = readFileSync4(entryPath, "utf8");
1498
+ let entryReal = entryPath;
1499
+ try {
1500
+ entryReal = realpathSync2(entryPath);
1501
+ } catch {
1502
+ }
1503
+ const raws = /* @__PURE__ */ new Map([[entryReal, entry]]);
1504
+ const files = [];
1505
+ const packageLines = [];
1506
+ const evidenceWalk = walkRelativeCssImports(baseDir, entryReal, raws, CSS_IMPORT_DEPTH_LIMIT, false);
1507
+ const relOfReal = /* @__PURE__ */ new Map([[entryReal, entryRel]]);
1508
+ for (const node of evidenceWalk.order) {
1509
+ const isEntry = node.real === entryReal;
1510
+ const rel2 = isEntry ? entryRel : node.rel;
1511
+ const css = stripCssComments(raws.get(node.real) ?? "");
1512
+ const file = { rel: rel2, path: node.real, css, depth: node.depth };
1513
+ const cssDir = isEntry ? entryCssDir : dirname2(node.real);
1514
+ if (cssDir !== void 0) file.cssDir = cssDir;
1515
+ files.push(file);
1516
+ relOfReal.set(node.real, rel2);
1517
+ for (const m of css.matchAll(CSS_IMPORT_SPEC)) {
1518
+ if (!isPackageCssSpec(m[2])) continue;
1519
+ const line = { spec: m[2], file: rel2 };
1520
+ if (cssDir !== void 0) line.cssDir = cssDir;
1521
+ packageLines.push(line);
1522
+ }
1523
+ }
1524
+ const cycleWalk = walkRelativeCssImports(baseDir, entryReal, raws, CSS_IMPORT_CYCLE_DEPTH_LIMIT, true);
1525
+ const cycle = findImportCycle(entryReal, cycleWalk.edges);
1526
+ if (cycle !== void 0) {
1527
+ for (const node of cycleWalk.order) if (!relOfReal.has(node.real)) relOfReal.set(node.real, node.rel);
1528
+ const head = files[0];
1529
+ return {
1530
+ entry,
1531
+ evidence: entry,
1532
+ files: [head],
1533
+ packageLines: packageLines.filter((l) => l.file === head.rel),
1534
+ cycle: cycle.map((p) => relOfReal.get(p) ?? p)
1535
+ };
1536
+ }
1537
+ const evidence = files.length === 1 ? entry : files.map((f) => f.css).join("\n");
1538
+ return { entry, evidence, files, packageLines };
1539
+ }
1540
+ function walkRelativeCssImports(baseDir, entryReal, raws, limit, includeConditional) {
1541
+ const order = [];
1542
+ const edges = /* @__PURE__ */ new Map();
1543
+ const visited = /* @__PURE__ */ new Set([entryReal]);
1544
+ const queue = [{ real: entryReal, rel: "", depth: 0 }];
1545
+ while (queue.length > 0) {
1546
+ const cur = queue.shift();
1547
+ order.push(cur);
1548
+ const css = stripCssComments(raws.get(cur.real) ?? "");
1549
+ const out = [];
1550
+ edges.set(cur.real, out);
1551
+ for (const m of css.matchAll(RELATIVE_CSS_IMPORT)) {
1552
+ if (!includeConditional && isConditionalCssImport(m[3])) continue;
1553
+ const target = resolveRelativeCssImport(dirname2(cur.real), m[1] ?? m[2]);
1554
+ if (target === void 0) continue;
1555
+ let real;
1556
+ try {
1557
+ real = realpathSync2(target);
1558
+ } catch {
1559
+ continue;
1560
+ }
1561
+ if (visited.has(real)) {
1562
+ out.push(real);
1563
+ continue;
1564
+ }
1565
+ if (cur.depth >= limit) continue;
1566
+ const rel2 = relative(baseDir, real);
1567
+ if (rel2 === "" || rel2 === ".." || rel2.startsWith(`..${sep}`) || isAbsolute(rel2)) continue;
1568
+ if (!raws.has(real)) {
1569
+ try {
1570
+ raws.set(real, readFileSync4(real, "utf8"));
1571
+ } catch {
1572
+ continue;
1573
+ }
1574
+ }
1575
+ visited.add(real);
1576
+ out.push(real);
1577
+ queue.push({ real, rel: rel2.split(sep).join("/"), depth: cur.depth + 1 });
1578
+ }
1579
+ }
1580
+ return { order, edges };
1581
+ }
1582
+ function evidenceOrigin(expanded, test) {
1583
+ return expanded.files.find((f) => test(f.css));
1584
+ }
1585
+ function packageLineCssDir(expanded, spec) {
1586
+ const line = expanded.packageLines.find((l) => l.spec === spec);
1587
+ return line !== void 0 ? line.cssDir : expanded.files[0]?.cssDir;
1588
+ }
1589
+ function viaFiles(origins) {
1590
+ const out = [];
1591
+ for (const o of origins) if (o !== void 0 && o.depth > 0 && !out.includes(o.rel)) out.push(o.rel);
1592
+ return out;
1593
+ }
1258
1594
  var TOKENS_CSS_JS_IMPORT = /(?:\bimport\s+|\bfrom\s+|\brequire\s*\(\s*)(["'])(@axis-ds\/tokens\/css(?:\/shadcn|\/tailwind4)?)\1/;
1259
1595
  var AXIS_VARIABLE_DEFINITION = /(?<![\w-])--axis-[\w-]+\s*:/;
1260
1596
  function findLayoutTokensCssImport(baseDirInput) {
@@ -1273,45 +1609,92 @@ function findLayoutTokensCssImport(baseDirInput) {
1273
1609
  }
1274
1610
  return void 0;
1275
1611
  }
1612
+ var TOKENS_PACKAGE_NAME = "@axis-ds/tokens";
1613
+ function outsideCssDir(selection) {
1614
+ if (selection.path === void 0 || selection.rel === void 0) return void 0;
1615
+ const outside = selection.rel === ".." || selection.rel.startsWith("../") || isAbsolute(selection.rel);
1616
+ return outside ? dirname2(selection.path) : void 0;
1617
+ }
1618
+ function outsideCssUnresolvedIssue(spec, name) {
1619
+ return `${spec} import \uAC00 \uC788\uC9C0\uB9CC \uC774 \uD30C\uC77C \uC704\uCE58\uC5D0\uC11C ${name} \uB97C \uCC3E\uC9C0 \uBABB\uD574 \uD574\uC11D\uB418\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4(\uC124\uCE58\uBCF8\uC774 \uC571 \uCABD node_modules \uC5D0\uB9CC \uC788\uC74C) \u2192 \uC774 \uD30C\uC77C\uC758 \uC0C1\uC704 node_modules(\uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uB8E8\uD2B8 \uB4F1)\uC5D0 \uC124\uCE58\uD558\uAC70\uB098 globalCss \uB97C \uC571 \uC548 \uD30C\uC77C\uB85C \uBC14\uAFB8\uC138\uC694`;
1620
+ }
1621
+ function tokensInstallPhrase(baseDir) {
1622
+ const g = dependencyInstallGuide(baseDir, TOKENS_PACKAGE_NAME, `^${TAILWIND4_MIN_AXIS_VERSION}`);
1623
+ if (g.kind === "install-at-root") return `\uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uB8E8\uD2B8\uC5D0\uC11C ${g.installCommand}`;
1624
+ return g.kind === "install" ? g.installCommand : g.addCommand;
1625
+ }
1626
+ function tokensCssUnresolvedIssue(baseDir, pkg, spec, cssDir) {
1627
+ const r = tokensCssResolution(baseDir, pkg, TOKENS_PACKAGE_NAME);
1628
+ const head = `${spec} import \uAC00 \uC788\uC9C0\uB9CC`;
1629
+ if (r.kind === "pnp-root-only") return `${head} ${TOKENS_PACKAGE_NAME} \uAC00 ${PNP_ROOT_ONLY_NOTE} \u2192 \uC571 package.json \uC5D0 \uC120\uC5B8\uD558\uC138\uC694`;
1630
+ if (r.kind === "not-installed") {
1631
+ return `${head} ${TOKENS_PACKAGE_NAME} \uAC00 \uC124\uCE58\uB418\uC9C0 \uC54A\uC544 \uD574\uC11D\uB418\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4 \u2192 \uC124\uCE58(${tokensInstallPhrase(baseDir)})`;
1632
+ }
1633
+ if (cssDir !== void 0 && outsideCssPackageResolution(baseDir, cssDir, TOKENS_PACKAGE_NAME) === "unresolved") {
1634
+ return outsideCssUnresolvedIssue(spec, TOKENS_PACKAGE_NAME);
1635
+ }
1636
+ return void 0;
1637
+ }
1276
1638
  function checkGlobalsCss(baseDirInput) {
1277
1639
  const baseDir = resolveBaseDir(baseDirInput);
1278
- for (const candidate of TAILWIND_CSS_CANDIDATES) {
1279
- const file = join2(baseDir, candidate);
1280
- if (!existsSync3(file)) continue;
1281
- const content = readFileSync4(file, "utf8");
1282
- const css = stripCssComments(content);
1283
- const imported = findTokensCssImport(content);
1284
- let pass;
1285
- if (imported !== void 0) pass = `${candidate}\uC5D0 AXIS CSS \uBCC0\uC218\uAC00 \uC788\uC2B5\uB2C8\uB2E4 (${imported} import)`;
1286
- else if (AXIS_VARIABLE_DEFINITION.test(css)) pass = `${candidate}\uC5D0 AXIS CSS \uBCC0\uC218(--axis-*)\uAC00 \uC815\uC758\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4`;
1287
- else {
1288
- const layout = findLayoutTokensCssImport(baseDir);
1289
- if (layout) pass = `${candidate}\uC5D0 AXIS CSS \uBCC0\uC218\uAC00 \uC788\uC2B5\uB2C8\uB2E4 (${layout.file}\uC758 ${layout.spec} import)`;
1290
- }
1291
- if (pass !== void 0) {
1292
- const tailwind = detectTailwind(baseDir, readPackageJson(baseDir));
1293
- const tailwind4 = tailwind.major !== void 0 && tailwind.major >= 4;
1294
- if (!tailwind4 && findCreateNextAppDefaults(content).some((d) => d.includes("font-family: Arial"))) {
1295
- return {
1296
- name: "globals.css",
1297
- severity: "warn",
1298
- message: `${pass}. \uB2E4\uB9CC create-next-app \uAE30\uBCF8 body font-family: Arial \uC774 \uB0A8\uC544 \uC788\uC2B5\uB2C8\uB2E4 \u2192 \uC9C0\uC6B0\uC138\uC694(AXIS \uAE00\uAF34 \uB300\uC2E0 Arial \uC774 \uC801\uC6A9\uB428)`
1299
- };
1300
- }
1301
- return { name: "globals.css", severity: "pass", message: pass };
1302
- }
1303
- if (css.includes("--background") && css.includes("--primary")) {
1640
+ const selection = selectCheckGlobalCss(baseDir);
1641
+ const note = globalCssSelectionNote(selection);
1642
+ if (selection.path !== void 0 && selection.rel !== void 0) {
1643
+ const candidate = selection.rel;
1644
+ const expanded = expandGlobalCss(baseDir, selection.path, candidate, outsideCssDir(selection));
1645
+ const judged = judgeGlobalsCss(baseDir, selection, candidate, expanded);
1646
+ if (expanded.cycle !== void 0) {
1647
+ return { name: "globals.css", severity: "warn", message: `${judged.message} / ${cssImportCycleIssue(expanded.cycle)}${note}` };
1648
+ }
1649
+ return { name: "globals.css", severity: judged.severity, message: `${judged.message}${note}` };
1650
+ }
1651
+ return { name: "globals.css", severity: "fail", message: `globals.css \uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4${note}` };
1652
+ }
1653
+ function judgeGlobalsCss(baseDir, selection, candidate, expanded) {
1654
+ const content = expanded.entry;
1655
+ const css = stripCssComments(content);
1656
+ const imported = findTokensCssImport(expanded.evidence);
1657
+ const pkg = readPackageJson(baseDir);
1658
+ let pass;
1659
+ let unresolved;
1660
+ let via = "";
1661
+ if (imported !== void 0) {
1662
+ const origin = evidenceOrigin(expanded, (f) => findTokensCssImport(f) === imported);
1663
+ via = cssImportViaNote(viaFiles([origin]));
1664
+ const issue = tokensCssUnresolvedIssue(baseDir, pkg, imported, origin !== void 0 ? origin.cssDir : outsideCssDir(selection));
1665
+ if (issue !== void 0) unresolved = `${candidate}\uC5D0 ${issue}`;
1666
+ else pass = `${candidate}\uC5D0 AXIS CSS \uBCC0\uC218\uAC00 \uC788\uC2B5\uB2C8\uB2E4 (${imported} import)`;
1667
+ } else if (AXIS_VARIABLE_DEFINITION.test(stripCssComments(expanded.evidence))) {
1668
+ via = cssImportViaNote(viaFiles([evidenceOrigin(expanded, (f) => AXIS_VARIABLE_DEFINITION.test(f))]));
1669
+ pass = `${candidate}\uC5D0 AXIS CSS \uBCC0\uC218(--axis-*)\uAC00 \uC815\uC758\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4`;
1670
+ } else {
1671
+ const layout = findLayoutTokensCssImport(baseDir);
1672
+ if (layout) {
1673
+ const issue = tokensCssUnresolvedIssue(baseDir, pkg, layout.spec);
1674
+ if (issue !== void 0) unresolved = `${candidate}\uC5D0 AXIS CSS \uBCC0\uC218\uAC00 \uC5C6\uACE0 ${layout.file}\uC758 ${issue}`;
1675
+ else pass = `${candidate}\uC5D0 AXIS CSS \uBCC0\uC218\uAC00 \uC788\uC2B5\uB2C8\uB2E4 (${layout.file}\uC758 ${layout.spec} import)`;
1676
+ }
1677
+ }
1678
+ const head = pass ?? unresolved;
1679
+ if (head !== void 0) {
1680
+ const tailwind = detectTailwind(baseDir, pkg);
1681
+ const tailwind4 = tailwind.major !== void 0 && tailwind.major >= 4;
1682
+ if (!tailwind4 && findCreateNextAppDefaults(content).some((d) => d.includes("font-family: Arial"))) {
1304
1683
  return {
1305
- name: "globals.css",
1306
1684
  severity: "warn",
1307
- message: `${candidate}\uC5D0 \uC790\uCCB4 CSS \uBCC0\uC218(--background \xB7 --primary)\uB9CC \uC788\uACE0 AXIS \uD1A0\uD070\uC774 \uC5C6\uC2B5\uB2C8\uB2E4 \u2192 @axis-ds/tokens CSS \uB97C import \uD558\uC138\uC694`
1685
+ message: `${head}. \uB2E4\uB9CC create-next-app \uAE30\uBCF8 body font-family: Arial \uC774 \uB0A8\uC544 \uC788\uC2B5\uB2C8\uB2E4 \u2192 \uC9C0\uC6B0\uC138\uC694(AXIS \uAE00\uAF34 \uB300\uC2E0 Arial \uC774 \uC801\uC6A9\uB428)${via}`
1308
1686
  };
1309
1687
  }
1310
- return { name: "globals.css", severity: "warn", message: `${candidate}\uC5D0 AXIS CSS \uBCC0\uC218\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4` };
1688
+ return { severity: pass !== void 0 ? "pass" : "warn", message: `${head}${via}` };
1689
+ }
1690
+ if (css.includes("--background") && css.includes("--primary")) {
1691
+ return {
1692
+ severity: "warn",
1693
+ message: `${candidate}\uC5D0 \uC790\uCCB4 CSS \uBCC0\uC218(--background \xB7 --primary)\uB9CC \uC788\uACE0 AXIS \uD1A0\uD070\uC774 \uC5C6\uC2B5\uB2C8\uB2E4 \u2192 @axis-ds/tokens CSS \uB97C import \uD558\uC138\uC694`
1694
+ };
1311
1695
  }
1312
- return { name: "globals.css", severity: "fail", message: "globals.css \uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4" };
1696
+ return { severity: "warn", message: `${candidate}\uC5D0 AXIS CSS \uBCC0\uC218\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4` };
1313
1697
  }
1314
- var TAILWIND4_MIN_AXIS_VERSION = "1.4.0";
1315
1698
  var TAILWIND4_AXIS_PACKAGES = ["@axis-ds/tokens", "@axis-ds/ui-react", "@axis-ds/agentic-ui"];
1316
1699
  function lowerOf(token) {
1317
1700
  const v = versionParts(token);
@@ -1544,66 +1927,134 @@ function readPackageJson(baseDir) {
1544
1927
  return void 0;
1545
1928
  }
1546
1929
  }
1547
- function tailwind4Issues(css, pkg, versions, baseDir) {
1930
+ function tailwind4Issues(input, pkg, versions, baseDir) {
1931
+ const { entry, evidence } = input;
1932
+ const cssDirOf = input.cssDirOf ?? (() => void 0);
1548
1933
  const issues = [];
1549
- const hasEntry = hasTokensTailwind4Import(css);
1934
+ const tailwindDir = cssDirOf("tailwindcss");
1935
+ if (tailwindDir !== void 0 && outsideCssPackageResolution(baseDir, tailwindDir, "tailwindcss") === "unresolved") {
1936
+ issues.push(outsideCssUnresolvedIssue("tailwindcss", "tailwindcss"));
1937
+ }
1938
+ const hasEntry = hasTokensTailwind4Import(evidence);
1550
1939
  if (!hasEntry) issues.push(`AXIS \uD1A0\uD070 \uC9C4\uC785\uC810\uC774 \uC5C6\uC2B5\uB2C8\uB2E4 \u2192 ${TOKENS_TAILWIND4_IMPORT_LINE}`);
1551
- const missing = TAILWIND4_COMPONENT_PACKAGES.filter(
1552
- (name) => declaredRange(baseDir, pkg, name) !== void 0 && !hasComponentTailwindImport(css, name) && !hasComponentSource(css, name)
1553
- );
1940
+ const resolutions = new Map(TAILWIND4_COMPONENT_PACKAGES.map((name) => [name, componentCssResolution(baseDir, pkg, name)]));
1941
+ const missing = [];
1942
+ const unresolvedMissing = [];
1943
+ for (const name of TAILWIND4_COMPONENT_PACKAGES) {
1944
+ const r = resolutions.get(name);
1945
+ if (r.kind === "undeclared" || r.kind === "app-lockfile") continue;
1946
+ if (hasComponentTailwindImport(evidence, name) || hasComponentSource(evidence, name)) continue;
1947
+ if (componentCssResolvable(r)) missing.push(name);
1948
+ else unresolvedMissing.push(componentCssMissingIssue(baseDir, name, r));
1949
+ }
1554
1950
  if (missing.length > 0) {
1555
1951
  issues.push(`\uCEF4\uD3EC\uB10C\uD2B8 \uC2A4\uCE94 \uACBD\uB85C(tailwind.css)\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4 \u2192 ${missing.map(componentTailwindImportLine).join(" ")}`);
1556
1952
  }
1953
+ issues.push(...unresolvedMissing);
1557
1954
  if (hasEntry) {
1558
- const defaults = findCreateNextAppDefaults(css);
1955
+ const defaults = findCreateNextAppDefaults(entry);
1559
1956
  if (defaults.length > 0) issues.push(`create-next-app \uAE30\uBCF8 \uC815\uC758\uAC00 \uB0A8\uC544 \uC788\uC2B5\uB2C8\uB2E4(${defaults.join(" \xB7 ")}) \u2192 \uC9C0\uC6B0\uC138\uC694`);
1560
1957
  if (versions.some((v) => v.name === TAILWIND4_AXIS_PACKAGES[0])) {
1561
1958
  issues.push(`AXIS \uD1A0\uD070 \uC9C4\uC785\uC810\uC774 \uC788\uC9C0\uB9CC ${TAILWIND4_AXIS_PACKAGES[0]} \uBC84\uC804 \uD655\uC778\uC774 \uD544\uC694\uD569\uB2C8\uB2E4`);
1562
1959
  }
1563
1960
  }
1564
1961
  for (const name of TAILWIND4_COMPONENT_PACKAGES) {
1565
- if (hasComponentTailwindImport(css, name) && versions.some((v) => v.name === name)) {
1566
- issues.push(`${name}/tailwind.css import \uAC00 \uC788\uC9C0\uB9CC ${name} \uBC84\uC804 \uD655\uC778\uC774 \uD544\uC694\uD569\uB2C8\uB2E4`);
1567
- }
1962
+ if (!hasComponentTailwindImport(evidence, name)) continue;
1963
+ const unresolved = componentCssPresentIssue(baseDir, name, resolutions.get(name));
1964
+ const componentDir = cssDirOf(`${name}/tailwind.css`);
1965
+ if (unresolved !== void 0) issues.push(unresolved);
1966
+ else if (componentDir !== void 0 && outsideCssPackageResolution(baseDir, componentDir, name, "tailwind.css") === "unresolved") {
1967
+ issues.push(outsideCssUnresolvedIssue(`${name}/tailwind.css`, name));
1968
+ } else if (versions.some((v) => v.name === name)) issues.push(`${name}/tailwind.css import \uAC00 \uC788\uC9C0\uB9CC ${name} \uBC84\uC804 \uD655\uC778\uC774 \uD544\uC694\uD569\uB2C8\uB2E4`);
1568
1969
  }
1569
1970
  return issues;
1570
1971
  }
1972
+ function componentInstallPhrase(baseDir, name, range) {
1973
+ const g = dependencyInstallGuide(baseDir, name, range);
1974
+ return g.kind === "install-at-root" ? `\uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uB8E8\uD2B8\uC5D0\uC11C ${g.installCommand}` : g.installCommand;
1975
+ }
1976
+ function componentCssMissingIssue(baseDir, name, r) {
1977
+ const line = componentTailwindImportLine(name);
1978
+ switch (r.kind) {
1979
+ case "pnp-root-only":
1980
+ return `${name} \uAC00 ${PNP_ROOT_ONLY_NOTE} \u2192 \uC571 package.json \uC5D0 \uC120\uC5B8\uD55C \uB4A4 ${line}`;
1981
+ case "root-not-installed":
1982
+ return `${name} \uAC00 \uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uB8E8\uD2B8\uC5D0 \uC120\uC5B8\uB410\uC9C0\uB9CC \uC124\uCE58\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4 \u2192 \uC124\uCE58(${componentInstallPhrase(baseDir, name, r.range)}) \uB4A4 ${line}`;
1983
+ case "root-old":
1984
+ return `\uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uB8E8\uD2B8\uC5D0 \uC120\uC5B8\uB41C ${name} \uC758 \uC124\uCE58\uBCF8(${r.installedVersion === "?" ? "\uBC84\uC804 \uBAA8\uB984" : r.installedVersion})\uC5D0 tailwind.css \uAC00 \uC5C6\uC2B5\uB2C8\uB2E4(${TAILWIND4_MIN_AXIS_VERSION} \uBD80\uD130 \uC81C\uACF5) \u2192 ${TAILWIND4_MIN_AXIS_VERSION} \uC774\uC0C1\uC73C\uB85C \uC62C\uB9B0 \uB4A4 ${line}`;
1985
+ case "root-missing-file":
1986
+ return `\uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uB8E8\uD2B8\uC5D0 \uC120\uC5B8\uB41C ${name} \uC758 \uC124\uCE58\uBCF8(${r.installedVersion})\uC5D0 tailwind.css \uAC00 \uC5C6\uC2B5\uB2C8\uB2E4(\uC124\uCE58\uAC00 \uC190\uC0C1\uB410\uC744 \uC218 \uC788\uC74C) \u2192 \uB2E4\uC2DC \uC124\uCE58(${componentInstallPhrase(baseDir, name, r.range)}) \uB4A4 ${line}`;
1987
+ default:
1988
+ return line;
1989
+ }
1990
+ }
1991
+ function componentCssPresentIssue(baseDir, name, r) {
1992
+ const head = `${name}/tailwind.css import \uAC00 \uC788\uC9C0\uB9CC`;
1993
+ switch (r.kind) {
1994
+ case "pnp-root-only":
1995
+ return `${head} ${name} \uAC00 ${PNP_ROOT_ONLY_NOTE} \u2192 \uC571 package.json \uC5D0 \uC120\uC5B8\uD558\uC138\uC694`;
1996
+ case "root-not-installed":
1997
+ return `${head} ${name} \uAC00 \uC124\uCE58\uB418\uC9C0 \uC54A\uC544 \uD574\uC11D\uB418\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4 \u2192 \uC124\uCE58(${componentInstallPhrase(baseDir, name, r.range)})`;
1998
+ case "root-missing-file":
1999
+ return `${head} ${name} \uC124\uCE58\uBCF8(${r.installedVersion})\uC5D0 tailwind.css \uAC00 \uC5C6\uC5B4 \uD574\uC11D\uB418\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4 \u2192 \uB2E4\uC2DC \uC124\uCE58(${componentInstallPhrase(baseDir, name, r.range)})`;
2000
+ case "root-old":
2001
+ return r.installedVersion === "?" ? `${head} ${name} \uC124\uCE58\uBCF8(\uBC84\uC804 \uBAA8\uB984)\uC5D0 tailwind.css \uAC00 \uC5C6\uC5B4 \uD574\uC11D\uB418\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4 \u2192 ${TAILWIND4_MIN_AXIS_VERSION} \uC774\uC0C1\uC73C\uB85C \uC62C\uB9AC\uC138\uC694` : void 0;
2002
+ default:
2003
+ return void 0;
2004
+ }
2005
+ }
1571
2006
  function checkTailwindSetup(baseDirInput) {
1572
2007
  const baseDir = resolveBaseDir(baseDirInput);
1573
2008
  const pkg = readPackageJson(baseDir);
1574
2009
  const tailwind = detectTailwind(baseDir, pkg);
1575
2010
  if (tailwind.major !== void 0 && tailwind.major >= 4) {
1576
2011
  const label = `Tailwind ${tailwind.major}`;
1577
- for (const candidate of TAILWIND_CSS_CANDIDATES) {
1578
- const file = join2(baseDir, candidate);
1579
- if (!existsSync3(file)) continue;
1580
- const css = readFileSync4(file, "utf8");
1581
- if (!hasTailwindImport(css)) {
2012
+ const selection = selectCheckGlobalCss(baseDir);
2013
+ const note = globalCssSelectionNote(selection);
2014
+ if (selection.path !== void 0 && selection.rel !== void 0) {
2015
+ const candidate = selection.rel;
2016
+ const expanded = expandGlobalCss(baseDir, selection.path, candidate, outsideCssDir(selection));
2017
+ if (!hasTailwindImport(expanded.evidence)) {
1582
2018
  return {
1583
2019
  name: "tailwind.config",
1584
2020
  severity: "warn",
1585
- message: `${label}: ${candidate}\uC5D0 @import "tailwindcss" \uAC00 \uC5C6\uC2B5\uB2C8\uB2E4`
2021
+ message: `${label}: ${candidate}\uC5D0 @import "tailwindcss" \uAC00 \uC5C6\uC2B5\uB2C8\uB2E4${note}`
1586
2022
  };
1587
2023
  }
2024
+ const via = cssImportViaNote(
2025
+ viaFiles([
2026
+ evidenceOrigin(expanded, hasTailwindImport),
2027
+ evidenceOrigin(expanded, hasTokensTailwind4Import),
2028
+ ...TAILWIND4_COMPONENT_PACKAGES.flatMap((name) => [
2029
+ evidenceOrigin(expanded, (f) => hasComponentTailwindImport(f, name)),
2030
+ evidenceOrigin(expanded, (f) => hasComponentSource(f, name))
2031
+ ])
2032
+ ])
2033
+ );
1588
2034
  const versions = axisPackagesBelowTailwind4(pkg, baseDir);
1589
- const issues = tailwind4Issues(css, pkg, versions, baseDir);
2035
+ const issues = tailwind4Issues(
2036
+ { entry: expanded.entry, evidence: expanded.evidence, cssDirOf: (spec) => packageLineCssDir(expanded, spec) },
2037
+ pkg,
2038
+ versions,
2039
+ baseDir
2040
+ );
1590
2041
  if (issues.length > 0) {
1591
2042
  return {
1592
2043
  name: "tailwind.config",
1593
2044
  severity: "warn",
1594
- message: `${label}: ${candidate}\uC5D0 ${issues.join(" / ")}${tailwind4VersionNote(versions)}`
2045
+ message: `${label}: ${candidate}\uC5D0 ${issues.join(" / ")}${tailwind4VersionNote(versions)}${via}${note}`
1595
2046
  };
1596
2047
  }
1597
2048
  return {
1598
2049
  name: "tailwind.config",
1599
2050
  severity: "pass",
1600
- message: `${label}: ${candidate}\uC5D0 @import "tailwindcss" \uC640 AXIS \uD1A0\uD070 \uC9C4\uC785\uC810\uC774 \uC788\uC2B5\uB2C8\uB2E4`
2051
+ message: `${label}: ${candidate}\uC5D0 @import "tailwindcss" \uC640 AXIS \uD1A0\uD070 \uC9C4\uC785\uC810\uC774 \uC788\uC2B5\uB2C8\uB2E4${via}${note}`
1601
2052
  };
1602
2053
  }
1603
2054
  return {
1604
2055
  name: "tailwind.config",
1605
2056
  severity: "warn",
1606
- message: `${label}: @import "tailwindcss" \uB97C \uD655\uC778\uD560 CSS \uD30C\uC77C\uC744 \uCC3E\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4`
2057
+ message: `${label}: @import "tailwindcss" \uB97C \uD655\uC778\uD560 CSS \uD30C\uC77C\uC744 \uCC3E\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4${note}`
1607
2058
  };
1608
2059
  }
1609
2060
  for (const file of TAILWIND_CONFIG_FILES) {
@@ -1649,31 +2100,45 @@ function readAxisConfigLike(baseDir) {
1649
2100
  return void 0;
1650
2101
  }
1651
2102
  }
1652
- function contentGlobToRegExp(glob) {
2103
+ function selectCheckGlobalCss(baseDir) {
2104
+ return selectGlobalCss(baseDir, readAxisConfigLike(baseDir)?.globalCss, TAILWIND_CSS_CANDIDATES, { requireStylesheet: true });
2105
+ }
2106
+ function contentGlobToRegExp(glob, opts = {}) {
2107
+ const noDot = opts.noDot === true;
1653
2108
  const g = glob.trim().replace(/^\.\//, "");
2109
+ const lead = (i) => noDot && (i === 0 || g[i - 1] === "/") ? "(?!\\.)" : "";
1654
2110
  let re = "";
1655
2111
  for (let i = 0; i < g.length; i++) {
1656
2112
  const c = g[i];
1657
2113
  if (c === "*") {
1658
2114
  if (g[i + 1] === "*") {
1659
2115
  const slash = g[i + 2] === "/";
1660
- re += slash ? "(?:.*/)?" : ".*";
2116
+ if (noDot) re += slash ? `(?:${lead(i)}[^/]*/(?:(?!\\.)[^/]*/)*)?` : `${lead(i)}[^/]*(?:/(?!\\.)[^/]*)*`;
2117
+ else re += slash ? "(?:.*/)?" : ".*";
1661
2118
  i += slash ? 2 : 1;
1662
- } else re += "[^/]*";
1663
- } else if (c === "?") re += "[^/]";
2119
+ } else re += `${lead(i)}[^/]*`;
2120
+ } else if (c === "?") re += `${lead(i)}[^/]`;
1664
2121
  else if (c === "{") {
1665
2122
  const end = g.indexOf("}", i);
1666
2123
  if (end === -1) {
1667
2124
  re += "\\{";
1668
2125
  continue;
1669
2126
  }
1670
- re += `(?:${g.slice(i + 1, end).split(",").map((part) => part.replace(/[.+^$()|[\]\\]/g, "\\$&").replace(/\*/g, "[^/]*")).join("|")})`;
2127
+ const atStart = lead(i) !== "";
2128
+ re += `(?:${g.slice(i + 1, end).split(",").map((part) => {
2129
+ const body = part.replace(/[.+^$()|[\]\\]/g, "\\$&");
2130
+ if (!noDot) return body.replace(/\*/g, "[^/]*");
2131
+ return body.replace(
2132
+ /(\/)?\*/g,
2133
+ (_m, slash, off) => slash !== void 0 || off === 0 && atStart ? `${slash ?? ""}(?!\\.)[^/]*` : "[^/]*"
2134
+ );
2135
+ }).join("|")})`;
1671
2136
  i = end;
1672
2137
  } else if (c === "[") {
1673
2138
  const end = g.indexOf("]", i);
1674
2139
  if (end === -1) re += "\\[";
1675
2140
  else {
1676
- re += g.slice(i, end + 1);
2141
+ re += lead(i) + g.slice(i, end + 1);
1677
2142
  i = end;
1678
2143
  }
1679
2144
  } else re += c.replace(/[.+^$()|\\]/g, "\\$&");
@@ -1742,22 +2207,46 @@ function realpathPosix(p) {
1742
2207
  }
1743
2208
  return void 0;
1744
2209
  }
1745
- function contentGlobBranchCovers(glob, sample, baseDir) {
2210
+ function contentGlobBranchCovers(glob, sample, baseDir, noDot) {
1746
2211
  if (isAbsoluteGlob(glob)) {
1747
- const re = contentGlobToRegExp(glob.trim().replace(/\\/g, "/"));
2212
+ const re = contentGlobToRegExp(glob.trim().replace(/\\/g, "/"), { noDot });
1748
2213
  const absSample = resolve(baseDir, sample);
1749
2214
  if (re.test(absSample.split(sep).join("/"))) return true;
1750
2215
  const real = realpathPosix(absSample);
1751
2216
  return real !== void 0 && re.test(real);
1752
2217
  }
1753
- return leadingParentSegments(glob) === leadingParentSegments(sample) && contentGlobToRegExp(glob).test(sample);
2218
+ return leadingParentSegments(glob) === leadingParentSegments(sample) && contentGlobToRegExp(glob, { noDot }).test(sample);
1754
2219
  }
1755
- function contentGlobCovers(glob, sample, baseDirInput) {
2220
+ function contentGlobCovers(glob, sample, baseDirInput, opts = {}) {
1756
2221
  const baseDir = resolveBaseDir(baseDirInput);
1757
2222
  const branches = expandBraces(glob.trim()) ?? [glob];
1758
- return branches.some((b) => contentGlobBranchCovers(b, sample, baseDir));
2223
+ return branches.some((b) => contentGlobBranchCovers(b, sample, baseDir, opts.noDot === true));
2224
+ }
2225
+ 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\uB9BD\uB2C8\uB2E4. \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";
2226
+ function contentPnpNote(names, unplugged = []) {
2227
+ const list = [...new Set(typeof names === "string" ? [names] : names)];
2228
+ const dyn = list.map((n) => `path.join(path.dirname(require.resolve("${n}")), "..", "dist/**/*.{js,mjs}")`).join(", ");
2229
+ const needsSetup = list.filter((n) => !unplugged.includes(n));
2230
+ const meta = needsSetup.map((n) => `"${n}": { "unplugged": true }`).join(", ");
2231
+ const setup = needsSetup.length > 0 ? ` \uC815\uC801 \uACBD\uB85C\uB97C \uC4F0\uB824\uBA74 package.json \uC758 dependenciesMeta \uC5D0 ${meta} \uB97C \uB450\uACE0 yarn install \uB4A4 .yarn/unplugged \uACBD\uB85C\uB97C \uB123\uC73C\uC138\uC694` : "";
2232
+ return `Plug'n'Play \uC5D0\uB294 node_modules \uAC00 \uC5C6\uC2B5\uB2C8\uB2E4. content \uC5D0 ${dyn} \uCC98\uB7FC \uC2E4\uC81C \uC704\uCE58\uB97C \uB123\uC73C\uC138\uC694(\uC815\uC801\uC73C\uB85C \uD655\uC778\uD560 \uC218 \uC5C6\uC5B4 WARN \uC73C\uB85C \uB0A8\uC2B5\uB2C8\uB2E4).${setup}`;
2233
+ }
2234
+ function contentPnpNoteTargets(targets) {
2235
+ return targets.filter((t) => t.pnp !== void 0 && t.pnp.state !== "rootOnly").map((t) => t.label);
2236
+ }
2237
+ function contentPnpNoteFor(targets) {
2238
+ const names = contentPnpNoteTargets(targets);
2239
+ if (names.length === 0) return void 0;
2240
+ const unplugged = targets.filter((t) => t.pnp?.state === "unplugged").map((t) => t.label);
2241
+ return contentPnpNote(names, unplugged);
2242
+ }
2243
+ var CONTENT_PNP_ROOT_ONLY_ACTION = "\uC571 package.json \uC5D0 \uC120\uC5B8\uD558\uC138\uC694";
2244
+ var CONTENT_PNP_NO_NODE_MODULES = "Plug'n'Play \uB77C node_modules \uACBD\uB85C\uAC00 \uC5C6\uC74C";
2245
+ function contentTargetText(t) {
2246
+ if (t.pnp?.state === "noNodeModules") return `${t.label}(${CONTENT_PNP_NO_NODE_MODULES})`;
2247
+ if (t.pnp?.state === "rootOnly") return `${t.label} \uAC00 ${PNP_ROOT_ONLY_NOTE} \u2192 ${CONTENT_PNP_ROOT_ONLY_ACTION}`;
2248
+ return `${t.label} \u2192 "${t.suggest}"${t.note === void 0 ? "" : ` (${t.note})`}`;
1759
2249
  }
1760
- 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";
1761
2250
  function relDirOf(baseDir, dir) {
1762
2251
  const rel2 = relative(baseDir, dir);
1763
2252
  return rel2 === "" || isAbsolute(rel2) ? void 0 : rel2.split(sep).join("/");
@@ -1777,8 +2266,26 @@ function packageVersion(dir) {
1777
2266
  return void 0;
1778
2267
  }
1779
2268
  }
1780
- function packageContentTarget(baseDir, name) {
1781
- const found = isPnpProject(baseDir) ? void 0 : findInstalledPackage(baseDir, name);
2269
+ function pnpPackageContentTarget(baseDir, name, pkg) {
2270
+ const legacySample = `node_modules/${name}/dist/index.js`;
2271
+ const none = { sample: "", suggest: "", alternates: [], others: [] };
2272
+ if (pnpRootOnlyDependency(baseDir, pkg, name) !== void 0) return { ...none, pnp: { state: "rootOnly", legacySample } };
2273
+ const range = pkg === void 0 ? void 0 : hasDependency(pkg, name);
2274
+ const rels = (range === void 0 ? [] : findPnpUnpluggedPackages(baseDir, name, range)).map((d) => relDirOf(baseDir, d)).filter((r) => r !== void 0);
2275
+ const root = pnpProjectRoot(baseDir);
2276
+ if (rels.length === 0 || root === void 0) return { ...none, pnp: { state: "noNodeModules", legacySample } };
2277
+ const rootRel = relDirOf(baseDir, root);
2278
+ return {
2279
+ sample: `${rels[0]}/dist/index.js`,
2280
+ suggest: `${rootRel === void 0 ? "." : rootRel}/.yarn/unplugged/*/node_modules/${name}/dist/**/*.{js,mjs}`,
2281
+ alternates: rels.slice(1).map((r) => `${r}/dist/index.js`),
2282
+ others: [],
2283
+ pnp: { state: "unplugged", legacySample }
2284
+ };
2285
+ }
2286
+ function packageContentTarget(baseDir, name, pkg) {
2287
+ if (isPnpProject(baseDir)) return pnpPackageContentTarget(baseDir, name, pkg);
2288
+ const found = findInstalledPackage(baseDir, name);
1782
2289
  const relDir = (found === void 0 ? void 0 : relDirOf(baseDir, found.dir)) ?? `node_modules/${name}`;
1783
2290
  const alternates = [];
1784
2291
  const others = [];
@@ -1799,7 +2306,7 @@ function packageContentTarget(baseDir, name) {
1799
2306
  const versions = theirs === void 0 || ours === void 0 ? "" : theirs === ours ? `(\uBC84\uC804\uC740 ${ours} \uB85C \uAC19\uC74C)` : `(${theirs}, \uC571 ${ours})`;
1800
2307
  others.push({
1801
2308
  sample: `${rel2}/dist/index.js`,
1802
- note: `\uC0C1\uC704 \uACBD\uB85C ${rel2} \uB294 \uC571\uC774 \uC4F0\uB294 \uC124\uCE58\uBCF8\uACFC \uB2E4\uB978 \uC124\uCE58\uBCF8${versions}\uC774\uB77C \uB36E\uC74C\uC73C\uB85C \uBCF4\uC9C0 \uC54A\uC544\uC694`
2309
+ note: `\uC0C1\uC704 \uACBD\uB85C ${rel2} \uB294 \uC571\uC774 \uC4F0\uB294 \uC124\uCE58\uBCF8\uACFC \uB2E4\uB978 \uC124\uCE58\uBCF8${versions}\uC774\uB77C \uB36E\uC74C\uC73C\uB85C \uBCF4\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4`
1803
2310
  });
1804
2311
  }
1805
2312
  }
@@ -1876,7 +2383,7 @@ function inspectTailwindContent(baseDirInput) {
1876
2383
  }
1877
2384
  for (const name of TAILWIND4_COMPONENT_PACKAGES) {
1878
2385
  if (declaredRange(baseDir, pkg, name) !== void 0) {
1879
- targets.push({ label: name, ...packageContentTarget(baseDir, name) });
2386
+ targets.push({ label: name, ...packageContentTarget(baseDir, name, pkg) });
1880
2387
  }
1881
2388
  }
1882
2389
  if (targets.length === 0) return null;
@@ -1886,11 +2393,14 @@ function inspectTailwindContent(baseDirInput) {
1886
2393
  configFile,
1887
2394
  unreadable: read === void 0,
1888
2395
  dynamic: read?.dynamic ?? false,
1889
- targets: targets.map(({ alternates = [], others = [], ...t }) => {
2396
+ targets: targets.map(({ alternates = [], others = [], pnp, ...t }) => {
1890
2397
  const covers = (sample) => globs.some((g) => contentGlobCovers(g, sample, baseDir));
1891
- const covered = [t.sample, ...alternates].some(covers);
2398
+ const samples = pnp !== void 0 && pnp.state !== "unplugged" ? [] : [t.sample, ...alternates];
2399
+ const coversSample = pnp?.state === "unplugged" ? (sample) => globs.some((g) => contentGlobCovers(g, sample, baseDir, { noDot: true })) : covers;
2400
+ const covered = samples.some(coversSample);
1892
2401
  const note = covered ? void 0 : others.find((o) => covers(o.sample))?.note;
1893
- return note === void 0 ? { ...t, covered } : { ...t, covered, note };
2402
+ const base = note === void 0 ? { ...t, covered } : { ...t, covered, note };
2403
+ return pnp === void 0 ? base : { ...base, pnp: { state: pnp.state, legacyCovered: covers(pnp.legacySample) } };
1894
2404
  })
1895
2405
  };
1896
2406
  }
@@ -1905,19 +2415,30 @@ function checkTailwindContent(baseDir) {
1905
2415
  message: `${r.configFile}\uC758 content \uAC00 ${r.targets.map((t) => t.label).join(" \xB7 ")} \uB97C \uB36E\uC2B5\uB2C8\uB2E4`
1906
2416
  };
1907
2417
  }
1908
- const list = missing.map((t) => `${t.label} \u2192 "${t.suggest}"${t.note === void 0 ? "" : ` (${t.note})`}`).join(" \xB7 ");
2418
+ const list = missing.map(contentTargetText).join(" \xB7 ");
1909
2419
  const note = missing.some((t) => t.suggest.startsWith("../")) ? ` (${CONTENT_PARENT_PATH_NOTE})` : "";
2420
+ const pnpText = contentPnpNoteFor(missing);
2421
+ const pnpNote = pnpText === void 0 ? "" : ` (${pnpText})`;
1910
2422
  if (r.unreadable || r.dynamic) {
1911
2423
  return {
1912
2424
  name: "tailwind.content",
1913
2425
  severity: "warn",
1914
- 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}`
2426
+ 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}${pnpNote}`
2427
+ };
2428
+ }
2429
+ if (missing.every((t) => t.pnp?.legacyCovered === true)) {
2430
+ const labels = missing.map((t) => t.label).join(" \xB7 ");
2431
+ const details = missing.filter((t) => t.pnp?.state !== "noNodeModules").map(contentTargetText);
2432
+ return {
2433
+ name: "tailwind.content",
2434
+ severity: "warn",
2435
+ message: `${r.configFile}\uC758 content \uAC00 Plug'n'Play \uC5D0\uC11C \uC2A4\uCE94\uB418\uC9C0 \uC54A\uB294 \uACBD\uB85C\uB85C ${labels} \uB97C \uB36E\uC2B5\uB2C8\uB2E4(node_modules \uACBD\uB85C \xB7 ./** \uB294 \uC2A4\uCE94\uB418\uC9C0 \uC54A\uC74C)${details.length > 0 ? `: ${details.join(" \xB7 ")}` : ""}${note}${pnpNote}`
1915
2436
  };
1916
2437
  }
1917
2438
  return {
1918
2439
  name: "tailwind.content",
1919
2440
  severity: "fail",
1920
- 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}`
2441
+ 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}${pnpNote}`
1921
2442
  };
1922
2443
  }
1923
2444
  var ANIMATION_PLUGIN_TAILWIND3 = "tailwindcss-animate";
@@ -1934,7 +2455,7 @@ function componentsUseAnimation(baseDir, componentsDir) {
1934
2455
  const [dir, depth] = stack.pop();
1935
2456
  let names;
1936
2457
  try {
1937
- names = readdirSync(dir);
2458
+ names = readdirSync2(dir);
1938
2459
  } catch {
1939
2460
  continue;
1940
2461
  }
@@ -1975,24 +2496,30 @@ function checkAnimationPlugin(baseDirInput) {
1975
2496
  return void 0;
1976
2497
  };
1977
2498
  if (tailwind.major !== void 0 && tailwind.major >= 4) {
1978
- const file = TAILWIND_CSS_CANDIDATES.find((c) => existsSync3(join2(baseDir, c)));
1979
- const css = file !== void 0 ? stripCssComments(readFileSync4(join2(baseDir, file), "utf8")) : "";
2499
+ const selection = selectCheckGlobalCss(baseDir);
2500
+ const note = globalCssSelectionNote(selection);
2501
+ const file = selection.rel;
2502
+ const expanded = selection.path !== void 0 && selection.rel !== void 0 ? expandGlobalCss(baseDir, selection.path, selection.rel, outsideCssDir(selection)) : void 0;
2503
+ const css = expanded !== void 0 ? stripCssComments(expanded.evidence) : "";
2504
+ const twAnimate = new RegExp(`@import\\s+(?:url\\(\\s*)?["']${ANIMATION_PLUGIN_TAILWIND4}["']`);
2505
+ const animatePlugin = new RegExp(`@plugin\\s+["']${ANIMATION_PLUGIN_TAILWIND3}["']`);
1980
2506
  const lines = [];
1981
- if (new RegExp(`@import\\s+(?:url\\(\\s*)?["']${ANIMATION_PLUGIN_TAILWIND4}["']`).test(css)) lines.push(ANIMATION_PLUGIN_TAILWIND4);
1982
- if (new RegExp(`@plugin\\s+["']${ANIMATION_PLUGIN_TAILWIND3}["']`).test(css)) lines.push(ANIMATION_PLUGIN_TAILWIND3);
2507
+ if (twAnimate.test(css)) lines.push(ANIMATION_PLUGIN_TAILWIND4);
2508
+ if (animatePlugin.test(css)) lines.push(ANIMATION_PLUGIN_TAILWIND3);
2509
+ const via = expanded !== void 0 ? cssImportViaNote(viaFiles([evidenceOrigin(expanded, (f) => twAnimate.test(f)), evidenceOrigin(expanded, (f) => animatePlugin.test(f))])) : "";
1983
2510
  if (lines.length === 0) {
1984
2511
  return {
1985
2512
  name: "animation",
1986
2513
  severity: "warn",
1987
- message: `\uC560\uB2C8\uBA54\uC774\uC158 \uD50C\uB7EC\uADF8\uC778\uC774 \uC5C6\uC2B5\uB2C8\uB2E4(${by}): Dialog \xB7 Select \uB4F1\uC758 \uC5F4\uACE0 \uB2EB\uB294 \uC560\uB2C8\uBA54\uC774\uC158\uC774 \uB3D9\uC791\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4 \u2192 ${ANIMATION_PLUGIN_TAILWIND4} \uC124\uCE58 \uB4A4 @import "${ANIMATION_PLUGIN_TAILWIND4}";`
2514
+ message: `\uC560\uB2C8\uBA54\uC774\uC158 \uD50C\uB7EC\uADF8\uC778\uC774 \uC5C6\uC2B5\uB2C8\uB2E4(${by}): Dialog \xB7 Select \uB4F1\uC758 \uC5F4\uACE0 \uB2EB\uB294 \uC560\uB2C8\uBA54\uC774\uC158\uC774 \uB3D9\uC791\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4 \u2192 ${ANIMATION_PLUGIN_TAILWIND4} \uC124\uCE58 \uB4A4 @import "${ANIMATION_PLUGIN_TAILWIND4}";${note}`
1988
2515
  };
1989
2516
  }
1990
2517
  const problems = lines.map((name) => ({ name, why: pluginProblem(name) })).filter((x) => x.why !== void 0);
1991
- if (problems.length === 0) return { name: "animation", severity: "pass", message: `${file}\uC5D0 \uC560\uB2C8\uBA54\uC774\uC158 \uD50C\uB7EC\uADF8\uC778\uC774 \uC788\uC2B5\uB2C8\uB2E4` };
2518
+ if (problems.length === 0) return { name: "animation", severity: "pass", message: `${file}\uC5D0 \uC560\uB2C8\uBA54\uC774\uC158 \uD50C\uB7EC\uADF8\uC778\uC774 \uC788\uC2B5\uB2C8\uB2E4${via}${note}` };
1992
2519
  return {
1993
2520
  name: "animation",
1994
2521
  severity: "warn",
1995
- message: `${file}\uC758 \uC560\uB2C8\uBA54\uC774\uC158 \uD50C\uB7EC\uADF8\uC778\uC744 \uC4F8 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4(${by}, ${problems.map((x) => x.why).join(" \xB7 ")}): Dialog \xB7 Select \uB4F1\uC758 \uC5F4\uACE0 \uB2EB\uB294 \uC560\uB2C8\uBA54\uC774\uC158\uC774 \uB3D9\uC791\uD558\uC9C0 \uC54A\uACE0 \uBE4C\uB4DC\uAC00 \uC2E4\uD328\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4 \u2192 ${problems.map((x) => x.name).join(" \xB7 ")} \uB97C package.json \uC5D0 \uC120\uC5B8 \xB7 \uC124\uCE58\uD558\uC138\uC694`
2522
+ message: `${file}\uC758 \uC560\uB2C8\uBA54\uC774\uC158 \uD50C\uB7EC\uADF8\uC778\uC744 \uC4F8 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4(${by}, ${problems.map((x) => x.why).join(" \xB7 ")}): Dialog \xB7 Select \uB4F1\uC758 \uC5F4\uACE0 \uB2EB\uB294 \uC560\uB2C8\uBA54\uC774\uC158\uC774 \uB3D9\uC791\uD558\uC9C0 \uC54A\uACE0 \uBE4C\uB4DC\uAC00 \uC2E4\uD328\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4 \u2192 ${problems.map((x) => x.name).join(" \xB7 ")} \uB97C package.json \uC5D0 \uC120\uC5B8 \xB7 \uC124\uCE58\uD558\uC138\uC694${via}${note}`
1996
2523
  };
1997
2524
  }
1998
2525
  const configFile = TAILWIND_CONFIG_FILES.find((f) => existsSync3(join2(baseDir, f)));
@@ -2097,7 +2624,7 @@ function selectUtilsDependencies(tailwind) {
2097
2624
  }
2098
2625
 
2099
2626
  // ../axis-registry-core/src/add/safe-write.ts
2100
- import { constants as fsConstants, existsSync as existsSync4, lstatSync as lstatSync2, realpathSync as realpathSync3, statSync as statSync2 } from "fs";
2627
+ import { constants as fsConstants, existsSync as existsSync4, lstatSync as lstatSync2, realpathSync as realpathSync3, statSync as statSync3 } from "fs";
2101
2628
  import path4 from "path";
2102
2629
  import fs2 from "fs-extra";
2103
2630
  var NEW_FILE_FLAGS = fsConstants.O_WRONLY | fsConstants.O_CREAT | fsConstants.O_EXCL | (fsConstants.O_NOFOLLOW ?? 0);
@@ -2153,7 +2680,7 @@ function escapeReason(root, target, options = {}) {
2153
2680
  }
2154
2681
  let followed;
2155
2682
  try {
2156
- followed = statSync2(realTarget);
2683
+ followed = statSync3(realTarget);
2157
2684
  } catch {
2158
2685
  return `\uAE30\uC874 \uD30C\uC77C \uC815\uBCF4\uB97C \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4(${target})`;
2159
2686
  }
@@ -2425,7 +2952,7 @@ function relativeSpecifierResolves(fromFile, spec) {
2425
2952
  const base = path5.resolve(path5.dirname(fromFile), spec);
2426
2953
  return RESOLVE_EXTS.some((ext) => {
2427
2954
  try {
2428
- return statSync3(base + ext).isFile();
2955
+ return statSync4(base + ext).isFile();
2429
2956
  } catch {
2430
2957
  return false;
2431
2958
  }
@@ -3208,7 +3735,7 @@ function formatTokenList(result) {
3208
3735
  }
3209
3736
 
3210
3737
  // src/tools/install.ts
3211
- import { statSync as statSync4 } from "fs";
3738
+ import { statSync as statSync5 } from "fs";
3212
3739
  import path6 from "path";
3213
3740
  var DEFAULT_LAYOUT_CONFIG = { componentsDir: "components/ui" };
3214
3741
  var MCP_ADD_HINTS = {
@@ -3247,7 +3774,7 @@ async function handleInstallComponent(params, deps = {}) {
3247
3774
  const root = path6.resolve(params.targetDir);
3248
3775
  let isDir = false;
3249
3776
  try {
3250
- isDir = statSync4(root).isDirectory();
3777
+ isDir = statSync5(root).isDirectory();
3251
3778
  } catch {
3252
3779
  isDir = false;
3253
3780
  }
@@ -4752,7 +5279,7 @@ import fs6 from "fs-extra";
4752
5279
  import path9 from "path";
4753
5280
 
4754
5281
  // src/tools/brand-core.ts
4755
- import { existsSync as existsSync8, readFileSync as readFileSync8, statSync as statSync5 } from "fs";
5282
+ import { existsSync as existsSync8, readFileSync as readFileSync8, statSync as statSync6 } from "fs";
4756
5283
  import { createRequire } from "module";
4757
5284
  import { dirname as dirname4, join as join4, relative as relative2, resolve as resolve3, sep as sep2 } from "path";
4758
5285
  var TOKENS_PACKAGE = "@axis-ds/tokens";
@@ -4815,29 +5342,11 @@ function brandImportPath(entry) {
4815
5342
  }
4816
5343
  function isFile2(file) {
4817
5344
  try {
4818
- return statSync5(file).isFile();
5345
+ return statSync6(file).isFile();
4819
5346
  } catch {
4820
5347
  return false;
4821
5348
  }
4822
5349
  }
4823
- function findGlobalCss(baseDir, config) {
4824
- const root = resolve3(baseDir);
4825
- const result = {};
4826
- const configured = config?.globalCss;
4827
- if (typeof configured === "string" && configured.trim() !== "") {
4828
- const file = resolve3(root, configured);
4829
- if (isFile2(file)) return { path: file };
4830
- result.configuredMissing = configured;
4831
- }
4832
- for (const candidate of GLOBAL_CSS_CANDIDATES) {
4833
- const file = join4(root, candidate);
4834
- if (isFile2(file)) {
4835
- result.path = file;
4836
- break;
4837
- }
4838
- }
4839
- return result;
4840
- }
4841
5350
  function findBrandImports(css) {
4842
5351
  const names = [];
4843
5352
  const pattern = /@import\s+(?:url\(\s*)?["']?@axis-ds\/tokens\/css\/brands\/([a-z][a-z0-9-]*)(?:\.css)?["']?\s*\)?\s*(?=[;\s]|$)/g;
@@ -4862,18 +5371,24 @@ function inspectBrandImport(baseDir) {
4862
5371
  const brand = config?.brand;
4863
5372
  if (typeof brand !== "string" || brand.trim() === "") return null;
4864
5373
  const root = resolve3(baseDir);
4865
- const location = findGlobalCss(root, config);
5374
+ const location = selectGlobalCss(root, config?.globalCss, GLOBAL_CSS_CANDIDATES, { requireStylesheet: true });
4866
5375
  const base = { brand };
4867
5376
  if (location.configuredMissing !== void 0) base.configuredMissing = location.configuredMissing;
5377
+ if (location.configuredRejected !== void 0) base.configuredRejected = location.configuredRejected;
4868
5378
  if (!location.path) {
4869
5379
  return { ...base, state: "css-missing", imports: [] };
4870
5380
  }
4871
5381
  const cssFile = relative2(root, location.path).split(sep2).join("/");
4872
- const imports = [...new Set(findBrandImports(readFileSync8(location.path, "utf8")))];
5382
+ const expanded = expandGlobalCss(root, location.path, cssFile);
5383
+ const imports = [...new Set(findBrandImports(expanded.evidence))];
4873
5384
  let state;
4874
5385
  if (imports.includes(brand)) state = "match";
4875
5386
  else if (imports.length === 0) state = "import-missing";
4876
5387
  else state = "other-brand";
5388
+ const sub = expanded.files.filter((f) => f.depth > 0);
5389
+ const via = state === "match" ? sub.filter((f) => findBrandImports(f.css).includes(brand)).slice(0, 1) : state === "other-brand" ? sub.filter((f) => findBrandImports(f.css).length > 0) : [];
5390
+ const entryHas = state === "match" && findBrandImports(expanded.files[0].css).includes(brand);
5391
+ if (via.length > 0 && !entryHas) return { ...base, state, cssFile, imports, importVia: via.map((f) => f.rel) };
4877
5392
  return { ...base, state, cssFile, imports };
4878
5393
  }
4879
5394
  function isMissingBuildFile(err) {
@@ -5262,13 +5777,14 @@ async function handleDiffTemplate(params) {
5262
5777
  }
5263
5778
  function brandCheckResult(check) {
5264
5779
  const { brand } = check;
5265
- const suffix = check.configuredMissing !== void 0 ? ` (globalCss ${check.configuredMissing} \uC5C6\uC74C)` : "";
5780
+ const suffix = globalCssSelectionNote(check);
5781
+ const via = cssImportViaNote(check.importVia);
5266
5782
  switch (check.state) {
5267
5783
  case "match":
5268
5784
  return {
5269
5785
  name: "brand",
5270
5786
  severity: "pass",
5271
- message: `brand "${brand}" import \uAC00 ${check.cssFile}\uC5D0 \uC788\uC2B5\uB2C8\uB2E4${suffix}`
5787
+ message: `brand "${brand}" import \uAC00 ${check.cssFile}\uC5D0 \uC788\uC2B5\uB2C8\uB2E4${via}${suffix}`
5272
5788
  };
5273
5789
  case "css-missing":
5274
5790
  return {
@@ -5286,7 +5802,7 @@ function brandCheckResult(check) {
5286
5802
  return {
5287
5803
  name: "brand",
5288
5804
  severity: "warn",
5289
- message: `brand "${brand}" \uC640 import(${check.imports.join(", ")})\uAC00 \uB2E4\uB985\uB2C8\uB2E4${suffix}`
5805
+ message: `brand "${brand}" \uC640 import(${check.imports.join(", ")})\uAC00 \uB2E4\uB985\uB2C8\uB2E4${via}${suffix}`
5290
5806
  };
5291
5807
  }
5292
5808
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axis-ds/mcp",
3
- "version": "1.4.5",
3
+ "version": "1.4.6",
4
4
  "type": "module",
5
5
  "description": "AXIS Design System - MCP Server for AI-assisted component discovery",
6
6
  "bin": {