@axis-ds/mcp 1.4.4 → 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 (3) hide show
  1. package/README.md +1 -0
  2. package/dist/index.js +777 -149
  3. 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);
@@ -970,14 +970,56 @@ function workspaceRootPackage(baseDirInput) {
970
970
  return void 0;
971
971
  }
972
972
  }
973
- function declaredDependency(baseDir, pkg, name, rootPkg) {
973
+ function declaredDependency(baseDir, pkg, name, rootPkg, options = {}) {
974
974
  if (pkg === void 0) return void 0;
975
975
  const own = hasDependency(pkg, name);
976
976
  if (own !== void 0) return { range: own, source: "app" };
977
+ if (options.appOnlyInPnp && isPnpProject(baseDir)) return void 0;
977
978
  const root = rootPkg === void 0 ? workspaceRootPackage(baseDir) : rootPkg ?? void 0;
978
979
  const fromRoot = root !== void 0 ? hasDependency(root, name) : void 0;
979
980
  return fromRoot !== void 0 ? { range: fromRoot, source: "root" } : void 0;
980
981
  }
982
+ function pnpRootOnlyDependency(baseDir, pkg, name, rootPkg) {
983
+ if (pkg === void 0 || hasDependency(pkg, name) !== void 0 || !isPnpProject(baseDir)) return void 0;
984
+ const found = declaredDependency(baseDir, pkg, name, rootPkg);
985
+ return found?.source === "root" ? found : void 0;
986
+ }
987
+ var PNP_ROOT_ONLY_NOTE = "\uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uB8E8\uD2B8\uC5D0\uB9CC \uC120\uC5B8\uB3FC Plug'n'Play \uC5D0\uC11C \uC571\uC774 \uD574\uC11D\uD558\uC9C0 \uBABB\uD569\uB2C8\uB2E4";
988
+ var APP_LOCKFILES = ["package-lock.json", "pnpm-lock.yaml", "yarn.lock", "bun.lockb", "bun.lock"];
989
+ function hasAppLockfile(baseDirInput) {
990
+ const baseDir = path3.resolve(baseDirInput);
991
+ return APP_LOCKFILES.some((f) => existsSync2(path3.join(baseDir, f)));
992
+ }
993
+ function rootDeclarationsAllowed(baseDir, pkg) {
994
+ return pkg !== void 0 && !isPnpProject(baseDir) && !hasAppLockfile(baseDir);
995
+ }
996
+ function readPackageJsonAt(dir) {
997
+ try {
998
+ const parsed = JSON.parse(readFileSync3(path3.join(dir, "package.json"), "utf8"));
999
+ return isPlainObject(parsed) ? parsed : void 0;
1000
+ } catch {
1001
+ return void 0;
1002
+ }
1003
+ }
1004
+ function dependencyInstallGuide(baseDirInput, name, range) {
1005
+ const baseDir = resolveBaseDir(baseDirInput);
1006
+ const installCommand = detectInstallCommand(baseDir);
1007
+ const base = { installCommand, addCommand: addCommandFor(installCommand, { [name]: range }) };
1008
+ const pkg = readPackageJsonAt(baseDir);
1009
+ if (pkg === void 0) return { kind: "add", ...base };
1010
+ const own = hasDependency(pkg, name);
1011
+ if (isPnpProject(baseDir)) return own !== void 0 ? { kind: "pnp", source: "app", range: own, ...base } : { kind: "add", ...base };
1012
+ if (own !== void 0) return { kind: "install", source: "app", range: own, ...base };
1013
+ if (!rootDeclarationsAllowed(baseDir, pkg)) return { kind: "add", ...base };
1014
+ const declared = declaredDependency(baseDir, pkg, name);
1015
+ if (declared?.source !== "root") return { kind: "add", ...base };
1016
+ return {
1017
+ kind: packageManagerOf(installCommand) === "npm" ? "install-at-root" : "install",
1018
+ source: "root",
1019
+ range: declared.range,
1020
+ ...base
1021
+ };
1022
+ }
981
1023
  function isPlainObject(value) {
982
1024
  return typeof value === "object" && value !== null && !Array.isArray(value);
983
1025
  }
@@ -1020,6 +1062,32 @@ function isFile(file) {
1020
1062
  return false;
1021
1063
  }
1022
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
+ }
1023
1091
  var ROOT_LAYOUT_FILES = [
1024
1092
  "app/layout.tsx",
1025
1093
  "app/layout.jsx",
@@ -1063,14 +1131,174 @@ function findInstalledPackage(baseDirInput, name) {
1063
1131
  }
1064
1132
  }
1065
1133
  function isPnpProject(baseDirInput) {
1134
+ return pnpProjectRoot(baseDirInput) !== void 0;
1135
+ }
1136
+ function pnpProjectRoot(baseDirInput) {
1066
1137
  let dir = resolveBaseDir(baseDirInput);
1067
1138
  for (; ; ) {
1068
- if (isFile(path3.join(dir, ".pnp.cjs")) || isFile(path3.join(dir, ".pnp.js"))) return true;
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;
1069
1141
  const parent = path3.dirname(dir);
1070
- if (parent === dir) return false;
1142
+ if (parent === dir) return void 0;
1071
1143
  dir = parent;
1072
1144
  }
1073
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
+ }
1074
1302
  function compareExactVersions(a, b) {
1075
1303
  const parse = (v) => {
1076
1304
  const m = /^v?(\d+)\.(\d+)\.(\d+)(-[0-9A-Za-z.-]+)?/.exec(v.trim());
@@ -1084,11 +1312,14 @@ function compareExactVersions(a, b) {
1084
1312
  }
1085
1313
 
1086
1314
  // ../axis-registry-core/src/template/tailwind-core.ts
1087
- 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";
1088
1316
  import { basename, dirname as dirname2, extname, isAbsolute, join as join2, relative, resolve, sep } from "path";
1089
1317
  function declaredRange(baseDir, pkg, name) {
1090
1318
  return declaredDependency(baseDir, pkg, name)?.range;
1091
1319
  }
1320
+ function declaredRangeForCheck(baseDir, pkg, name) {
1321
+ return declaredDependency(baseDir, pkg, name, void 0, { appOnlyInPnp: true })?.range;
1322
+ }
1092
1323
  function isPlainObject2(value) {
1093
1324
  return typeof value === "object" && value !== null && !Array.isArray(value);
1094
1325
  }
@@ -1209,6 +1440,157 @@ var TOKENS_CSS_IMPORT = /@import\s+(?:url\(\s*)?["'](@axis-ds\/tokens\/css(?:\/s
1209
1440
  function findTokensCssImport(css) {
1210
1441
  return TOKENS_CSS_IMPORT.exec(stripCssComments(css))?.[1];
1211
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
+ }
1212
1594
  var TOKENS_CSS_JS_IMPORT = /(?:\bimport\s+|\bfrom\s+|\brequire\s*\(\s*)(["'])(@axis-ds\/tokens\/css(?:\/shadcn|\/tailwind4)?)\1/;
1213
1595
  var AXIS_VARIABLE_DEFINITION = /(?<![\w-])--axis-[\w-]+\s*:/;
1214
1596
  function findLayoutTokensCssImport(baseDirInput) {
@@ -1227,45 +1609,92 @@ function findLayoutTokensCssImport(baseDirInput) {
1227
1609
  }
1228
1610
  return void 0;
1229
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
+ }
1230
1638
  function checkGlobalsCss(baseDirInput) {
1231
1639
  const baseDir = resolveBaseDir(baseDirInput);
1232
- for (const candidate of TAILWIND_CSS_CANDIDATES) {
1233
- const file = join2(baseDir, candidate);
1234
- if (!existsSync3(file)) continue;
1235
- const content = readFileSync4(file, "utf8");
1236
- const css = stripCssComments(content);
1237
- const imported = findTokensCssImport(content);
1238
- let pass;
1239
- if (imported !== void 0) pass = `${candidate}\uC5D0 AXIS CSS \uBCC0\uC218\uAC00 \uC788\uC2B5\uB2C8\uB2E4 (${imported} import)`;
1240
- else if (AXIS_VARIABLE_DEFINITION.test(css)) pass = `${candidate}\uC5D0 AXIS CSS \uBCC0\uC218(--axis-*)\uAC00 \uC815\uC758\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4`;
1241
- else {
1242
- const layout = findLayoutTokensCssImport(baseDir);
1243
- if (layout) pass = `${candidate}\uC5D0 AXIS CSS \uBCC0\uC218\uAC00 \uC788\uC2B5\uB2C8\uB2E4 (${layout.file}\uC758 ${layout.spec} import)`;
1244
- }
1245
- if (pass !== void 0) {
1246
- const tailwind = detectTailwind(baseDir, readPackageJson(baseDir));
1247
- const tailwind4 = tailwind.major !== void 0 && tailwind.major >= 4;
1248
- if (!tailwind4 && findCreateNextAppDefaults(content).some((d) => d.includes("font-family: Arial"))) {
1249
- return {
1250
- name: "globals.css",
1251
- severity: "warn",
1252
- 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)`
1253
- };
1254
- }
1255
- return { name: "globals.css", severity: "pass", message: pass };
1256
- }
1257
- 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"))) {
1258
1683
  return {
1259
- name: "globals.css",
1260
1684
  severity: "warn",
1261
- 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}`
1262
1686
  };
1263
1687
  }
1264
- 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
+ };
1265
1695
  }
1266
- 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` };
1267
1697
  }
1268
- var TAILWIND4_MIN_AXIS_VERSION = "1.4.0";
1269
1698
  var TAILWIND4_AXIS_PACKAGES = ["@axis-ds/tokens", "@axis-ds/ui-react", "@axis-ds/agentic-ui"];
1270
1699
  function lowerOf(token) {
1271
1700
  const v = versionParts(token);
@@ -1463,7 +1892,7 @@ function hasBareCjsPresetRequire(code) {
1463
1892
  function isCommonJsConfig(file, source) {
1464
1893
  return extname(file) === ".cjs" || /\bmodule\.exports\b/.test(source);
1465
1894
  }
1466
- function packageVersionGate(baseDirInput, pkg, name, min) {
1895
+ function packageVersionGate(baseDirInput, pkg, name, min, options = {}) {
1467
1896
  const baseDir = resolveBaseDir(baseDirInput);
1468
1897
  if (!isPnpProject(baseDir)) {
1469
1898
  const installed = findInstalledPackage(baseDir, name)?.version;
@@ -1472,7 +1901,11 @@ function packageVersionGate(baseDirInput, pkg, name, min) {
1472
1901
  if (cmp !== void 0) return { status: cmp >= 0 ? "ok" : "below", source: "installed", value: installed };
1473
1902
  }
1474
1903
  }
1475
- const declared = pkg ? declaredRange(baseDir, pkg, name) : void 0;
1904
+ const declared = pkg ? declaredDependency(baseDir, pkg, name, void 0, options)?.range : void 0;
1905
+ if (declared === void 0 && options.appOnlyInPnp) {
1906
+ const rootOnly = pnpRootOnlyDependency(baseDir, pkg, name);
1907
+ if (rootOnly !== void 0) return { status: "unresolved", source: "declared", value: rootOnly.range };
1908
+ }
1476
1909
  if (declared !== void 0) {
1477
1910
  const atLeast = rangeLowerAtLeast(declared, min);
1478
1911
  if (atLeast !== void 0) return { status: atLeast ? "ok" : "below", source: "declared", value: declared };
@@ -1481,6 +1914,7 @@ function packageVersionGate(baseDirInput, pkg, name, min) {
1481
1914
  return { status: "unknown", source: "none" };
1482
1915
  }
1483
1916
  function versionGateLabel(gate) {
1917
+ if (gate.status === "unresolved") return `\uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uB8E8\uD2B8 \uC120\uC5B8 ${gate.value}`;
1484
1918
  if (gate.source === "installed") return `\uC124\uCE58\uBCF8 ${gate.value}`;
1485
1919
  if (gate.source === "declared") return `\uC120\uC5B8 ${gate.value}`;
1486
1920
  return "\uC124\uCE58\uBCF8 \xB7 \uC120\uC5B8 \uC5C6\uC74C";
@@ -1493,66 +1927,134 @@ function readPackageJson(baseDir) {
1493
1927
  return void 0;
1494
1928
  }
1495
1929
  }
1496
- 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);
1497
1933
  const issues = [];
1498
- 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);
1499
1939
  if (!hasEntry) issues.push(`AXIS \uD1A0\uD070 \uC9C4\uC785\uC810\uC774 \uC5C6\uC2B5\uB2C8\uB2E4 \u2192 ${TOKENS_TAILWIND4_IMPORT_LINE}`);
1500
- const missing = TAILWIND4_COMPONENT_PACKAGES.filter(
1501
- (name) => declaredRange(baseDir, pkg, name) !== void 0 && !hasComponentTailwindImport(css, name) && !hasComponentSource(css, name)
1502
- );
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
+ }
1503
1950
  if (missing.length > 0) {
1504
1951
  issues.push(`\uCEF4\uD3EC\uB10C\uD2B8 \uC2A4\uCE94 \uACBD\uB85C(tailwind.css)\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4 \u2192 ${missing.map(componentTailwindImportLine).join(" ")}`);
1505
1952
  }
1953
+ issues.push(...unresolvedMissing);
1506
1954
  if (hasEntry) {
1507
- const defaults = findCreateNextAppDefaults(css);
1955
+ const defaults = findCreateNextAppDefaults(entry);
1508
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`);
1509
1957
  if (versions.some((v) => v.name === TAILWIND4_AXIS_PACKAGES[0])) {
1510
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`);
1511
1959
  }
1512
1960
  }
1513
1961
  for (const name of TAILWIND4_COMPONENT_PACKAGES) {
1514
- if (hasComponentTailwindImport(css, name) && versions.some((v) => v.name === name)) {
1515
- issues.push(`${name}/tailwind.css import \uAC00 \uC788\uC9C0\uB9CC ${name} \uBC84\uC804 \uD655\uC778\uC774 \uD544\uC694\uD569\uB2C8\uB2E4`);
1516
- }
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`);
1517
1969
  }
1518
1970
  return issues;
1519
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
+ }
1520
2006
  function checkTailwindSetup(baseDirInput) {
1521
2007
  const baseDir = resolveBaseDir(baseDirInput);
1522
2008
  const pkg = readPackageJson(baseDir);
1523
2009
  const tailwind = detectTailwind(baseDir, pkg);
1524
2010
  if (tailwind.major !== void 0 && tailwind.major >= 4) {
1525
2011
  const label = `Tailwind ${tailwind.major}`;
1526
- for (const candidate of TAILWIND_CSS_CANDIDATES) {
1527
- const file = join2(baseDir, candidate);
1528
- if (!existsSync3(file)) continue;
1529
- const css = readFileSync4(file, "utf8");
1530
- 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)) {
1531
2018
  return {
1532
2019
  name: "tailwind.config",
1533
2020
  severity: "warn",
1534
- message: `${label}: ${candidate}\uC5D0 @import "tailwindcss" \uAC00 \uC5C6\uC2B5\uB2C8\uB2E4`
2021
+ message: `${label}: ${candidate}\uC5D0 @import "tailwindcss" \uAC00 \uC5C6\uC2B5\uB2C8\uB2E4${note}`
1535
2022
  };
1536
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
+ );
1537
2034
  const versions = axisPackagesBelowTailwind4(pkg, baseDir);
1538
- 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
+ );
1539
2041
  if (issues.length > 0) {
1540
2042
  return {
1541
2043
  name: "tailwind.config",
1542
2044
  severity: "warn",
1543
- message: `${label}: ${candidate}\uC5D0 ${issues.join(" / ")}${tailwind4VersionNote(versions)}`
2045
+ message: `${label}: ${candidate}\uC5D0 ${issues.join(" / ")}${tailwind4VersionNote(versions)}${via}${note}`
1544
2046
  };
1545
2047
  }
1546
2048
  return {
1547
2049
  name: "tailwind.config",
1548
2050
  severity: "pass",
1549
- 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}`
1550
2052
  };
1551
2053
  }
1552
2054
  return {
1553
2055
  name: "tailwind.config",
1554
2056
  severity: "warn",
1555
- 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}`
1556
2058
  };
1557
2059
  }
1558
2060
  for (const file of TAILWIND_CONFIG_FILES) {
@@ -1562,7 +2064,14 @@ function checkTailwindSetup(baseDirInput) {
1562
2064
  if (hasTokensPresetReference(content)) {
1563
2065
  const code = stripJsComments(content);
1564
2066
  if (isCommonJsConfig(file, code) && hasBareCjsPresetRequire(code)) {
1565
- const gate = packageVersionGate(baseDir, pkg, "@axis-ds/tokens", TOKENS_CJS_PRESET_FIXED_VERSION);
2067
+ const gate = packageVersionGate(baseDir, pkg, "@axis-ds/tokens", TOKENS_CJS_PRESET_FIXED_VERSION, { appOnlyInPnp: true });
2068
+ if (gate.status === "unresolved") {
2069
+ return {
2070
+ name: "tailwind.config",
2071
+ severity: "warn",
2072
+ message: `${file}\uC5D0 AXIS preset \uCC38\uC870\uAC00 \uC788\uC9C0\uB9CC @axis-ds/tokens \uAC00 ${PNP_ROOT_ONLY_NOTE}(${versionGateLabel(gate)}) \u2192 \uC571 package.json \uC5D0 @axis-ds/tokens ${TOKENS_CJS_PRESET_FIXED_VERSION} \uC774\uC0C1\uC744 \uC120\uC5B8\uD558\uC138\uC694`
2073
+ };
2074
+ }
1566
2075
  if (gate.status !== "ok") {
1567
2076
  const why = gate.status === "below" ? `@axis-ds/tokens ${versionGateLabel(gate)} \uC5D0\uC11C\uB294 CommonJS \uC758 require("${TOKENS_TAILWIND3_PRESET}") \uAC00 preset \uC774 \uC544\uB2C8\uB77C { default } \uB97C \uB3CC\uB824\uC918 \uC0C9 \xB7 keyframes \uAC00 \uC801\uC6A9\uB418\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4` : `@axis-ds/tokens \uBC84\uC804\uC744 \uD655\uC778\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4(${versionGateLabel(gate)}). ${TOKENS_CJS_PRESET_FIXED_VERSION} \uBBF8\uB9CC\uC774\uBA74 CommonJS \uC758 require("${TOKENS_TAILWIND3_PRESET}") \uB85C\uB294 preset \uC774 \uC801\uC6A9\uB418\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4`;
1568
2077
  return {
@@ -1591,31 +2100,45 @@ function readAxisConfigLike(baseDir) {
1591
2100
  return void 0;
1592
2101
  }
1593
2102
  }
1594
- 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;
1595
2108
  const g = glob.trim().replace(/^\.\//, "");
2109
+ const lead = (i) => noDot && (i === 0 || g[i - 1] === "/") ? "(?!\\.)" : "";
1596
2110
  let re = "";
1597
2111
  for (let i = 0; i < g.length; i++) {
1598
2112
  const c = g[i];
1599
2113
  if (c === "*") {
1600
2114
  if (g[i + 1] === "*") {
1601
2115
  const slash = g[i + 2] === "/";
1602
- re += slash ? "(?:.*/)?" : ".*";
2116
+ if (noDot) re += slash ? `(?:${lead(i)}[^/]*/(?:(?!\\.)[^/]*/)*)?` : `${lead(i)}[^/]*(?:/(?!\\.)[^/]*)*`;
2117
+ else re += slash ? "(?:.*/)?" : ".*";
1603
2118
  i += slash ? 2 : 1;
1604
- } else re += "[^/]*";
1605
- } else if (c === "?") re += "[^/]";
2119
+ } else re += `${lead(i)}[^/]*`;
2120
+ } else if (c === "?") re += `${lead(i)}[^/]`;
1606
2121
  else if (c === "{") {
1607
2122
  const end = g.indexOf("}", i);
1608
2123
  if (end === -1) {
1609
2124
  re += "\\{";
1610
2125
  continue;
1611
2126
  }
1612
- 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("|")})`;
1613
2136
  i = end;
1614
2137
  } else if (c === "[") {
1615
2138
  const end = g.indexOf("]", i);
1616
2139
  if (end === -1) re += "\\[";
1617
2140
  else {
1618
- re += g.slice(i, end + 1);
2141
+ re += lead(i) + g.slice(i, end + 1);
1619
2142
  i = end;
1620
2143
  }
1621
2144
  } else re += c.replace(/[.+^$()|\\]/g, "\\$&");
@@ -1684,22 +2207,46 @@ function realpathPosix(p) {
1684
2207
  }
1685
2208
  return void 0;
1686
2209
  }
1687
- function contentGlobBranchCovers(glob, sample, baseDir) {
2210
+ function contentGlobBranchCovers(glob, sample, baseDir, noDot) {
1688
2211
  if (isAbsoluteGlob(glob)) {
1689
- const re = contentGlobToRegExp(glob.trim().replace(/\\/g, "/"));
2212
+ const re = contentGlobToRegExp(glob.trim().replace(/\\/g, "/"), { noDot });
1690
2213
  const absSample = resolve(baseDir, sample);
1691
2214
  if (re.test(absSample.split(sep).join("/"))) return true;
1692
2215
  const real = realpathPosix(absSample);
1693
2216
  return real !== void 0 && re.test(real);
1694
2217
  }
1695
- return leadingParentSegments(glob) === leadingParentSegments(sample) && contentGlobToRegExp(glob).test(sample);
2218
+ return leadingParentSegments(glob) === leadingParentSegments(sample) && contentGlobToRegExp(glob, { noDot }).test(sample);
1696
2219
  }
1697
- function contentGlobCovers(glob, sample, baseDirInput) {
2220
+ function contentGlobCovers(glob, sample, baseDirInput, opts = {}) {
1698
2221
  const baseDir = resolveBaseDir(baseDirInput);
1699
2222
  const branches = expandBraces(glob.trim()) ?? [glob];
1700
- 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})`}`;
1701
2249
  }
1702
- 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";
1703
2250
  function relDirOf(baseDir, dir) {
1704
2251
  const rel2 = relative(baseDir, dir);
1705
2252
  return rel2 === "" || isAbsolute(rel2) ? void 0 : rel2.split(sep).join("/");
@@ -1719,8 +2266,26 @@ function packageVersion(dir) {
1719
2266
  return void 0;
1720
2267
  }
1721
2268
  }
1722
- function packageContentTarget(baseDir, name) {
1723
- 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);
1724
2289
  const relDir = (found === void 0 ? void 0 : relDirOf(baseDir, found.dir)) ?? `node_modules/${name}`;
1725
2290
  const alternates = [];
1726
2291
  const others = [];
@@ -1741,7 +2306,7 @@ function packageContentTarget(baseDir, name) {
1741
2306
  const versions = theirs === void 0 || ours === void 0 ? "" : theirs === ours ? `(\uBC84\uC804\uC740 ${ours} \uB85C \uAC19\uC74C)` : `(${theirs}, \uC571 ${ours})`;
1742
2307
  others.push({
1743
2308
  sample: `${rel2}/dist/index.js`,
1744
- 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`
1745
2310
  });
1746
2311
  }
1747
2312
  }
@@ -1818,7 +2383,7 @@ function inspectTailwindContent(baseDirInput) {
1818
2383
  }
1819
2384
  for (const name of TAILWIND4_COMPONENT_PACKAGES) {
1820
2385
  if (declaredRange(baseDir, pkg, name) !== void 0) {
1821
- targets.push({ label: name, ...packageContentTarget(baseDir, name) });
2386
+ targets.push({ label: name, ...packageContentTarget(baseDir, name, pkg) });
1822
2387
  }
1823
2388
  }
1824
2389
  if (targets.length === 0) return null;
@@ -1828,11 +2393,14 @@ function inspectTailwindContent(baseDirInput) {
1828
2393
  configFile,
1829
2394
  unreadable: read === void 0,
1830
2395
  dynamic: read?.dynamic ?? false,
1831
- targets: targets.map(({ alternates = [], others = [], ...t }) => {
2396
+ targets: targets.map(({ alternates = [], others = [], pnp, ...t }) => {
1832
2397
  const covers = (sample) => globs.some((g) => contentGlobCovers(g, sample, baseDir));
1833
- 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);
1834
2401
  const note = covered ? void 0 : others.find((o) => covers(o.sample))?.note;
1835
- 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) } };
1836
2404
  })
1837
2405
  };
1838
2406
  }
@@ -1847,19 +2415,30 @@ function checkTailwindContent(baseDir) {
1847
2415
  message: `${r.configFile}\uC758 content \uAC00 ${r.targets.map((t) => t.label).join(" \xB7 ")} \uB97C \uB36E\uC2B5\uB2C8\uB2E4`
1848
2416
  };
1849
2417
  }
1850
- 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 ");
1851
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})`;
1852
2422
  if (r.unreadable || r.dynamic) {
1853
2423
  return {
1854
2424
  name: "tailwind.content",
1855
2425
  severity: "warn",
1856
- 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}`
1857
2436
  };
1858
2437
  }
1859
2438
  return {
1860
2439
  name: "tailwind.content",
1861
2440
  severity: "fail",
1862
- 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}`
1863
2442
  };
1864
2443
  }
1865
2444
  var ANIMATION_PLUGIN_TAILWIND3 = "tailwindcss-animate";
@@ -1876,7 +2455,7 @@ function componentsUseAnimation(baseDir, componentsDir) {
1876
2455
  const [dir, depth] = stack.pop();
1877
2456
  let names;
1878
2457
  try {
1879
- names = readdirSync(dir);
2458
+ names = readdirSync2(dir);
1880
2459
  } catch {
1881
2460
  continue;
1882
2461
  }
@@ -1908,30 +2487,62 @@ function checkAnimationPlugin(baseDirInput) {
1908
2487
  if (!declared && !copied) return null;
1909
2488
  const by = declared ? "@axis-ds/ui-react \uC120\uC5B8" : "componentsDir \uC758 animate-in \uB958 \uD074\uB798\uC2A4";
1910
2489
  const tailwind = detectTailwind(baseDir, pkg);
2490
+ const pnp = isPnpProject(baseDir);
2491
+ const pluginProblem = (name) => {
2492
+ if (declaredRangeForCheck(baseDir, pkg, name) === void 0) {
2493
+ return pnpRootOnlyDependency(baseDir, pkg, name) !== void 0 ? `${name} \uAC00 ${PNP_ROOT_ONLY_NOTE}` : `${name} \uC120\uC5B8 \uC5C6\uC74C`;
2494
+ }
2495
+ if (!pnp && findInstalledPackage(baseDir, name) === void 0) return `${name} \uBBF8\uC124\uCE58(\uC120\uC5B8\uB9CC \uC788\uC74C)`;
2496
+ return void 0;
2497
+ };
1911
2498
  if (tailwind.major !== void 0 && tailwind.major >= 4) {
1912
- const file = TAILWIND_CSS_CANDIDATES.find((c) => existsSync3(join2(baseDir, c)));
1913
- const css = file !== void 0 ? stripCssComments(readFileSync4(join2(baseDir, file), "utf8")) : "";
1914
- const ok = new RegExp(`@import\\s+(?:url\\(\\s*)?["']${ANIMATION_PLUGIN_TAILWIND4}["']`).test(css) || new RegExp(`@plugin\\s+["']${ANIMATION_PLUGIN_TAILWIND3}["']`).test(css);
1915
- return ok ? { name: "animation", severity: "pass", message: `${file}\uC5D0 \uC560\uB2C8\uBA54\uC774\uC158 \uD50C\uB7EC\uADF8\uC778\uC774 \uC788\uC2B5\uB2C8\uB2E4` } : {
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}["']`);
2506
+ const lines = [];
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))])) : "";
2510
+ if (lines.length === 0) {
2511
+ return {
2512
+ name: "animation",
2513
+ severity: "warn",
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}`
2515
+ };
2516
+ }
2517
+ const problems = lines.map((name) => ({ name, why: pluginProblem(name) })).filter((x) => x.why !== void 0);
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}` };
2519
+ return {
1916
2520
  name: "animation",
1917
2521
  severity: "warn",
1918
- 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}";`
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}`
1919
2523
  };
1920
2524
  }
1921
2525
  const configFile = TAILWIND_CONFIG_FILES.find((f) => existsSync3(join2(baseDir, f)));
1922
2526
  const source = configFile !== void 0 ? stripJsComments(readFileSync4(join2(baseDir, configFile), "utf8")) : "";
1923
2527
  const plugins = configFile !== void 0 ? readAnimationPluginUse(source) : "absent";
1924
- const pluginDeclared = declaredRange(baseDir, pkg, ANIMATION_PLUGIN_TAILWIND3) !== void 0;
1925
- const pluginInstalled = pluginDeclared && (isPnpProject(baseDir) || findInstalledPackage(baseDir, ANIMATION_PLUGIN_TAILWIND3) !== void 0);
1926
- if (plugins === "found" && pluginDeclared && pluginInstalled) {
2528
+ const pluginReason = pluginProblem(ANIMATION_PLUGIN_TAILWIND3);
2529
+ if (plugins === "found" && pluginReason === void 0) {
1927
2530
  return { name: "animation", severity: "pass", message: `${configFile}\uC758 plugins \uC5D0 ${ANIMATION_PLUGIN_TAILWIND3} \uAC00 \uC788\uC2B5\uB2C8\uB2E4` };
1928
2531
  }
1929
2532
  const cfg = configFile ?? "tailwind.config";
2533
+ const configReason = plugins === "dynamic" ? `${cfg} plugins \uB97C \uC815\uC801\uC73C\uB85C \uB2E4 \uC77D\uC9C0 \uBABB\uD574 \uD655\uC778\uD558\uC9C0 \uBABB\uD568` : plugins !== "found" ? `${cfg} plugins \uC5D0 \uC5C6\uC74C` : void 0;
2534
+ if (pluginReason !== void 0 && pnpRootOnlyDependency(baseDir, pkg, ANIMATION_PLUGIN_TAILWIND3) !== void 0) {
2535
+ const extra = configReason !== void 0 ? `, ${configReason}` : "";
2536
+ const plug = configReason !== void 0 ? ` \xB7 plugins \uC5D0 require("${ANIMATION_PLUGIN_TAILWIND3}")` : "";
2537
+ return {
2538
+ name: "animation",
2539
+ severity: "warn",
2540
+ message: `\uC560\uB2C8\uBA54\uC774\uC158 \uD50C\uB7EC\uADF8\uC778 ${ANIMATION_PLUGIN_TAILWIND3} \uAC00 ${PNP_ROOT_ONLY_NOTE}(${by}${extra}): Dialog \xB7 Select \uB4F1\uC758 \uC5F4\uACE0 \uB2EB\uB294 \uC560\uB2C8\uBA54\uC774\uC158\uC774 \uB3D9\uC791\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4 \u2192 \uC571 package.json \uC5D0 ${ANIMATION_PLUGIN_TAILWIND3} \uB97C \uC120\uC5B8\uD558\uC138\uC694${plug}`
2541
+ };
2542
+ }
1930
2543
  const reasons = [];
1931
- if (!pluginDeclared) reasons.push(`${ANIMATION_PLUGIN_TAILWIND3} \uC120\uC5B8 \uC5C6\uC74C`);
1932
- else if (!pluginInstalled) reasons.push(`${ANIMATION_PLUGIN_TAILWIND3} \uBBF8\uC124\uCE58(\uC120\uC5B8\uB9CC \uC788\uC74C)`);
1933
- if (plugins === "dynamic") reasons.push(`${cfg} plugins \uB97C \uC815\uC801\uC73C\uB85C \uB2E4 \uC77D\uC9C0 \uBABB\uD574 \uD655\uC778\uD558\uC9C0 \uBABB\uD568`);
1934
- else if (plugins !== "found") reasons.push(`${cfg} plugins \uC5D0 \uC5C6\uC74C`);
2544
+ if (pluginReason !== void 0) reasons.push(pluginReason);
2545
+ if (configReason !== void 0) reasons.push(configReason);
1935
2546
  return {
1936
2547
  name: "animation",
1937
2548
  severity: "warn",
@@ -2013,7 +2624,7 @@ function selectUtilsDependencies(tailwind) {
2013
2624
  }
2014
2625
 
2015
2626
  // ../axis-registry-core/src/add/safe-write.ts
2016
- 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";
2017
2628
  import path4 from "path";
2018
2629
  import fs2 from "fs-extra";
2019
2630
  var NEW_FILE_FLAGS = fsConstants.O_WRONLY | fsConstants.O_CREAT | fsConstants.O_EXCL | (fsConstants.O_NOFOLLOW ?? 0);
@@ -2069,7 +2680,7 @@ function escapeReason(root, target, options = {}) {
2069
2680
  }
2070
2681
  let followed;
2071
2682
  try {
2072
- followed = statSync2(realTarget);
2683
+ followed = statSync3(realTarget);
2073
2684
  } catch {
2074
2685
  return `\uAE30\uC874 \uD30C\uC77C \uC815\uBCF4\uB97C \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4(${target})`;
2075
2686
  }
@@ -2341,7 +2952,7 @@ function relativeSpecifierResolves(fromFile, spec) {
2341
2952
  const base = path5.resolve(path5.dirname(fromFile), spec);
2342
2953
  return RESOLVE_EXTS.some((ext) => {
2343
2954
  try {
2344
- return statSync3(base + ext).isFile();
2955
+ return statSync4(base + ext).isFile();
2345
2956
  } catch {
2346
2957
  return false;
2347
2958
  }
@@ -3124,7 +3735,7 @@ function formatTokenList(result) {
3124
3735
  }
3125
3736
 
3126
3737
  // src/tools/install.ts
3127
- import { statSync as statSync4 } from "fs";
3738
+ import { statSync as statSync5 } from "fs";
3128
3739
  import path6 from "path";
3129
3740
  var DEFAULT_LAYOUT_CONFIG = { componentsDir: "components/ui" };
3130
3741
  var MCP_ADD_HINTS = {
@@ -3163,7 +3774,7 @@ async function handleInstallComponent(params, deps = {}) {
3163
3774
  const root = path6.resolve(params.targetDir);
3164
3775
  let isDir = false;
3165
3776
  try {
3166
- isDir = statSync4(root).isDirectory();
3777
+ isDir = statSync5(root).isDirectory();
3167
3778
  } catch {
3168
3779
  isDir = false;
3169
3780
  }
@@ -4668,7 +5279,7 @@ import fs6 from "fs-extra";
4668
5279
  import path9 from "path";
4669
5280
 
4670
5281
  // src/tools/brand-core.ts
4671
- 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";
4672
5283
  import { createRequire } from "module";
4673
5284
  import { dirname as dirname4, join as join4, relative as relative2, resolve as resolve3, sep as sep2 } from "path";
4674
5285
  var TOKENS_PACKAGE = "@axis-ds/tokens";
@@ -4731,29 +5342,11 @@ function brandImportPath(entry) {
4731
5342
  }
4732
5343
  function isFile2(file) {
4733
5344
  try {
4734
- return statSync5(file).isFile();
5345
+ return statSync6(file).isFile();
4735
5346
  } catch {
4736
5347
  return false;
4737
5348
  }
4738
5349
  }
4739
- function findGlobalCss(baseDir, config) {
4740
- const root = resolve3(baseDir);
4741
- const result = {};
4742
- const configured = config?.globalCss;
4743
- if (typeof configured === "string" && configured.trim() !== "") {
4744
- const file = resolve3(root, configured);
4745
- if (isFile2(file)) return { path: file };
4746
- result.configuredMissing = configured;
4747
- }
4748
- for (const candidate of GLOBAL_CSS_CANDIDATES) {
4749
- const file = join4(root, candidate);
4750
- if (isFile2(file)) {
4751
- result.path = file;
4752
- break;
4753
- }
4754
- }
4755
- return result;
4756
- }
4757
5350
  function findBrandImports(css) {
4758
5351
  const names = [];
4759
5352
  const pattern = /@import\s+(?:url\(\s*)?["']?@axis-ds\/tokens\/css\/brands\/([a-z][a-z0-9-]*)(?:\.css)?["']?\s*\)?\s*(?=[;\s]|$)/g;
@@ -4778,18 +5371,24 @@ function inspectBrandImport(baseDir) {
4778
5371
  const brand = config?.brand;
4779
5372
  if (typeof brand !== "string" || brand.trim() === "") return null;
4780
5373
  const root = resolve3(baseDir);
4781
- const location = findGlobalCss(root, config);
5374
+ const location = selectGlobalCss(root, config?.globalCss, GLOBAL_CSS_CANDIDATES, { requireStylesheet: true });
4782
5375
  const base = { brand };
4783
5376
  if (location.configuredMissing !== void 0) base.configuredMissing = location.configuredMissing;
5377
+ if (location.configuredRejected !== void 0) base.configuredRejected = location.configuredRejected;
4784
5378
  if (!location.path) {
4785
5379
  return { ...base, state: "css-missing", imports: [] };
4786
5380
  }
4787
5381
  const cssFile = relative2(root, location.path).split(sep2).join("/");
4788
- 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))];
4789
5384
  let state;
4790
5385
  if (imports.includes(brand)) state = "match";
4791
5386
  else if (imports.length === 0) state = "import-missing";
4792
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) };
4793
5392
  return { ...base, state, cssFile, imports };
4794
5393
  }
4795
5394
  function isMissingBuildFile(err) {
@@ -4924,7 +5523,11 @@ function inspectBrandActivation(baseDir) {
4924
5523
  if (typeof brand !== "string" || brand.trim() === "") return null;
4925
5524
  const location = findBrandActivation(baseDir);
4926
5525
  if (!location.markupWithProvider) return { brand, ...location };
4927
- return { brand, ...location, theme: packageVersionGate(baseDir, readProjectPackageJson(baseDir), THEME_PACKAGE, THEME_MARKUP_BRAND_MIN_VERSION) };
5526
+ return {
5527
+ brand,
5528
+ ...location,
5529
+ theme: packageVersionGate(baseDir, readProjectPackageJson(baseDir), THEME_PACKAGE, THEME_MARKUP_BRAND_MIN_VERSION, { appOnlyInPnp: true })
5530
+ };
4928
5531
  }
4929
5532
  var THEME_PACKAGE = "@axis-ds/theme";
4930
5533
  function readProjectPackageJson(baseDir) {
@@ -4997,25 +5600,43 @@ function checkDependencies(baseDirInput) {
4997
5600
  return { name: "dependencies", severity: "fail", message: "package.json \uC744 \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4(JSON \uD655\uC778)" };
4998
5601
  }
4999
5602
  const rootPkg = workspaceRootPackage(baseDir) ?? null;
5000
- const declared = (d) => declaredDependency(baseDir, pkg, d, rootPkg);
5603
+ const pnp = isPnpProject(baseDir);
5604
+ const declared = (d) => declaredDependency(baseDir, pkg, d, rootPkg, { appOnlyInPnp: true });
5605
+ const pnpRootOnly = (d) => pnpRootOnlyDependency(baseDir, pkg, d, rootPkg) !== void 0;
5001
5606
  const fromRoot = (d) => declared(d)?.source === "root";
5002
- const missingRequired = REQUIRED_DEPENDENCIES.filter((d) => declared(d) === void 0);
5003
- if (missingRequired.length > 0) {
5004
- return { name: "dependencies", severity: "fail", message: `\uD544\uC218 \uC758\uC874\uC131 \uB204\uB77D: ${missingRequired.join(", ")}` };
5005
- }
5006
- const missingRecommended = RECOMMENDED_DEPENDENCIES.filter((d) => declared(d) === void 0);
5007
- const rootDeclared = [...REQUIRED_DEPENDENCIES, ...RECOMMENDED_DEPENDENCIES].filter((d) => fromRoot(d));
5607
+ const missingRequired = REQUIRED_DEPENDENCIES.filter((d) => declared(d) === void 0 && !pnpRootOnly(d));
5608
+ const pnpRootRequired = REQUIRED_DEPENDENCIES.filter((d) => pnpRootOnly(d));
5609
+ if (missingRequired.length > 0 || pnpRootRequired.length > 0) {
5610
+ const fails = [];
5611
+ if (missingRequired.length > 0) fails.push(`\uD544\uC218 \uC758\uC874\uC131 \uB204\uB77D: ${missingRequired.join(", ")}`);
5612
+ if (pnpRootRequired.length > 0) fails.push(`\uD544\uC218 \uC758\uC874\uC131 ${pnpRootRequired.join(", ")} \uAC00 ${PNP_ROOT_ONLY_NOTE} \u2192 \uC571 package.json \uC5D0 \uC120\uC5B8\uD558\uC138\uC694`);
5613
+ return { name: "dependencies", severity: "fail", message: fails.join(" / ") };
5614
+ }
5615
+ const missingRecommended = RECOMMENDED_DEPENDENCIES.filter((d) => declared(d) === void 0 && !pnpRootOnly(d));
5616
+ const pnpRootRecommended = RECOMMENDED_DEPENDENCIES.filter((d) => pnpRootOnly(d));
5617
+ const appAxis = declaredAxisPackages(pkg);
5618
+ const rootOnlyAxis = rootPkg !== null ? declaredAxisPackages(rootPkg).filter((d) => !appAxis.includes(d)) : [];
5619
+ const rootAxis = pnp ? [] : rootOnlyAxis;
5620
+ const pnpRootAxis = pnp ? rootOnlyAxis : [];
5621
+ const rootDeclared = [...[...REQUIRED_DEPENDENCIES, ...RECOMMENDED_DEPENDENCIES].filter((d) => fromRoot(d)), ...rootAxis];
5008
5622
  const rootNote = rootDeclared.length > 0 ? `\uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uB8E8\uD2B8\uC5D0 \uC120\uC5B8: ${rootDeclared.join(", ")}` : void 0;
5009
5623
  const targets = [
5010
5624
  ...[...REQUIRED_DEPENDENCIES, ...RECOMMENDED_DEPENDENCIES].filter((d) => declared(d) !== void 0),
5011
- ...declaredAxisPackages(pkg)
5625
+ ...appAxis,
5626
+ ...rootAxis
5012
5627
  ];
5013
- const pnp = isPnpProject(baseDir);
5014
5628
  const notInstalled = pnp ? [] : targets.filter((d) => findInstalledPackage(baseDir, d) === void 0);
5629
+ const notInstalledRoot = notInstalled.filter((d) => rootAxis.includes(d));
5630
+ const notInstalledOther = notInstalled.filter((d) => !rootAxis.includes(d));
5015
5631
  const problems = [];
5016
5632
  if (missingRecommended.length > 0) problems.push(`\uAD8C\uC7A5 \uC758\uC874\uC131 \uB204\uB77D: ${missingRecommended.join(", ")}`);
5017
- if (notInstalled.length > 0) {
5018
- problems.push(`\uC120\uC5B8\uB410\uC9C0\uB9CC \uC124\uCE58\uB418\uC9C0 \uC54A\uC740 \uC758\uC874\uC131: ${notInstalled.join(", ")} \u2192 ${detectInstallCommand(baseDir)}`);
5633
+ if (pnpRootRecommended.length > 0) problems.push(`\uAD8C\uC7A5 \uC758\uC874\uC131 ${pnpRootRecommended.join(", ")} \uAC00 ${PNP_ROOT_ONLY_NOTE} \u2192 \uC571 package.json \uC5D0 \uC120\uC5B8\uD558\uC138\uC694`);
5634
+ if (pnpRootAxis.length > 0) problems.push(`${pnpRootAxis.join(", ")} \uAC00 ${PNP_ROOT_ONLY_NOTE} \u2192 \uC571 package.json \uC5D0 \uC120\uC5B8\uD558\uC138\uC694`);
5635
+ if (notInstalledOther.length > 0) {
5636
+ problems.push(`\uC120\uC5B8\uB410\uC9C0\uB9CC \uC124\uCE58\uB418\uC9C0 \uC54A\uC740 \uC758\uC874\uC131: ${notInstalledOther.join(", ")} \u2192 ${detectInstallCommand(baseDir)}`);
5637
+ }
5638
+ if (notInstalledRoot.length > 0) {
5639
+ problems.push(`\uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uB8E8\uD2B8\uC5D0 \uC120\uC5B8\uB3FC \uC788\uC9C0\uB9CC \uC124\uCE58\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4: ${notInstalledRoot.join(", ")} \u2192 ${detectInstallCommand(baseDir)}`);
5019
5640
  }
5020
5641
  if (problems.length > 0) {
5021
5642
  return { name: "dependencies", severity: "warn", message: problems.join(" / ") + (rootNote ? ` (${rootNote})` : "") };
@@ -5156,13 +5777,14 @@ async function handleDiffTemplate(params) {
5156
5777
  }
5157
5778
  function brandCheckResult(check) {
5158
5779
  const { brand } = check;
5159
- const suffix = check.configuredMissing !== void 0 ? ` (globalCss ${check.configuredMissing} \uC5C6\uC74C)` : "";
5780
+ const suffix = globalCssSelectionNote(check);
5781
+ const via = cssImportViaNote(check.importVia);
5160
5782
  switch (check.state) {
5161
5783
  case "match":
5162
5784
  return {
5163
5785
  name: "brand",
5164
5786
  severity: "pass",
5165
- 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}`
5166
5788
  };
5167
5789
  case "css-missing":
5168
5790
  return {
@@ -5180,11 +5802,18 @@ function brandCheckResult(check) {
5180
5802
  return {
5181
5803
  name: "brand",
5182
5804
  severity: "warn",
5183
- 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}`
5184
5806
  };
5185
5807
  }
5186
5808
  }
5187
5809
  function brandActivationResult(check) {
5810
+ if (check.found && check.theme?.status === "unresolved") {
5811
+ return {
5812
+ name: "brand.activation",
5813
+ severity: "warn",
5814
+ message: `${check.found}\uC758 <html data-brand> \uB97C ThemeProvider \uC640 \uD568\uAED8 \uC4F0\uB294\uB370 @axis-ds/theme \uAC00 ${PNP_ROOT_ONLY_NOTE}(${versionGateLabel(check.theme)}) \u2192 \uC571 package.json \uC5D0 @axis-ds/theme ${THEME_MARKUP_BRAND_MIN_VERSION} \uC774\uC0C1\uC744 \uC120\uC5B8\uD558\uAC70\uB098 setBrand("${check.brand}")`
5815
+ };
5816
+ }
5188
5817
  if (check.found && check.theme && check.theme.status !== "ok") {
5189
5818
  const label = versionGateLabel(check.theme);
5190
5819
  const why = check.theme.status === "below" ? `@axis-ds/theme ${label} \uC758 ThemeProvider \uAC00 \uB9C8\uC6B4\uD2B8 \uB54C \uC9C0\uC6C1\uB2C8\uB2E4` : `@axis-ds/theme \uBC84\uC804\uC744 \uD655\uC778\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4(${label}). ${THEME_MARKUP_BRAND_MIN_VERSION} \uBBF8\uB9CC\uC774\uBA74 ThemeProvider \uAC00 \uB9C8\uC6B4\uD2B8 \uB54C \uC9C0\uC6C1\uB2C8\uB2E4`;
@@ -5378,10 +6007,8 @@ var TOKENS_INSTALL_COMMAND = addCommandFor("pnpm install", { [TOKENS_PACKAGE]: `
5378
6007
  function baseDirOf(targetDir) {
5379
6008
  return path10.resolve(targetDir || process.cwd());
5380
6009
  }
5381
- function tokensInstallCommandFor(targetDir) {
5382
- return addCommandFor(detectInstallCommand(baseDirOf(targetDir)), {
5383
- [TOKENS_PACKAGE]: `^${TOKENS_DEPENDENCY_MIN_VERSION}`
5384
- });
6010
+ function tokensInstallGuideFor(targetDir) {
6011
+ return dependencyInstallGuide(baseDirOf(targetDir), TOKENS_PACKAGE, `^${TOKENS_DEPENDENCY_MIN_VERSION}`);
5385
6012
  }
5386
6013
  async function handleListBrands(params) {
5387
6014
  return listBrands(baseDirOf(params.targetDir));
@@ -5394,24 +6021,25 @@ async function handleGetBrand(params) {
5394
6021
  return getBrand(baseDirOf(params.targetDir), name);
5395
6022
  }
5396
6023
  function formatTokensStatusGuide(status, version, installCommand = TOKENS_INSTALL_COMMAND) {
6024
+ const g = typeof installCommand === "string" ? { kind: "add", installCommand, addCommand: installCommand } : installCommand;
6025
+ if (g.kind === "pnp") {
6026
+ return `${TOKENS_PACKAGE}${g.range ? ` ${g.range}` : ""} \uAC00 package.json \uC5D0 \uC120\uC5B8\uB3FC \uC788\uC9C0\uB9CC Plug'n'Play \uC124\uCE58\uB77C \uC124\uCE58\uBCF8\uC744 \uD310\uC815\uD558\uC9C0 \uBABB\uD574 \uBE0C\uB79C\uB4DC\uB97C \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.`;
6027
+ }
6028
+ const install = g.kind === "install-at-root" ? `\uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uB8E8\uD2B8\uC5D0\uC11C \`${g.installCommand}\`` : `\`${g.kind === "install" ? g.installCommand : g.addCommand}\``;
5397
6029
  switch (status) {
5398
6030
  case "not-installed":
5399
- return [
5400
- `${TOKENS_PACKAGE} \uAC00 \uC124\uCE58\uB3FC \uC788\uC9C0 \uC54A\uC544 \uBE0C\uB79C\uB4DC\uB97C \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.`,
5401
- "",
5402
- `- \uC124\uCE58: \`${installCommand}\``
5403
- ].join("\n");
6031
+ return [`${TOKENS_PACKAGE} \uAC00 \uC124\uCE58\uB3FC \uC788\uC9C0 \uC54A\uC544 \uBE0C\uB79C\uB4DC\uB97C \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.`, "", `- \uC124\uCE58: ${install}`].join("\n");
5404
6032
  case "unsupported":
5405
6033
  return [
5406
6034
  `${TOKENS_PACKAGE} ${version ?? "(\uBC84\uC804 \uBAA8\uB984)"} \uC740 \uBE0C\uB79C\uB4DC\uB97C \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4(${MIN_BRAND_TOKENS_VERSION} \uC774\uC0C1 \uD544\uC694).`,
5407
6035
  "",
5408
- `- \uC5C5\uADF8\uB808\uC774\uB4DC: \`${installCommand}\``
6036
+ g.source === "root" ? `- \uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uB8E8\uD2B8 package.json \uC758 ${TOKENS_PACKAGE} \uC120\uC5B8\uC744 ^${MIN_BRAND_TOKENS_VERSION} \uC774\uC0C1\uC73C\uB85C \uC62C\uB9AC\uACE0 \uC124\uCE58\uD558\uC138\uC694.` : `- \uC5C5\uADF8\uB808\uC774\uB4DC: \`${g.addCommand}\``
5409
6037
  ].join("\n");
5410
6038
  case "not-built":
5411
6039
  return [
5412
6040
  `${TOKENS_PACKAGE}${version ? ` ${version}` : ""} \uB294 \uC788\uC9C0\uB9CC \uBE4C\uB4DC \uC0B0\uCD9C\uBB3C\uC774 \uC5C6\uC5B4 \uBE0C\uB79C\uB4DC\uB97C \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.`,
5413
6041
  "",
5414
- `- \uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4\uBA74 \`${workspaceRunCommand(installCommand, TOKENS_PACKAGE, "build")}\`, \uC544\uB2C8\uBA74 \uC7AC\uC124\uCE58: \`${installCommand}\``
6042
+ `- \uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4\uBA74 \`${workspaceRunCommand(g.installCommand, TOKENS_PACKAGE, "build")}\`, \uC544\uB2C8\uBA74 \uC7AC\uC124\uCE58: ${install}`
5415
6043
  ].join("\n");
5416
6044
  }
5417
6045
  }
@@ -6069,7 +6697,7 @@ server.tool(
6069
6697
  async ({ targetDir }) => {
6070
6698
  try {
6071
6699
  const result = await handleListBrands({ targetDir });
6072
- const formatted = formatListBrandsResult(result, tokensInstallCommandFor(targetDir));
6700
+ const formatted = formatListBrandsResult(result, tokensInstallGuideFor(targetDir));
6073
6701
  return {
6074
6702
  content: [
6075
6703
  {
@@ -6102,7 +6730,7 @@ server.tool(
6102
6730
  async ({ name, targetDir }) => {
6103
6731
  try {
6104
6732
  const result = await handleGetBrand({ name, targetDir });
6105
- const formatted = formatGetBrandResult(result, name, tokensInstallCommandFor(targetDir));
6733
+ const formatted = formatGetBrandResult(result, name, tokensInstallGuideFor(targetDir));
6106
6734
  return {
6107
6735
  content: [
6108
6736
  {