@axis-ds/cli 1.7.6 → 1.7.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -4,25 +4,37 @@ import {
4
4
  MonetClient,
5
5
  PNP_ROOT_ONLY_NOTE,
6
6
  ROOT_LAYOUT_FILES,
7
+ TAILWIND4_MIN_AXIS_VERSION,
7
8
  addCommandFor,
8
9
  addCommandPrefix,
9
10
  compareExactVersions,
11
+ componentCssResolution,
12
+ componentCssResolvable,
13
+ cssImportViaNote,
14
+ cssPackageLineResolution,
10
15
  declaredDependency,
16
+ deferredComponentImportReason,
11
17
  dependencyInstallGuide,
12
18
  detectInstallCommand,
13
19
  detectProjectPaths,
14
20
  findInstalledPackage,
21
+ findPnpUnpluggedPackages,
22
+ globalCssSelectionNote,
15
23
  hasDependency,
16
24
  isPlainObject,
17
25
  isPnpProject,
26
+ outsideCssPackageResolution,
27
+ pnpProjectRoot,
18
28
  pnpRootOnlyDependency,
19
29
  projectFileExists,
20
30
  resolveBaseDir,
21
31
  rootDeclarationsAllowed,
22
32
  runScriptCommand,
33
+ selectGlobalCss,
34
+ tokensCssResolution,
23
35
  workspaceRootPackage,
24
36
  workspaceRunCommand
25
- } from "./chunk-I3HWV7Y5.js";
37
+ } from "./chunk-C2T7NVDG.js";
26
38
  import {
27
39
  V0Client
28
40
  } from "./chunk-2PNCUPCG.js";
@@ -1928,7 +1940,7 @@ async function readAxisConfig(baseDir) {
1928
1940
  }
1929
1941
 
1930
1942
  // ../axis-registry-core/src/template/tailwind-core.ts
1931
- import { existsSync, lstatSync, readdirSync, readFileSync, realpathSync } from "fs";
1943
+ import { existsSync, lstatSync, readdirSync, readFileSync, realpathSync, statSync } from "fs";
1932
1944
  import { basename, dirname, extname, isAbsolute, join, relative, resolve, sep } from "path";
1933
1945
  function declaredRange(baseDir, pkg, name) {
1934
1946
  return declaredDependency(baseDir, pkg, name)?.range;
@@ -2059,6 +2071,157 @@ var TOKENS_CSS_IMPORT = /@import\s+(?:url\(\s*)?["'](@axis-ds\/tokens\/css(?:\/s
2059
2071
  function findTokensCssImport(css) {
2060
2072
  return TOKENS_CSS_IMPORT.exec(stripCssComments(css))?.[1];
2061
2073
  }
2074
+ var CSS_IMPORT_DEPTH_LIMIT = 32;
2075
+ var CSS_IMPORT_CYCLE_DEPTH_LIMIT = 100;
2076
+ var RELATIVE_CSS_IMPORT = /@import\s*(?:"(\.{1,2}\/[^"\n]*)"|'(\.{1,2}\/[^'\n]*)')(?=([^;{}]*))/g;
2077
+ function isConditionalCssImport(tail) {
2078
+ return tail !== void 0 && tail.trim() !== "";
2079
+ }
2080
+ function resolveRelativeCssImport(fromDir, spec) {
2081
+ if (spec.endsWith("/")) return void 0;
2082
+ const target = resolve(fromDir, spec);
2083
+ if (regularFile(target)) return target;
2084
+ if (regularFile(`${target}.css`)) return `${target}.css`;
2085
+ return void 0;
2086
+ }
2087
+ var CSS_IMPORT_SPEC = /@import\s+(?:url\(\s*)?(["'])([^"'\n]+)\1/g;
2088
+ function isPackageCssSpec(spec) {
2089
+ return !spec.startsWith("./") && !spec.startsWith("../") && !spec.startsWith("/") && !/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(spec);
2090
+ }
2091
+ function cssImportCycleIssue(files) {
2092
+ 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`;
2093
+ 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`;
2094
+ }
2095
+ function findImportCycle(start, edges) {
2096
+ const state = /* @__PURE__ */ new Map();
2097
+ const trail = [start];
2098
+ const stack = [{ node: start, next: 0 }];
2099
+ state.set(start, "open");
2100
+ while (stack.length > 0) {
2101
+ const top = stack[stack.length - 1];
2102
+ const out = edges.get(top.node) ?? [];
2103
+ if (top.next >= out.length) {
2104
+ state.set(top.node, "done");
2105
+ stack.pop();
2106
+ trail.pop();
2107
+ continue;
2108
+ }
2109
+ const to = out[top.next++];
2110
+ const s = state.get(to);
2111
+ if (s === "open") return trail.slice(trail.indexOf(to));
2112
+ if (s === "done") continue;
2113
+ state.set(to, "open");
2114
+ trail.push(to);
2115
+ stack.push({ node: to, next: 0 });
2116
+ }
2117
+ return void 0;
2118
+ }
2119
+ function regularFile(file) {
2120
+ try {
2121
+ return statSync(file).isFile();
2122
+ } catch {
2123
+ return false;
2124
+ }
2125
+ }
2126
+ function expandGlobalCss(baseDirInput, entryPath, entryRel, entryCssDir) {
2127
+ const baseDir = resolveBaseDir(baseDirInput);
2128
+ const entry = readFileSync(entryPath, "utf8");
2129
+ let entryReal = entryPath;
2130
+ try {
2131
+ entryReal = realpathSync(entryPath);
2132
+ } catch {
2133
+ }
2134
+ const raws = /* @__PURE__ */ new Map([[entryReal, entry]]);
2135
+ const files = [];
2136
+ const packageLines = [];
2137
+ const evidenceWalk = walkRelativeCssImports(baseDir, entryReal, raws, CSS_IMPORT_DEPTH_LIMIT, false);
2138
+ const relOfReal = /* @__PURE__ */ new Map([[entryReal, entryRel]]);
2139
+ for (const node of evidenceWalk.order) {
2140
+ const isEntry = node.real === entryReal;
2141
+ const rel3 = isEntry ? entryRel : node.rel;
2142
+ const css = stripCssComments(raws.get(node.real) ?? "");
2143
+ const file = { rel: rel3, path: node.real, css, depth: node.depth };
2144
+ const cssDir = isEntry ? entryCssDir : dirname(node.real);
2145
+ if (cssDir !== void 0) file.cssDir = cssDir;
2146
+ files.push(file);
2147
+ relOfReal.set(node.real, rel3);
2148
+ for (const m of css.matchAll(CSS_IMPORT_SPEC)) {
2149
+ if (!isPackageCssSpec(m[2])) continue;
2150
+ const line = { spec: m[2], file: rel3 };
2151
+ if (cssDir !== void 0) line.cssDir = cssDir;
2152
+ packageLines.push(line);
2153
+ }
2154
+ }
2155
+ const cycleWalk = walkRelativeCssImports(baseDir, entryReal, raws, CSS_IMPORT_CYCLE_DEPTH_LIMIT, true);
2156
+ const cycle = findImportCycle(entryReal, cycleWalk.edges);
2157
+ if (cycle !== void 0) {
2158
+ for (const node of cycleWalk.order) if (!relOfReal.has(node.real)) relOfReal.set(node.real, node.rel);
2159
+ const head = files[0];
2160
+ return {
2161
+ entry,
2162
+ evidence: entry,
2163
+ files: [head],
2164
+ packageLines: packageLines.filter((l) => l.file === head.rel),
2165
+ cycle: cycle.map((p) => relOfReal.get(p) ?? p)
2166
+ };
2167
+ }
2168
+ const evidence = files.length === 1 ? entry : files.map((f) => f.css).join("\n");
2169
+ return { entry, evidence, files, packageLines };
2170
+ }
2171
+ function walkRelativeCssImports(baseDir, entryReal, raws, limit, includeConditional) {
2172
+ const order = [];
2173
+ const edges = /* @__PURE__ */ new Map();
2174
+ const visited = /* @__PURE__ */ new Set([entryReal]);
2175
+ const queue = [{ real: entryReal, rel: "", depth: 0 }];
2176
+ while (queue.length > 0) {
2177
+ const cur = queue.shift();
2178
+ order.push(cur);
2179
+ const css = stripCssComments(raws.get(cur.real) ?? "");
2180
+ const out = [];
2181
+ edges.set(cur.real, out);
2182
+ for (const m of css.matchAll(RELATIVE_CSS_IMPORT)) {
2183
+ if (!includeConditional && isConditionalCssImport(m[3])) continue;
2184
+ const target = resolveRelativeCssImport(dirname(cur.real), m[1] ?? m[2]);
2185
+ if (target === void 0) continue;
2186
+ let real;
2187
+ try {
2188
+ real = realpathSync(target);
2189
+ } catch {
2190
+ continue;
2191
+ }
2192
+ if (visited.has(real)) {
2193
+ out.push(real);
2194
+ continue;
2195
+ }
2196
+ if (cur.depth >= limit) continue;
2197
+ const rel3 = relative(baseDir, real);
2198
+ if (rel3 === "" || rel3 === ".." || rel3.startsWith(`..${sep}`) || isAbsolute(rel3)) continue;
2199
+ if (!raws.has(real)) {
2200
+ try {
2201
+ raws.set(real, readFileSync(real, "utf8"));
2202
+ } catch {
2203
+ continue;
2204
+ }
2205
+ }
2206
+ visited.add(real);
2207
+ out.push(real);
2208
+ queue.push({ real, rel: rel3.split(sep).join("/"), depth: cur.depth + 1 });
2209
+ }
2210
+ }
2211
+ return { order, edges };
2212
+ }
2213
+ function evidenceOrigin(expanded, test) {
2214
+ return expanded.files.find((f) => test(f.css));
2215
+ }
2216
+ function packageLineCssDir(expanded, spec) {
2217
+ const line = expanded.packageLines.find((l) => l.spec === spec);
2218
+ return line !== void 0 ? line.cssDir : expanded.files[0]?.cssDir;
2219
+ }
2220
+ function viaFiles(origins) {
2221
+ const out = [];
2222
+ for (const o of origins) if (o !== void 0 && o.depth > 0 && !out.includes(o.rel)) out.push(o.rel);
2223
+ return out;
2224
+ }
2062
2225
  var TOKENS_CSS_JS_IMPORT = /(?:\bimport\s+|\bfrom\s+|\brequire\s*\(\s*)(["'])(@axis-ds\/tokens\/css(?:\/shadcn|\/tailwind4)?)\1/;
2063
2226
  var AXIS_VARIABLE_DEFINITION = /(?<![\w-])--axis-[\w-]+\s*:/;
2064
2227
  function findLayoutTokensCssImport(baseDirInput) {
@@ -2077,45 +2240,133 @@ function findLayoutTokensCssImport(baseDirInput) {
2077
2240
  }
2078
2241
  return void 0;
2079
2242
  }
2243
+ var TOKENS_PACKAGE_NAME = "@axis-ds/tokens";
2244
+ function outsideCssDir(selection) {
2245
+ if (selection.path === void 0 || selection.rel === void 0) return void 0;
2246
+ const outside = selection.rel === ".." || selection.rel.startsWith("../") || isAbsolute(selection.rel);
2247
+ return outside ? dirname(selection.path) : void 0;
2248
+ }
2249
+ function outsideCssUnresolvedIssue(spec, name) {
2250
+ 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`;
2251
+ }
2252
+ function tokensInstallPhrase(baseDir, range = `^${TAILWIND4_MIN_AXIS_VERSION}`) {
2253
+ const g = dependencyInstallGuide(baseDir, TOKENS_PACKAGE_NAME, range);
2254
+ if (g.kind === "install-at-root") return `\uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uB8E8\uD2B8\uC5D0\uC11C ${g.installCommand}`;
2255
+ return g.kind === "install" ? g.installCommand : g.addCommand;
2256
+ }
2257
+ function tokensCssUnresolvedIssue(baseDir, pkg, spec, cssDir, lineIssue) {
2258
+ const r = tokensCssResolution(baseDir, pkg, TOKENS_PACKAGE_NAME);
2259
+ const head = `${spec} import \uAC00 \uC788\uC9C0\uB9CC`;
2260
+ 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`;
2261
+ if (r.kind === "not-installed") {
2262
+ 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)})`;
2263
+ }
2264
+ if (cssDir !== void 0 && outsideCssPackageResolution(baseDir, cssDir, TOKENS_PACKAGE_NAME) === "unresolved") {
2265
+ return outsideCssUnresolvedIssue(spec, TOKENS_PACKAGE_NAME);
2266
+ }
2267
+ return lineIssue?.();
2268
+ }
2269
+ function packageNameOfSpec(spec) {
2270
+ const parts = spec.split("/");
2271
+ return parts.slice(0, spec.startsWith("@") ? 2 : 1).join("/");
2272
+ }
2273
+ function displayRel(baseDir, p) {
2274
+ return relative(baseDir, p).split(sep).join("/");
2275
+ }
2276
+ function packageLineShadowIssue(baseDir, expanded, origin, spec) {
2277
+ const name = packageNameOfSpec(spec);
2278
+ const lineDir = dirname(origin.path);
2279
+ const others = () => [...new Set(expanded.files.map((f) => dirname(f.path)))].filter((d) => d !== lineDir);
2280
+ const r = cssPackageLineResolution(baseDir, lineDir, spec, others);
2281
+ const head = `${spec} import \uAC00 \uC788\uC9C0\uB9CC \uADF8 \uC904\uC774 \uC788\uB294 \uD30C\uC77C \uC704\uCE58\uC5D0\uC11C`;
2282
+ const label = (pkgDir, version) => `${displayRel(baseDir, pkgDir)}(${version ?? "\uBC84\uC804 \uBAA8\uB984"})`;
2283
+ switch (r.kind) {
2284
+ case "ok":
2285
+ return void 0;
2286
+ case "shadow-not-exported": {
2287
+ const current = r.version !== void 0 && (compareExactVersions(r.version, TAILWIND4_MIN_AXIS_VERSION) ?? -1) >= 0;
2288
+ const todo = current ? "\uB2E4\uC2DC \uC124\uCE58\uD558\uC138\uC694" : `${TAILWIND4_MIN_AXIS_VERSION} \uC774\uC0C1\uC73C\uB85C \uB9DE\uCD94\uC138\uC694`;
2289
+ return `${head} \uBA3C\uC800 \uC7A1\uD788\uB294 ${label(r.pkgDir, r.version)}\uAC00 ${r.subpath} \uB97C \uB0B4\uBCF4\uB0B4\uC9C0 \uC54A\uC544 \uD574\uC11D\uB418\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4 \u2192 \uADF8 \uC911\uCCA9 node_modules \uC758 ${name} \uB97C \uC9C0\uC6B0\uAC70\uB098 ${todo}`;
2290
+ }
2291
+ case "shadow-target-missing":
2292
+ return `${head} \uBA3C\uC800 \uC7A1\uD788\uB294 ${label(r.pkgDir, r.version)}\uC5D0 \uB0B4\uBCF4\uB0B8 \uD30C\uC77C(${r.target})\uC774 \uC5C6\uC5B4 \uD574\uC11D\uB418\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4 \u2192 \uADF8 \uC911\uCCA9 node_modules \uC758 ${name} \uB97C \uC9C0\uC6B0\uAC70\uB098 \uB2E4\uC2DC \uC124\uCE58\uD558\uC138\uC694`;
2293
+ case "not-visible": {
2294
+ const there = expanded.files.find((f) => dirname(f.path) === r.fromDir);
2295
+ const move = there !== void 0 ? `\uC774 \uC904(${origin.rel})\uC744 ${there.rel} \uB85C \uC62E\uAE30\uC138\uC694` : `\uC774 \uC904(${origin.rel})\uC744 \uADF8 \uC704\uCE58\uC758 CSS \uD30C\uC77C\uB85C \uC62E\uAE30\uC138\uC694`;
2296
+ return `${head} ${name} \uB97C \uCC3E\uC9C0 \uBABB\uD574 \uD574\uC11D\uB418\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4(\uC124\uCE58\uBCF8\uC774 ${displayRel(baseDir, r.pkgDir)} \uC5D0\uB9CC \uC788\uC74C) \u2192 \uC571 \uB610\uB294 \uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uB8E8\uD2B8\uC5D0 \uC124\uCE58\uD558\uAC70\uB098 ${move}`;
2297
+ }
2298
+ }
2299
+ }
2300
+ function isOutsideEntry(origin) {
2301
+ return origin.depth === 0 && origin.cssDir !== void 0;
2302
+ }
2080
2303
  function checkGlobalsCss(baseDirInput) {
2081
2304
  const baseDir = resolveBaseDir(baseDirInput);
2082
- for (const candidate of TAILWIND_CSS_CANDIDATES) {
2083
- const file = join(baseDir, candidate);
2084
- if (!existsSync(file)) continue;
2085
- const content = readFileSync(file, "utf8");
2086
- const css = stripCssComments(content);
2087
- const imported = findTokensCssImport(content);
2088
- let pass;
2089
- if (imported !== void 0) pass = `${candidate}\uC5D0 AXIS CSS \uBCC0\uC218\uAC00 \uC788\uC2B5\uB2C8\uB2E4 (${imported} import)`;
2090
- else if (AXIS_VARIABLE_DEFINITION.test(css)) pass = `${candidate}\uC5D0 AXIS CSS \uBCC0\uC218(--axis-*)\uAC00 \uC815\uC758\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4`;
2091
- else {
2092
- const layout = findLayoutTokensCssImport(baseDir);
2093
- if (layout) pass = `${candidate}\uC5D0 AXIS CSS \uBCC0\uC218\uAC00 \uC788\uC2B5\uB2C8\uB2E4 (${layout.file}\uC758 ${layout.spec} import)`;
2094
- }
2095
- if (pass !== void 0) {
2096
- const tailwind = detectTailwind(baseDir, readPackageJson(baseDir));
2097
- const tailwind4 = tailwind.major !== void 0 && tailwind.major >= 4;
2098
- if (!tailwind4 && findCreateNextAppDefaults(content).some((d) => d.includes("font-family: Arial"))) {
2099
- return {
2100
- name: "globals.css",
2101
- severity: "warn",
2102
- 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)`
2103
- };
2104
- }
2105
- return { name: "globals.css", severity: "pass", message: pass };
2106
- }
2107
- if (css.includes("--background") && css.includes("--primary")) {
2305
+ const selection = selectCheckGlobalCss(baseDir);
2306
+ const note = globalCssSelectionNote(selection);
2307
+ if (selection.path !== void 0 && selection.rel !== void 0) {
2308
+ const candidate = selection.rel;
2309
+ const expanded = expandGlobalCss(baseDir, selection.path, candidate, outsideCssDir(selection));
2310
+ const judged = judgeGlobalsCss(baseDir, selection, candidate, expanded);
2311
+ if (expanded.cycle !== void 0) {
2312
+ return { name: "globals.css", severity: "warn", message: `${judged.message} / ${cssImportCycleIssue(expanded.cycle)}${note}` };
2313
+ }
2314
+ return { name: "globals.css", severity: judged.severity, message: `${judged.message}${note}` };
2315
+ }
2316
+ return { name: "globals.css", severity: "fail", message: `globals.css \uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4${note}` };
2317
+ }
2318
+ function judgeGlobalsCss(baseDir, selection, candidate, expanded) {
2319
+ const content = expanded.entry;
2320
+ const css = stripCssComments(content);
2321
+ const imported = findTokensCssImport(expanded.evidence);
2322
+ const pkg = readPackageJson(baseDir);
2323
+ let pass;
2324
+ let unresolved;
2325
+ let via = "";
2326
+ if (imported !== void 0) {
2327
+ const origin = evidenceOrigin(expanded, (f) => findTokensCssImport(f) === imported);
2328
+ via = cssImportViaNote(viaFiles([origin]));
2329
+ const tailwind4 = (detectTailwind(baseDir, pkg).major ?? 0) >= 4;
2330
+ const issue = tailwind4 && origin !== void 0 && !isOutsideEntry(origin) ? tokensCssUnresolvedIssue(
2331
+ baseDir,
2332
+ pkg,
2333
+ imported,
2334
+ void 0,
2335
+ () => packageLineShadowIssue(baseDir, expanded, origin, imported)
2336
+ ) : tokensCssUnresolvedIssue(baseDir, pkg, imported, origin !== void 0 ? origin.cssDir : outsideCssDir(selection));
2337
+ if (issue !== void 0) unresolved = `${candidate}\uC5D0 ${issue}`;
2338
+ else pass = `${candidate}\uC5D0 AXIS CSS \uBCC0\uC218\uAC00 \uC788\uC2B5\uB2C8\uB2E4 (${imported} import)`;
2339
+ } else if (AXIS_VARIABLE_DEFINITION.test(stripCssComments(expanded.evidence))) {
2340
+ via = cssImportViaNote(viaFiles([evidenceOrigin(expanded, (f) => AXIS_VARIABLE_DEFINITION.test(f))]));
2341
+ pass = `${candidate}\uC5D0 AXIS CSS \uBCC0\uC218(--axis-*)\uAC00 \uC815\uC758\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4`;
2342
+ } else {
2343
+ const layout = findLayoutTokensCssImport(baseDir);
2344
+ if (layout) {
2345
+ const issue = tokensCssUnresolvedIssue(baseDir, pkg, layout.spec);
2346
+ if (issue !== void 0) unresolved = `${candidate}\uC5D0 AXIS CSS \uBCC0\uC218\uAC00 \uC5C6\uACE0 ${layout.file}\uC758 ${issue}`;
2347
+ else pass = `${candidate}\uC5D0 AXIS CSS \uBCC0\uC218\uAC00 \uC788\uC2B5\uB2C8\uB2E4 (${layout.file}\uC758 ${layout.spec} import)`;
2348
+ }
2349
+ }
2350
+ const head = pass ?? unresolved;
2351
+ if (head !== void 0) {
2352
+ const tailwind = detectTailwind(baseDir, pkg);
2353
+ const tailwind4 = tailwind.major !== void 0 && tailwind.major >= 4;
2354
+ if (!tailwind4 && findCreateNextAppDefaults(content).some((d) => d.includes("font-family: Arial"))) {
2108
2355
  return {
2109
- name: "globals.css",
2110
2356
  severity: "warn",
2111
- 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`
2357
+ 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}`
2112
2358
  };
2113
2359
  }
2114
- return { name: "globals.css", severity: "warn", message: `${candidate}\uC5D0 AXIS CSS \uBCC0\uC218\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4` };
2360
+ return { severity: pass !== void 0 ? "pass" : "warn", message: `${head}${via}` };
2361
+ }
2362
+ if (css.includes("--background") && css.includes("--primary")) {
2363
+ return {
2364
+ severity: "warn",
2365
+ 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`
2366
+ };
2115
2367
  }
2116
- return { name: "globals.css", severity: "fail", message: "globals.css \uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4" };
2368
+ return { severity: "warn", message: `${candidate}\uC5D0 AXIS CSS \uBCC0\uC218\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4` };
2117
2369
  }
2118
- var TAILWIND4_MIN_AXIS_VERSION = "1.4.0";
2119
2370
  var TAILWIND4_AXIS_PACKAGES = ["@axis-ds/tokens", "@axis-ds/ui-react", "@axis-ds/agentic-ui"];
2120
2371
  function lowerOf(token) {
2121
2372
  const v = versionParts(token);
@@ -2313,6 +2564,17 @@ function hasBareCjsPresetRequire(code) {
2313
2564
  function isCommonJsConfig(file, source) {
2314
2565
  return extname(file) === ".cjs" || /\bmodule\.exports\b/.test(source);
2315
2566
  }
2567
+ function presetTokensUnresolvedMessage(baseDir, pkg, file, bareCjs) {
2568
+ const r = tokensCssResolution(baseDir, pkg, TOKENS_PACKAGE_NAME);
2569
+ const head = `${file}\uC5D0 AXIS preset \uCC38\uC870\uAC00 \uC788\uC9C0\uB9CC ${TOKENS_PACKAGE_NAME} \uAC00`;
2570
+ if (r.kind === "not-installed") {
2571
+ return `${head} \uC124\uCE58\uB418\uC9C0 \uC54A\uC544 \uD574\uC11D\uB418\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4 \u2192 \uC124\uCE58(${tokensInstallPhrase(baseDir, `^${TOKENS_CJS_PRESET_FIXED_VERSION}`)})`;
2572
+ }
2573
+ if (r.kind === "pnp-root-only" && !bareCjs) {
2574
+ return `${head} ${PNP_ROOT_ONLY_NOTE}(\uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uB8E8\uD2B8 \uC120\uC5B8 ${r.range}) \u2192 \uC571 package.json \uC5D0 ${TOKENS_PACKAGE_NAME} \uB97C \uC120\uC5B8\uD558\uC138\uC694`;
2575
+ }
2576
+ return void 0;
2577
+ }
2316
2578
  function packageVersionGate(baseDirInput, pkg, name, min, options = {}) {
2317
2579
  const baseDir = resolveBaseDir(baseDirInput);
2318
2580
  if (!isPnpProject(baseDir)) {
@@ -2348,66 +2610,155 @@ function readPackageJson(baseDir) {
2348
2610
  return void 0;
2349
2611
  }
2350
2612
  }
2351
- function tailwind4Issues(css, pkg, versions, baseDir) {
2613
+ function tailwind4Issues(input, pkg, versions, baseDir) {
2614
+ const { entry, evidence } = input;
2615
+ const cssDirOf = input.cssDirOf ?? (() => void 0);
2352
2616
  const issues = [];
2353
- const hasEntry = hasTokensTailwind4Import(css);
2617
+ const tailwindDir = cssDirOf("tailwindcss");
2618
+ if (tailwindDir !== void 0 && outsideCssPackageResolution(baseDir, tailwindDir, "tailwindcss") === "unresolved") {
2619
+ issues.push(outsideCssUnresolvedIssue("tailwindcss", "tailwindcss"));
2620
+ }
2621
+ const hasEntry = hasTokensTailwind4Import(evidence);
2354
2622
  if (!hasEntry) issues.push(`AXIS \uD1A0\uD070 \uC9C4\uC785\uC810\uC774 \uC5C6\uC2B5\uB2C8\uB2E4 \u2192 ${TOKENS_TAILWIND4_IMPORT_LINE}`);
2355
- const missing = TAILWIND4_COMPONENT_PACKAGES.filter(
2356
- (name) => declaredRange(baseDir, pkg, name) !== void 0 && !hasComponentTailwindImport(css, name) && !hasComponentSource(css, name)
2357
- );
2623
+ const resolutions = new Map(TAILWIND4_COMPONENT_PACKAGES.map((name) => [name, componentCssResolution(baseDir, pkg, name)]));
2624
+ const missing = [];
2625
+ const unresolvedMissing = [];
2626
+ for (const name of TAILWIND4_COMPONENT_PACKAGES) {
2627
+ const r = resolutions.get(name);
2628
+ if (r.kind === "undeclared" || r.kind === "app-lockfile") continue;
2629
+ if (hasComponentTailwindImport(evidence, name) || hasComponentSource(evidence, name)) continue;
2630
+ if (componentCssResolvable(r)) missing.push(name);
2631
+ else unresolvedMissing.push(componentCssMissingIssue(baseDir, name, r));
2632
+ }
2358
2633
  if (missing.length > 0) {
2359
2634
  issues.push(`\uCEF4\uD3EC\uB10C\uD2B8 \uC2A4\uCE94 \uACBD\uB85C(tailwind.css)\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4 \u2192 ${missing.map(componentTailwindImportLine).join(" ")}`);
2360
2635
  }
2636
+ issues.push(...unresolvedMissing);
2361
2637
  if (hasEntry) {
2362
- const defaults = findCreateNextAppDefaults(css);
2638
+ const defaults = findCreateNextAppDefaults(entry);
2363
2639
  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`);
2364
2640
  if (versions.some((v) => v.name === TAILWIND4_AXIS_PACKAGES[0])) {
2365
2641
  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`);
2366
2642
  }
2367
2643
  }
2368
2644
  for (const name of TAILWIND4_COMPONENT_PACKAGES) {
2369
- if (hasComponentTailwindImport(css, name) && versions.some((v) => v.name === name)) {
2370
- issues.push(`${name}/tailwind.css import \uAC00 \uC788\uC9C0\uB9CC ${name} \uBC84\uC804 \uD655\uC778\uC774 \uD544\uC694\uD569\uB2C8\uB2E4`);
2645
+ if (!hasComponentTailwindImport(evidence, name)) continue;
2646
+ const unresolved = componentCssPresentIssue(baseDir, name, resolutions.get(name));
2647
+ const spec = `${name}/tailwind.css`;
2648
+ if (unresolved !== void 0) {
2649
+ issues.push(unresolved);
2650
+ continue;
2651
+ }
2652
+ const shadow = input.lineIssue === void 0 ? false : input.lineIssue(spec);
2653
+ let lineProblem;
2654
+ if (shadow !== false) lineProblem = shadow;
2655
+ else {
2656
+ const componentDir = cssDirOf(spec);
2657
+ if (componentDir !== void 0 && outsideCssPackageResolution(baseDir, componentDir, name, "tailwind.css") === "unresolved") {
2658
+ lineProblem = outsideCssUnresolvedIssue(spec, name);
2659
+ }
2371
2660
  }
2661
+ if (lineProblem !== void 0) issues.push(lineProblem);
2662
+ 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`);
2372
2663
  }
2373
2664
  return issues;
2374
2665
  }
2666
+ function componentInstallPhrase(baseDir, name, range) {
2667
+ const g = dependencyInstallGuide(baseDir, name, range);
2668
+ return g.kind === "install-at-root" ? `\uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uB8E8\uD2B8\uC5D0\uC11C ${g.installCommand}` : g.installCommand;
2669
+ }
2670
+ function componentCssMissingIssue(baseDir, name, r) {
2671
+ const line = componentTailwindImportLine(name);
2672
+ switch (r.kind) {
2673
+ case "pnp-root-only":
2674
+ return `${name} \uAC00 ${PNP_ROOT_ONLY_NOTE} \u2192 \uC571 package.json \uC5D0 \uC120\uC5B8\uD55C \uB4A4 ${line}`;
2675
+ case "root-not-installed":
2676
+ 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}`;
2677
+ case "root-old":
2678
+ 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}`;
2679
+ case "root-missing-file":
2680
+ 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}`;
2681
+ default:
2682
+ return line;
2683
+ }
2684
+ }
2685
+ function componentCssPresentIssue(baseDir, name, r) {
2686
+ const head = `${name}/tailwind.css import \uAC00 \uC788\uC9C0\uB9CC`;
2687
+ switch (r.kind) {
2688
+ case "pnp-root-only":
2689
+ return `${head} ${name} \uAC00 ${PNP_ROOT_ONLY_NOTE} \u2192 \uC571 package.json \uC5D0 \uC120\uC5B8\uD558\uC138\uC694`;
2690
+ case "root-not-installed":
2691
+ 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)})`;
2692
+ case "root-missing-file":
2693
+ 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)})`;
2694
+ case "root-old":
2695
+ 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;
2696
+ default:
2697
+ return void 0;
2698
+ }
2699
+ }
2375
2700
  function checkTailwindSetup(baseDirInput) {
2376
2701
  const baseDir = resolveBaseDir(baseDirInput);
2377
2702
  const pkg = readPackageJson(baseDir);
2378
2703
  const tailwind = detectTailwind(baseDir, pkg);
2379
2704
  if (tailwind.major !== void 0 && tailwind.major >= 4) {
2380
2705
  const label = `Tailwind ${tailwind.major}`;
2381
- for (const candidate of TAILWIND_CSS_CANDIDATES) {
2382
- const file = join(baseDir, candidate);
2383
- if (!existsSync(file)) continue;
2384
- const css = readFileSync(file, "utf8");
2385
- if (!hasTailwindImport(css)) {
2706
+ const selection = selectCheckGlobalCss(baseDir);
2707
+ const note = globalCssSelectionNote(selection);
2708
+ if (selection.path !== void 0 && selection.rel !== void 0) {
2709
+ const candidate = selection.rel;
2710
+ const expanded = expandGlobalCss(baseDir, selection.path, candidate, outsideCssDir(selection));
2711
+ if (!hasTailwindImport(expanded.evidence)) {
2386
2712
  return {
2387
2713
  name: "tailwind.config",
2388
2714
  severity: "warn",
2389
- message: `${label}: ${candidate}\uC5D0 @import "tailwindcss" \uAC00 \uC5C6\uC2B5\uB2C8\uB2E4`
2715
+ message: `${label}: ${candidate}\uC5D0 @import "tailwindcss" \uAC00 \uC5C6\uC2B5\uB2C8\uB2E4${note}`
2390
2716
  };
2391
2717
  }
2718
+ const via = cssImportViaNote(
2719
+ viaFiles([
2720
+ evidenceOrigin(expanded, hasTailwindImport),
2721
+ evidenceOrigin(expanded, hasTokensTailwind4Import),
2722
+ ...TAILWIND4_COMPONENT_PACKAGES.flatMap((name) => [
2723
+ evidenceOrigin(expanded, (f) => hasComponentTailwindImport(f, name)),
2724
+ evidenceOrigin(expanded, (f) => hasComponentSource(f, name))
2725
+ ])
2726
+ ])
2727
+ );
2392
2728
  const versions = axisPackagesBelowTailwind4(pkg, baseDir);
2393
- const issues = tailwind4Issues(css, pkg, versions, baseDir);
2729
+ const issues = tailwind4Issues(
2730
+ {
2731
+ entry: expanded.entry,
2732
+ evidence: expanded.evidence,
2733
+ cssDirOf: (spec) => packageLineCssDir(expanded, spec),
2734
+ lineIssue: (spec) => {
2735
+ const line = expanded.packageLines.find((l) => l.spec === spec);
2736
+ const origin = line !== void 0 ? expanded.files.find((f) => f.rel === line.file) : void 0;
2737
+ if (origin === void 0 || isOutsideEntry(origin)) return false;
2738
+ return packageLineShadowIssue(baseDir, expanded, origin, spec);
2739
+ }
2740
+ },
2741
+ pkg,
2742
+ versions,
2743
+ baseDir
2744
+ );
2394
2745
  if (issues.length > 0) {
2395
2746
  return {
2396
2747
  name: "tailwind.config",
2397
2748
  severity: "warn",
2398
- message: `${label}: ${candidate}\uC5D0 ${issues.join(" / ")}${tailwind4VersionNote(versions)}`
2749
+ message: `${label}: ${candidate}\uC5D0 ${issues.join(" / ")}${tailwind4VersionNote(versions)}${via}${note}`
2399
2750
  };
2400
2751
  }
2401
2752
  return {
2402
2753
  name: "tailwind.config",
2403
2754
  severity: "pass",
2404
- message: `${label}: ${candidate}\uC5D0 @import "tailwindcss" \uC640 AXIS \uD1A0\uD070 \uC9C4\uC785\uC810\uC774 \uC788\uC2B5\uB2C8\uB2E4`
2755
+ message: `${label}: ${candidate}\uC5D0 @import "tailwindcss" \uC640 AXIS \uD1A0\uD070 \uC9C4\uC785\uC810\uC774 \uC788\uC2B5\uB2C8\uB2E4${via}${note}`
2405
2756
  };
2406
2757
  }
2407
2758
  return {
2408
2759
  name: "tailwind.config",
2409
2760
  severity: "warn",
2410
- message: `${label}: @import "tailwindcss" \uB97C \uD655\uC778\uD560 CSS \uD30C\uC77C\uC744 \uCC3E\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4`
2761
+ message: `${label}: @import "tailwindcss" \uB97C \uD655\uC778\uD560 CSS \uD30C\uC77C\uC744 \uCC3E\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4${note}`
2411
2762
  };
2412
2763
  }
2413
2764
  for (const file of TAILWIND_CONFIG_FILES) {
@@ -2416,7 +2767,10 @@ function checkTailwindSetup(baseDirInput) {
2416
2767
  const content = readFileSync(path17, "utf8");
2417
2768
  if (hasTokensPresetReference(content)) {
2418
2769
  const code = stripJsComments(content);
2419
- if (isCommonJsConfig(file, code) && hasBareCjsPresetRequire(code)) {
2770
+ const bareCjs = isCommonJsConfig(file, code) && hasBareCjsPresetRequire(code);
2771
+ const unresolved = presetTokensUnresolvedMessage(baseDir, pkg, file, bareCjs);
2772
+ if (unresolved !== void 0) return { name: "tailwind.config", severity: "warn", message: unresolved };
2773
+ if (bareCjs) {
2420
2774
  const gate = packageVersionGate(baseDir, pkg, "@axis-ds/tokens", TOKENS_CJS_PRESET_FIXED_VERSION, { appOnlyInPnp: true });
2421
2775
  if (gate.status === "unresolved") {
2422
2776
  return {
@@ -2453,31 +2807,45 @@ function readAxisConfigLike(baseDir) {
2453
2807
  return void 0;
2454
2808
  }
2455
2809
  }
2456
- function contentGlobToRegExp(glob) {
2810
+ function selectCheckGlobalCss(baseDir) {
2811
+ return selectGlobalCss(baseDir, readAxisConfigLike(baseDir)?.globalCss, TAILWIND_CSS_CANDIDATES, { requireStylesheet: true });
2812
+ }
2813
+ function contentGlobToRegExp(glob, opts = {}) {
2814
+ const noDot = opts.noDot === true;
2457
2815
  const g = glob.trim().replace(/^\.\//, "");
2816
+ const lead = (i) => noDot && (i === 0 || g[i - 1] === "/") ? "(?!\\.)" : "";
2458
2817
  let re = "";
2459
2818
  for (let i = 0; i < g.length; i++) {
2460
2819
  const c = g[i];
2461
2820
  if (c === "*") {
2462
2821
  if (g[i + 1] === "*") {
2463
2822
  const slash = g[i + 2] === "/";
2464
- re += slash ? "(?:.*/)?" : ".*";
2823
+ if (noDot) re += slash ? `(?:${lead(i)}[^/]*/(?:(?!\\.)[^/]*/)*)?` : `${lead(i)}[^/]*(?:/(?!\\.)[^/]*)*`;
2824
+ else re += slash ? "(?:.*/)?" : ".*";
2465
2825
  i += slash ? 2 : 1;
2466
- } else re += "[^/]*";
2467
- } else if (c === "?") re += "[^/]";
2826
+ } else re += `${lead(i)}[^/]*`;
2827
+ } else if (c === "?") re += `${lead(i)}[^/]`;
2468
2828
  else if (c === "{") {
2469
2829
  const end = g.indexOf("}", i);
2470
2830
  if (end === -1) {
2471
2831
  re += "\\{";
2472
2832
  continue;
2473
2833
  }
2474
- re += `(?:${g.slice(i + 1, end).split(",").map((part) => part.replace(/[.+^$()|[\]\\]/g, "\\$&").replace(/\*/g, "[^/]*")).join("|")})`;
2834
+ const atStart = lead(i) !== "";
2835
+ re += `(?:${g.slice(i + 1, end).split(",").map((part) => {
2836
+ const body = part.replace(/[.+^$()|[\]\\]/g, "\\$&");
2837
+ if (!noDot) return body.replace(/\*/g, "[^/]*");
2838
+ return body.replace(
2839
+ /(\/)?\*/g,
2840
+ (_m, slash, off) => slash !== void 0 || off === 0 && atStart ? `${slash ?? ""}(?!\\.)[^/]*` : "[^/]*"
2841
+ );
2842
+ }).join("|")})`;
2475
2843
  i = end;
2476
2844
  } else if (c === "[") {
2477
2845
  const end = g.indexOf("]", i);
2478
2846
  if (end === -1) re += "\\[";
2479
2847
  else {
2480
- re += g.slice(i, end + 1);
2848
+ re += lead(i) + g.slice(i, end + 1);
2481
2849
  i = end;
2482
2850
  }
2483
2851
  } else re += c.replace(/[.+^$()|\\]/g, "\\$&");
@@ -2546,22 +2914,46 @@ function realpathPosix(p) {
2546
2914
  }
2547
2915
  return void 0;
2548
2916
  }
2549
- function contentGlobBranchCovers(glob, sample, baseDir) {
2917
+ function contentGlobBranchCovers(glob, sample, baseDir, noDot) {
2550
2918
  if (isAbsoluteGlob(glob)) {
2551
- const re = contentGlobToRegExp(glob.trim().replace(/\\/g, "/"));
2919
+ const re = contentGlobToRegExp(glob.trim().replace(/\\/g, "/"), { noDot });
2552
2920
  const absSample = resolve(baseDir, sample);
2553
2921
  if (re.test(absSample.split(sep).join("/"))) return true;
2554
2922
  const real = realpathPosix(absSample);
2555
2923
  return real !== void 0 && re.test(real);
2556
2924
  }
2557
- return leadingParentSegments(glob) === leadingParentSegments(sample) && contentGlobToRegExp(glob).test(sample);
2925
+ return leadingParentSegments(glob) === leadingParentSegments(sample) && contentGlobToRegExp(glob, { noDot }).test(sample);
2558
2926
  }
2559
- function contentGlobCovers(glob, sample, baseDirInput) {
2927
+ function contentGlobCovers(glob, sample, baseDirInput, opts = {}) {
2560
2928
  const baseDir = resolveBaseDir(baseDirInput);
2561
2929
  const branches = expandBraces(glob.trim()) ?? [glob];
2562
- return branches.some((b) => contentGlobBranchCovers(b, sample, baseDir));
2930
+ return branches.some((b) => contentGlobBranchCovers(b, sample, baseDir, opts.noDot === true));
2931
+ }
2932
+ 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";
2933
+ function contentPnpNote(names, unplugged = []) {
2934
+ const list = [...new Set(typeof names === "string" ? [names] : names)];
2935
+ const dyn = list.map((n) => `path.join(path.dirname(require.resolve("${n}")), "..", "dist/**/*.{js,mjs}")`).join(", ");
2936
+ const needsSetup = list.filter((n) => !unplugged.includes(n));
2937
+ const meta = needsSetup.map((n) => `"${n}": { "unplugged": true }`).join(", ");
2938
+ 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` : "";
2939
+ 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}`;
2940
+ }
2941
+ function contentPnpNoteTargets(targets) {
2942
+ return targets.filter((t) => t.pnp !== void 0 && t.pnp.state !== "rootOnly").map((t) => t.label);
2943
+ }
2944
+ function contentPnpNoteFor(targets) {
2945
+ const names = contentPnpNoteTargets(targets);
2946
+ if (names.length === 0) return void 0;
2947
+ const unplugged = targets.filter((t) => t.pnp?.state === "unplugged").map((t) => t.label);
2948
+ return contentPnpNote(names, unplugged);
2949
+ }
2950
+ var CONTENT_PNP_ROOT_ONLY_ACTION = "\uC571 package.json \uC5D0 \uC120\uC5B8\uD558\uC138\uC694";
2951
+ var CONTENT_PNP_NO_NODE_MODULES = "Plug'n'Play \uB77C node_modules \uACBD\uB85C\uAC00 \uC5C6\uC74C";
2952
+ function contentTargetText(t) {
2953
+ if (t.pnp?.state === "noNodeModules") return `${t.label}(${CONTENT_PNP_NO_NODE_MODULES})`;
2954
+ if (t.pnp?.state === "rootOnly") return `${t.label} \uAC00 ${PNP_ROOT_ONLY_NOTE} \u2192 ${CONTENT_PNP_ROOT_ONLY_ACTION}`;
2955
+ return `${t.label} \u2192 "${t.suggest}"${t.note === void 0 ? "" : ` (${t.note})`}`;
2563
2956
  }
2564
- 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";
2565
2957
  function relDirOf(baseDir, dir) {
2566
2958
  const rel3 = relative(baseDir, dir);
2567
2959
  return rel3 === "" || isAbsolute(rel3) ? void 0 : rel3.split(sep).join("/");
@@ -2581,8 +2973,26 @@ function packageVersion(dir) {
2581
2973
  return void 0;
2582
2974
  }
2583
2975
  }
2584
- function packageContentTarget(baseDir, name) {
2585
- const found = isPnpProject(baseDir) ? void 0 : findInstalledPackage(baseDir, name);
2976
+ function pnpPackageContentTarget(baseDir, name, pkg) {
2977
+ const legacySample = `node_modules/${name}/dist/index.js`;
2978
+ const none = { sample: "", suggest: "", alternates: [], others: [] };
2979
+ if (pnpRootOnlyDependency(baseDir, pkg, name) !== void 0) return { ...none, pnp: { state: "rootOnly", legacySample } };
2980
+ const range = pkg === void 0 ? void 0 : hasDependency(pkg, name);
2981
+ const rels = (range === void 0 ? [] : findPnpUnpluggedPackages(baseDir, name, range)).map((d) => relDirOf(baseDir, d)).filter((r) => r !== void 0);
2982
+ const root = pnpProjectRoot(baseDir);
2983
+ if (rels.length === 0 || root === void 0) return { ...none, pnp: { state: "noNodeModules", legacySample } };
2984
+ const rootRel = relDirOf(baseDir, root);
2985
+ return {
2986
+ sample: `${rels[0]}/dist/index.js`,
2987
+ suggest: `${rootRel === void 0 ? "." : rootRel}/.yarn/unplugged/*/node_modules/${name}/dist/**/*.{js,mjs}`,
2988
+ alternates: rels.slice(1).map((r) => `${r}/dist/index.js`),
2989
+ others: [],
2990
+ pnp: { state: "unplugged", legacySample }
2991
+ };
2992
+ }
2993
+ function packageContentTarget(baseDir, name, pkg) {
2994
+ if (isPnpProject(baseDir)) return pnpPackageContentTarget(baseDir, name, pkg);
2995
+ const found = findInstalledPackage(baseDir, name);
2586
2996
  const relDir = (found === void 0 ? void 0 : relDirOf(baseDir, found.dir)) ?? `node_modules/${name}`;
2587
2997
  const alternates = [];
2588
2998
  const others = [];
@@ -2603,7 +3013,7 @@ function packageContentTarget(baseDir, name) {
2603
3013
  const versions = theirs === void 0 || ours === void 0 ? "" : theirs === ours ? `(\uBC84\uC804\uC740 ${ours} \uB85C \uAC19\uC74C)` : `(${theirs}, \uC571 ${ours})`;
2604
3014
  others.push({
2605
3015
  sample: `${rel3}/dist/index.js`,
2606
- note: `\uC0C1\uC704 \uACBD\uB85C ${rel3} \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`
3016
+ note: `\uC0C1\uC704 \uACBD\uB85C ${rel3} \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`
2607
3017
  });
2608
3018
  }
2609
3019
  }
@@ -2680,7 +3090,7 @@ function inspectTailwindContent(baseDirInput) {
2680
3090
  }
2681
3091
  for (const name of TAILWIND4_COMPONENT_PACKAGES) {
2682
3092
  if (declaredRange(baseDir, pkg, name) !== void 0) {
2683
- targets.push({ label: name, ...packageContentTarget(baseDir, name) });
3093
+ targets.push({ label: name, ...packageContentTarget(baseDir, name, pkg) });
2684
3094
  }
2685
3095
  }
2686
3096
  if (targets.length === 0) return null;
@@ -2690,11 +3100,14 @@ function inspectTailwindContent(baseDirInput) {
2690
3100
  configFile,
2691
3101
  unreadable: read === void 0,
2692
3102
  dynamic: read?.dynamic ?? false,
2693
- targets: targets.map(({ alternates = [], others = [], ...t }) => {
3103
+ targets: targets.map(({ alternates = [], others = [], pnp, ...t }) => {
2694
3104
  const covers = (sample) => globs.some((g) => contentGlobCovers(g, sample, baseDir));
2695
- const covered = [t.sample, ...alternates].some(covers);
3105
+ const samples = pnp !== void 0 && pnp.state !== "unplugged" ? [] : [t.sample, ...alternates];
3106
+ const coversSample = pnp?.state === "unplugged" ? (sample) => globs.some((g) => contentGlobCovers(g, sample, baseDir, { noDot: true })) : covers;
3107
+ const covered = samples.some(coversSample);
2696
3108
  const note = covered ? void 0 : others.find((o) => covers(o.sample))?.note;
2697
- return note === void 0 ? { ...t, covered } : { ...t, covered, note };
3109
+ const base = note === void 0 ? { ...t, covered } : { ...t, covered, note };
3110
+ return pnp === void 0 ? base : { ...base, pnp: { state: pnp.state, legacyCovered: covers(pnp.legacySample) } };
2698
3111
  })
2699
3112
  };
2700
3113
  }
@@ -2709,19 +3122,30 @@ function checkTailwindContent(baseDir) {
2709
3122
  message: `${r.configFile}\uC758 content \uAC00 ${r.targets.map((t) => t.label).join(" \xB7 ")} \uB97C \uB36E\uC2B5\uB2C8\uB2E4`
2710
3123
  };
2711
3124
  }
2712
- const list = missing.map((t) => `${t.label} \u2192 "${t.suggest}"${t.note === void 0 ? "" : ` (${t.note})`}`).join(" \xB7 ");
3125
+ const list = missing.map(contentTargetText).join(" \xB7 ");
2713
3126
  const note = missing.some((t) => t.suggest.startsWith("../")) ? ` (${CONTENT_PARENT_PATH_NOTE})` : "";
3127
+ const pnpText = contentPnpNoteFor(missing);
3128
+ const pnpNote = pnpText === void 0 ? "" : ` (${pnpText})`;
2714
3129
  if (r.unreadable || r.dynamic) {
2715
3130
  return {
2716
3131
  name: "tailwind.content",
2717
3132
  severity: "warn",
2718
- 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}`
3133
+ 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}`
3134
+ };
3135
+ }
3136
+ if (missing.every((t) => t.pnp?.legacyCovered === true)) {
3137
+ const labels = missing.map((t) => t.label).join(" \xB7 ");
3138
+ const details = missing.filter((t) => t.pnp?.state !== "noNodeModules").map(contentTargetText);
3139
+ return {
3140
+ name: "tailwind.content",
3141
+ severity: "warn",
3142
+ 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}`
2719
3143
  };
2720
3144
  }
2721
3145
  return {
2722
3146
  name: "tailwind.content",
2723
3147
  severity: "fail",
2724
- 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}`
3148
+ 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}`
2725
3149
  };
2726
3150
  }
2727
3151
  var ANIMATION_PLUGIN_TAILWIND3 = "tailwindcss-animate";
@@ -2779,24 +3203,30 @@ function checkAnimationPlugin(baseDirInput) {
2779
3203
  return void 0;
2780
3204
  };
2781
3205
  if (tailwind.major !== void 0 && tailwind.major >= 4) {
2782
- const file = TAILWIND_CSS_CANDIDATES.find((c) => existsSync(join(baseDir, c)));
2783
- const css = file !== void 0 ? stripCssComments(readFileSync(join(baseDir, file), "utf8")) : "";
3206
+ const selection = selectCheckGlobalCss(baseDir);
3207
+ const note = globalCssSelectionNote(selection);
3208
+ const file = selection.rel;
3209
+ const expanded = selection.path !== void 0 && selection.rel !== void 0 ? expandGlobalCss(baseDir, selection.path, selection.rel, outsideCssDir(selection)) : void 0;
3210
+ const css = expanded !== void 0 ? stripCssComments(expanded.evidence) : "";
3211
+ const twAnimate = new RegExp(`@import\\s+(?:url\\(\\s*)?["']${ANIMATION_PLUGIN_TAILWIND4}["']`);
3212
+ const animatePlugin = new RegExp(`@plugin\\s+["']${ANIMATION_PLUGIN_TAILWIND3}["']`);
2784
3213
  const lines = [];
2785
- if (new RegExp(`@import\\s+(?:url\\(\\s*)?["']${ANIMATION_PLUGIN_TAILWIND4}["']`).test(css)) lines.push(ANIMATION_PLUGIN_TAILWIND4);
2786
- if (new RegExp(`@plugin\\s+["']${ANIMATION_PLUGIN_TAILWIND3}["']`).test(css)) lines.push(ANIMATION_PLUGIN_TAILWIND3);
3214
+ if (twAnimate.test(css)) lines.push(ANIMATION_PLUGIN_TAILWIND4);
3215
+ if (animatePlugin.test(css)) lines.push(ANIMATION_PLUGIN_TAILWIND3);
3216
+ const via = expanded !== void 0 ? cssImportViaNote(viaFiles([evidenceOrigin(expanded, (f) => twAnimate.test(f)), evidenceOrigin(expanded, (f) => animatePlugin.test(f))])) : "";
2787
3217
  if (lines.length === 0) {
2788
3218
  return {
2789
3219
  name: "animation",
2790
3220
  severity: "warn",
2791
- 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}";`
3221
+ 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}`
2792
3222
  };
2793
3223
  }
2794
3224
  const problems = lines.map((name) => ({ name, why: pluginProblem(name) })).filter((x) => x.why !== void 0);
2795
- 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` };
3225
+ 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}` };
2796
3226
  return {
2797
3227
  name: "animation",
2798
3228
  severity: "warn",
2799
- 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`
3229
+ 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}`
2800
3230
  };
2801
3231
  }
2802
3232
  const configFile = TAILWIND_CONFIG_FILES.find((f) => existsSync(join(baseDir, f)));
@@ -3227,9 +3657,11 @@ import path10 from "path";
3227
3657
  import chalk7 from "chalk";
3228
3658
 
3229
3659
  // src/theme/brand-core.ts
3230
- import { existsSync as existsSync2, readFileSync as readFileSync2, statSync } from "fs";
3660
+ import { createHash } from "crypto";
3661
+ import { existsSync as existsSync2, readFileSync as readFileSync2, statSync as statSync2 } from "fs";
3231
3662
  import { createRequire } from "module";
3232
3663
  import { dirname as dirname2, join as join2, relative as relative2, resolve as resolve2, sep as sep2 } from "path";
3664
+ import { MessageChannel, Worker, receiveMessageOnPort } from "worker_threads";
3233
3665
  var TOKENS_PACKAGE = "@axis-ds/tokens";
3234
3666
  var BRAND_NAME_PATTERN = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/;
3235
3667
  var MIN_BRAND_TOKENS_VERSION = "1.3.0";
@@ -3255,13 +3687,15 @@ function readJsonFile(file) {
3255
3687
  function errorCode(err) {
3256
3688
  return typeof err === "object" && err !== null && "code" in err ? String(err.code) : void 0;
3257
3689
  }
3258
- function findTokensPackageJson(baseDir) {
3690
+ function tokensPackageJsonCandidates(baseDir) {
3691
+ const candidates = [];
3259
3692
  let dir = resolve2(baseDir);
3260
3693
  for (; ; ) {
3261
3694
  const candidate = join2(dir, "node_modules", TOKENS_PACKAGE, "package.json");
3262
- if (existsSync2(candidate)) return candidate;
3695
+ candidates.push(candidate);
3696
+ if (existsSync2(candidate)) return { found: candidate, candidates };
3263
3697
  const parent = dirname2(dir);
3264
- if (parent === dir) return void 0;
3698
+ if (parent === dir) return { candidates };
3265
3699
  dir = parent;
3266
3700
  }
3267
3701
  }
@@ -3271,47 +3705,218 @@ function projectRequire(baseDir) {
3271
3705
  function tokensSpecifier(subpath) {
3272
3706
  return `${TOKENS_PACKAGE}/${subpath.replace(/^\.\//, "")}`;
3273
3707
  }
3274
- function resolveTokens(baseDir) {
3275
- const pkgJson = findTokensPackageJson(baseDir);
3276
- if (!pkgJson) return { status: "not-installed" };
3277
- const pkg = readJsonFile(pkgJson);
3278
- const version = typeof pkg.version === "string" ? pkg.version : void 0;
3708
+ var nodeSeenStates = /* @__PURE__ */ new Map();
3709
+ var ABSENT = "absent";
3710
+ var UNKNOWN = "unknown";
3711
+ var isolationDisabled = false;
3712
+ var isolatedStats = { workers: 0, resolves: 0, fallbacks: 0 };
3713
+ var ISOLATED_RESOLVE_TIMEOUT_MS = 5e3;
3714
+ var ISOLATED_RESOLVE_SOURCE = `
3715
+ const { workerData } = require("node:worker_threads");
3716
+ const { createRequire } = require("node:module");
3717
+ const { port, signal, from } = workerData;
3718
+ const req = createRequire(from);
3719
+ port.on("message", (spec) => {
3720
+ let reply;
3721
+ try {
3722
+ reply = { path: req.resolve(spec) };
3723
+ } catch (err) {
3724
+ const code = err && typeof err === "object" && "code" in err ? String(err.code) : undefined;
3725
+ reply = { code, message: err && err.message ? String(err.message) : String(err) };
3726
+ }
3727
+ port.postMessage(reply);
3728
+ Atomics.store(signal, 0, 1);
3729
+ Atomics.notify(signal, 0);
3730
+ });
3731
+ `;
3732
+ var IsolationFailure = class extends Error {
3733
+ };
3734
+ function createWorkerResolveSession(from, source, timeoutMs) {
3735
+ const { port1, port2 } = new MessageChannel();
3736
+ const signal = new Int32Array(new SharedArrayBuffer(4));
3737
+ const worker = new Worker(source, {
3738
+ eval: true,
3739
+ workerData: { port: port2, signal, from },
3740
+ transferList: [port2]
3741
+ });
3742
+ worker.on("error", () => {
3743
+ });
3744
+ worker.unref();
3745
+ return {
3746
+ resolve(spec) {
3747
+ Atomics.store(signal, 0, 0);
3748
+ port1.postMessage(spec);
3749
+ const waited = Atomics.wait(signal, 0, 0, timeoutMs);
3750
+ const received = receiveMessageOnPort(port1);
3751
+ if (waited === "timed-out" || !received) throw new IsolationFailure("\uACA9\uB9AC \uD574\uC11D\uC774 \uC751\uB2F5\uD558\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4");
3752
+ const reply = received.message;
3753
+ if (typeof reply.path === "string") return reply.path;
3754
+ throw Object.assign(new Error(reply.message ?? spec), reply.code === void 0 ? {} : { code: reply.code });
3755
+ },
3756
+ close() {
3757
+ port1.close();
3758
+ void worker.terminate();
3759
+ }
3760
+ };
3761
+ }
3762
+ function workerResolveSession(from) {
3763
+ return createWorkerResolveSession(from, ISOLATED_RESOLVE_SOURCE, ISOLATED_RESOLVE_TIMEOUT_MS);
3764
+ }
3765
+ var isolatedFactory = workerResolveSession;
3766
+ function sha256(text) {
3767
+ return createHash("sha256").update(text).digest("hex");
3768
+ }
3769
+ function openTokensResolver(baseDir, candidates, pkgJson, pkgText) {
3770
+ const nodeRequire = projectRequire(baseDir);
3771
+ const key = sha256(pkgText);
3772
+ const current = candidates.map((c) => c === pkgJson ? key : ABSENT);
3773
+ const changed = candidates.some((c, i) => {
3774
+ const seen = nodeSeenStates.get(c);
3775
+ return seen !== void 0 && seen !== current[i];
3776
+ });
3777
+ let mode = changed ? "isolated" : "node";
3778
+ if (mode === "node") {
3779
+ candidates.forEach((c, i) => {
3780
+ if (!nodeSeenStates.has(c)) nodeSeenStates.set(c, current[i]);
3781
+ });
3782
+ }
3783
+ let session = null;
3784
+ let stale = false;
3785
+ let raced = false;
3786
+ let postChecked = false;
3787
+ const markStale = () => {
3788
+ if (!stale) isolatedStats.fallbacks += 1;
3789
+ stale = true;
3790
+ };
3791
+ const fallBack = () => {
3792
+ markStale();
3793
+ isolationDisabled = true;
3794
+ session?.close();
3795
+ session = null;
3796
+ };
3797
+ const startIsolation = () => {
3798
+ if (isolationDisabled) {
3799
+ markStale();
3800
+ return;
3801
+ }
3802
+ try {
3803
+ session = isolatedFactory(join2(resolve2(baseDir), "package.json"));
3804
+ isolatedStats.workers += 1;
3805
+ } catch {
3806
+ fallBack();
3807
+ }
3808
+ };
3809
+ if (mode === "isolated") startIsolation();
3810
+ const isolatedResolve = (spec) => {
3811
+ if (session) {
3812
+ try {
3813
+ const resolved = session.resolve(spec);
3814
+ isolatedStats.resolves += 1;
3815
+ return resolved;
3816
+ } catch (err) {
3817
+ if (!(err instanceof IsolationFailure)) {
3818
+ isolatedStats.resolves += 1;
3819
+ throw err;
3820
+ }
3821
+ fallBack();
3822
+ }
3823
+ }
3824
+ return nodeRequire.resolve(spec);
3825
+ };
3826
+ return {
3827
+ resolve(spec) {
3828
+ if (mode === "isolated") return isolatedResolve(spec);
3829
+ let resolved;
3830
+ let failure;
3831
+ let failed = false;
3832
+ try {
3833
+ resolved = nodeRequire.resolve(spec);
3834
+ } catch (err) {
3835
+ failed = true;
3836
+ failure = err;
3837
+ }
3838
+ if (!postChecked) {
3839
+ postChecked = true;
3840
+ let after;
3841
+ try {
3842
+ after = sha256(readFileSync2(pkgJson, "utf8"));
3843
+ } catch {
3844
+ after = UNKNOWN;
3845
+ }
3846
+ if (after !== key) {
3847
+ nodeSeenStates.set(pkgJson, UNKNOWN);
3848
+ raced = true;
3849
+ mode = "isolated";
3850
+ startIsolation();
3851
+ return isolatedResolve(spec);
3852
+ }
3853
+ }
3854
+ if (failed) throw failure;
3855
+ return resolved;
3856
+ },
3857
+ get stale() {
3858
+ return stale;
3859
+ },
3860
+ get raced() {
3861
+ return raced;
3862
+ },
3863
+ close() {
3864
+ session?.close();
3865
+ session = null;
3866
+ }
3867
+ };
3868
+ }
3869
+ function readVersion(pkgText) {
3870
+ const pkg = JSON.parse(pkgText);
3871
+ return typeof pkg.version === "string" ? pkg.version : void 0;
3872
+ }
3873
+ function openTokens(baseDir) {
3874
+ const { found: pkgJson, candidates } = tokensPackageJsonCandidates(baseDir);
3875
+ if (!pkgJson) return { resolution: { status: "not-installed" } };
3876
+ const pkgText = readFileSync2(pkgJson, "utf8");
3877
+ let version = readVersion(pkgText);
3878
+ const resolver = openTokensResolver(baseDir, candidates, pkgJson, pkgText);
3879
+ const finish = (status, indexPath) => {
3880
+ if (resolver.raced) {
3881
+ try {
3882
+ version = readVersion(readFileSync2(pkgJson, "utf8"));
3883
+ } catch {
3884
+ }
3885
+ }
3886
+ const resolution = indexPath === void 0 ? { status, version } : { status, version, indexPath };
3887
+ return { resolution: resolver.stale ? { ...resolution, stale: true } : resolution, resolver };
3888
+ };
3279
3889
  try {
3280
- const indexPath = projectRequire(baseDir).resolve(tokensSpecifier("./brands"));
3281
- return { status: "ok", version, indexPath };
3890
+ const indexPath = resolver.resolve(tokensSpecifier("./brands"));
3891
+ return finish("ok", indexPath);
3282
3892
  } catch (err) {
3283
3893
  const code = errorCode(err);
3284
- if (code === "ERR_PACKAGE_PATH_NOT_EXPORTED") return { status: "unsupported", version };
3285
- if (code === "MODULE_NOT_FOUND") return { status: "not-built", version };
3894
+ if (code === "ERR_PACKAGE_PATH_NOT_EXPORTED") return finish("unsupported");
3895
+ if (code === "MODULE_NOT_FOUND") return finish("not-built");
3896
+ resolver.close();
3286
3897
  throw err;
3287
3898
  }
3288
3899
  }
3900
+ function resolveTokens(baseDir) {
3901
+ const { resolution, resolver } = openTokens(baseDir);
3902
+ resolver?.close();
3903
+ return resolution;
3904
+ }
3289
3905
  function brandImportPath(entry) {
3290
3906
  return tokensSpecifier(entry.css);
3291
3907
  }
3292
3908
  function isFile(file) {
3293
3909
  try {
3294
- return statSync(file).isFile();
3910
+ return statSync2(file).isFile();
3295
3911
  } catch {
3296
3912
  return false;
3297
3913
  }
3298
3914
  }
3299
3915
  function findGlobalCss(baseDir, config) {
3300
- const root = resolve2(baseDir);
3916
+ const selection = selectGlobalCss(resolve2(baseDir), config?.globalCss, GLOBAL_CSS_CANDIDATES);
3301
3917
  const result = {};
3302
- const configured = config?.globalCss;
3303
- if (typeof configured === "string" && configured.trim() !== "") {
3304
- const file = resolve2(root, configured);
3305
- if (isFile(file)) return { path: file };
3306
- result.configuredMissing = configured;
3307
- }
3308
- for (const candidate of GLOBAL_CSS_CANDIDATES) {
3309
- const file = join2(root, candidate);
3310
- if (isFile(file)) {
3311
- result.path = file;
3312
- break;
3313
- }
3314
- }
3918
+ if (selection.configuredMissing !== void 0) result.configuredMissing = selection.configuredMissing;
3919
+ if (selection.path !== void 0) result.path = selection.path;
3315
3920
  return result;
3316
3921
  }
3317
3922
  function findBrandImports(css) {
@@ -3338,18 +3943,24 @@ function inspectBrandImport(baseDir) {
3338
3943
  const brand = config?.brand;
3339
3944
  if (typeof brand !== "string" || brand.trim() === "") return null;
3340
3945
  const root = resolve2(baseDir);
3341
- const location = findGlobalCss(root, config);
3946
+ const location = selectGlobalCss(root, config?.globalCss, GLOBAL_CSS_CANDIDATES, { requireStylesheet: true });
3342
3947
  const base = { brand };
3343
3948
  if (location.configuredMissing !== void 0) base.configuredMissing = location.configuredMissing;
3949
+ if (location.configuredRejected !== void 0) base.configuredRejected = location.configuredRejected;
3344
3950
  if (!location.path) {
3345
3951
  return { ...base, state: "css-missing", imports: [] };
3346
3952
  }
3347
3953
  const cssFile = relative2(root, location.path).split(sep2).join("/");
3348
- const imports = [...new Set(findBrandImports(readFileSync2(location.path, "utf8")))];
3954
+ const expanded = expandGlobalCss(root, location.path, cssFile);
3955
+ const imports = [...new Set(findBrandImports(expanded.evidence))];
3349
3956
  let state;
3350
3957
  if (imports.includes(brand)) state = "match";
3351
3958
  else if (imports.length === 0) state = "import-missing";
3352
3959
  else state = "other-brand";
3960
+ const sub = expanded.files.filter((f) => f.depth > 0);
3961
+ 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) : [];
3962
+ const entryHas = state === "match" && findBrandImports(expanded.files[0].css).includes(brand);
3963
+ if (via.length > 0 && !entryHas) return { ...base, state, cssFile, imports, importVia: via.map((f) => f.rel) };
3353
3964
  return { ...base, state, cssFile, imports };
3354
3965
  }
3355
3966
  function isMissingBuildFile(err) {
@@ -3363,8 +3974,8 @@ function readBrandIndex(indexPath) {
3363
3974
  }
3364
3975
  return data.brands;
3365
3976
  }
3366
- function readSummary(baseDir, entry) {
3367
- const metaPath = projectRequire(baseDir).resolve(tokensSpecifier(entry.meta));
3977
+ function readSummary(resolver, entry) {
3978
+ const metaPath = resolver.resolve(tokensSpecifier(entry.meta));
3368
3979
  const meta = readJsonFile(metaPath);
3369
3980
  return {
3370
3981
  name: entry.name,
@@ -3375,20 +3986,33 @@ function readSummary(baseDir, entry) {
3375
3986
  };
3376
3987
  }
3377
3988
  function listBrands(baseDir) {
3378
- const tokens = resolveTokens(baseDir);
3379
- if (tokens.status !== "ok" || !tokens.indexPath) {
3989
+ const { resolution: tokens, resolver } = openTokens(baseDir);
3990
+ try {
3991
+ return withStaleOf(resolver, listBrandsWith(tokens, resolver));
3992
+ } finally {
3993
+ resolver?.close();
3994
+ }
3995
+ }
3996
+ function listBrandsWith(tokens, resolver) {
3997
+ if (tokens.status !== "ok" || !tokens.indexPath || !resolver) {
3380
3998
  return { status: tokens.status, version: tokens.version, brands: [] };
3381
3999
  }
3382
4000
  const entries = readBrandIndex(tokens.indexPath);
3383
- let brands;
3384
- try {
3385
- brands = entries.map((entry) => readSummary(baseDir, entry));
3386
- } catch (err) {
3387
- if (isMissingBuildFile(err)) return { status: "not-built", version: tokens.version, brands: [] };
3388
- throw err;
4001
+ const brands = [];
4002
+ for (const entry of entries) {
4003
+ try {
4004
+ brands.push(readSummary(resolver, entry));
4005
+ } catch (err) {
4006
+ if (isMissingBuildFile(err)) return { status: "not-built", version: tokens.version, brands: [] };
4007
+ if (resolver.stale && errorCode(err) === "ERR_PACKAGE_PATH_NOT_EXPORTED") continue;
4008
+ throw err;
4009
+ }
3389
4010
  }
3390
4011
  return { status: "ok", version: tokens.version, brands };
3391
4012
  }
4013
+ function withStaleOf(resolver, result) {
4014
+ return resolver?.stale ? { ...result, stale: true } : result;
4015
+ }
3392
4016
  function stripComments(css) {
3393
4017
  return css.replace(/\/\*[\s\S]*?\*\//g, "");
3394
4018
  }
@@ -3500,8 +4124,15 @@ function readProjectPackageJson(baseDir) {
3500
4124
  }
3501
4125
  }
3502
4126
  function getBrand(baseDir, name) {
3503
- const tokens = resolveTokens(baseDir);
3504
- if (tokens.status !== "ok" || !tokens.indexPath) {
4127
+ const { resolution: tokens, resolver } = openTokens(baseDir);
4128
+ try {
4129
+ return withStaleOf(resolver, getBrandWith(tokens, resolver, name));
4130
+ } finally {
4131
+ resolver?.close();
4132
+ }
4133
+ }
4134
+ function getBrandWith(tokens, resolver, name) {
4135
+ if (tokens.status !== "ok" || !tokens.indexPath || !resolver) {
3505
4136
  return { status: tokens.status, version: tokens.version, brand: null, available: [] };
3506
4137
  }
3507
4138
  const entries = readBrandIndex(tokens.indexPath);
@@ -3513,11 +4144,14 @@ function getBrand(baseDir, name) {
3513
4144
  let summary;
3514
4145
  let parsed;
3515
4146
  try {
3516
- summary = readSummary(baseDir, entry);
3517
- const cssPath = projectRequire(baseDir).resolve(summary.importPath);
4147
+ summary = readSummary(resolver, entry);
4148
+ const cssPath = resolver.resolve(summary.importPath);
3518
4149
  parsed = parseBrandCss(readFileSync2(cssPath, "utf8"), name);
3519
4150
  } catch (err) {
3520
4151
  if (isMissingBuildFile(err)) return { status: "not-built", version: tokens.version, brand: null, available: [] };
4152
+ if (resolver.stale && errorCode(err) === "ERR_PACKAGE_PATH_NOT_EXPORTED") {
4153
+ return { status: "ok", version: tokens.version, brand: null, available: available.filter((n) => n !== name) };
4154
+ }
3521
4155
  throw err;
3522
4156
  }
3523
4157
  return {
@@ -3707,13 +4341,14 @@ function checkBrand(baseDir) {
3707
4341
  }
3708
4342
  function brandCheckResult(check) {
3709
4343
  const { brand } = check;
3710
- const suffix = check.configuredMissing !== void 0 ? ` (globalCss ${check.configuredMissing} \uC5C6\uC74C)` : "";
4344
+ const suffix = globalCssSelectionNote(check);
4345
+ const via = cssImportViaNote(check.importVia);
3711
4346
  switch (check.state) {
3712
4347
  case "match":
3713
4348
  return {
3714
4349
  name: "brand",
3715
4350
  severity: "pass",
3716
- message: `brand "${brand}" import \uAC00 ${check.cssFile}\uC5D0 \uC788\uC2B5\uB2C8\uB2E4${suffix}`
4351
+ message: `brand "${brand}" import \uAC00 ${check.cssFile}\uC5D0 \uC788\uC2B5\uB2C8\uB2E4${via}${suffix}`
3717
4352
  };
3718
4353
  case "css-missing":
3719
4354
  return {
@@ -3731,7 +4366,7 @@ function brandCheckResult(check) {
3731
4366
  return {
3732
4367
  name: "brand",
3733
4368
  severity: "warn",
3734
- message: `brand "${brand}" \uC640 import(${check.imports.join(", ")})\uAC00 \uB2E4\uB985\uB2C8\uB2E4${suffix}`
4369
+ message: `brand "${brand}" \uC640 import(${check.imports.join(", ")})\uAC00 \uB2E4\uB985\uB2C8\uB2E4${via}${suffix}`
3735
4370
  };
3736
4371
  }
3737
4372
  }
@@ -3876,12 +4511,11 @@ import chalk9 from "chalk";
3876
4511
  import path12 from "path";
3877
4512
 
3878
4513
  // src/theme/theme-add.ts
3879
- import { accessSync, constants, existsSync as existsSync3, readFileSync as readFileSync4, realpathSync as realpathSync2, statSync as statSync2, unlinkSync, writeFileSync } from "fs";
4514
+ import { accessSync, constants, existsSync as existsSync3, readFileSync as readFileSync4, realpathSync as realpathSync2, unlinkSync, writeFileSync } from "fs";
3880
4515
  import path11 from "path";
3881
4516
  var TOKENS_DEPENDENCY_RANGE = `^${TOKENS_DEPENDENCY_MIN_VERSION}`;
3882
4517
  var TAILWIND3_BASE_IMPORTS = [`${TOKENS_PACKAGE}/css`, `${TOKENS_PACKAGE}/css/shadcn`];
3883
4518
  var THEME_MIN_VERSION = "1.3.0";
3884
- var COMPONENT_TAILWIND_CSS_MIN_VERSION = "1.4.0";
3885
4519
  function readText(file) {
3886
4520
  return existsSync3(file) ? readFileSync4(file, "utf8") : null;
3887
4521
  }
@@ -3980,13 +4614,6 @@ function realPathInside(baseDir, file) {
3980
4614
  const inside = relPath !== "" && !relPath.startsWith("..") && !path11.isAbsolute(relPath);
3981
4615
  return { inside, realPath };
3982
4616
  }
3983
- function isFile2(file) {
3984
- try {
3985
- return statSync2(file).isFile();
3986
- } catch {
3987
- return false;
3988
- }
3989
- }
3990
4617
  function isStylesheet(realPath) {
3991
4618
  return path11.extname(realPath).toLowerCase() === ".css";
3992
4619
  }
@@ -4062,16 +4689,11 @@ function planThemeAdd(baseDirInput, brand) {
4062
4689
  const deferredComponentImports = [];
4063
4690
  if (tailwind4 && pkg !== void 0) {
4064
4691
  for (const n of TAILWIND4_COMPONENT_PACKAGES) {
4065
- if (hasDependency(pkg, n) !== void 0) {
4066
- componentImports.push(n);
4067
- continue;
4068
- }
4069
- if (declaredDependency(baseDir, pkg, n, rootPkg)?.source !== "root") continue;
4070
- const installed2 = findInstalledPackage(baseDir, n);
4071
- if (installed2 !== void 0 && isFile2(path11.join(installed2.dir, "tailwind.css"))) {
4072
- componentImports.push(n);
4073
- } else {
4074
- deferredComponentImports.push(installed2 === void 0 ? { name: n } : { name: n, installedVersion: installed2.version ?? "?" });
4692
+ const r = componentCssResolution(baseDir, pkg, n);
4693
+ if (r.kind === "app" || r.kind === "root-ok") componentImports.push(n);
4694
+ else if (r.kind === "root-not-installed") deferredComponentImports.push({ name: n });
4695
+ else if (r.kind === "root-old" || r.kind === "root-missing-file") {
4696
+ deferredComponentImports.push({ name: n, installedVersion: r.installedVersion });
4075
4697
  }
4076
4698
  }
4077
4699
  }
@@ -4487,13 +5109,7 @@ function renderThemeAdd(plan, written) {
4487
5109
  );
4488
5110
  }
4489
5111
  for (const d of css?.deferredComponentImports ?? []) {
4490
- const line = `@import "${d.name}/tailwind.css";`;
4491
- const current = d.installedVersion !== void 0 && d.installedVersion !== "?" && (compareExactVersions(d.installedVersion, COMPONENT_TAILWIND_CSS_MIN_VERSION) ?? -1) >= 0;
4492
- lines.push(
4493
- chalk9.yellow(
4494
- d.installedVersion === void 0 ? ` ! ${d.name} \uAC00 \uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uB8E8\uD2B8\uC5D0 \uC120\uC5B8\uB410\uC9C0\uB9CC \uC124\uCE58\uB418\uC9C0 \uC54A\uC544 ${line} \uB97C \uB123\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. \uC124\uCE58(${plan.installCommand}) \uB4A4 theme add \uB97C \uB2E4\uC2DC \uC2E4\uD589\uD558\uAC70\uB098 \uC9C1\uC811 \uB123\uC73C\uC138\uC694.` : current ? ` ! \uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uB8E8\uD2B8\uC5D0 \uC120\uC5B8\uB41C ${d.name} \uC758 \uC124\uCE58\uBCF8(${d.installedVersion})\uC5D0 tailwind.css \uAC00 \uC5C6\uC5B4 ${line} \uB97C \uB123\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. \uC124\uCE58\uAC00 \uC190\uC0C1\uB410\uC744 \uC218 \uC788\uC73C\uB2C8 \uB2E4\uC2DC \uC124\uCE58(${plan.installCommand}) \uB4A4 theme add \uB97C \uB2E4\uC2DC \uC2E4\uD589\uD558\uAC70\uB098 \uC9C1\uC811 \uB123\uC73C\uC138\uC694.` : ` ! \uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uB8E8\uD2B8\uC5D0 \uC120\uC5B8\uB41C ${d.name} \uC758 \uC124\uCE58\uBCF8(${d.installedVersion === "?" ? "\uBC84\uC804 \uBAA8\uB984" : d.installedVersion})\uC5D0 tailwind.css \uAC00 \uC5C6\uC5B4(${COMPONENT_TAILWIND_CSS_MIN_VERSION} \uBD80\uD130 \uC81C\uACF5) ${line} \uB97C \uB123\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. ${COMPONENT_TAILWIND_CSS_MIN_VERSION} \uC774\uC0C1\uC73C\uB85C \uC62C\uB9B0 \uB4A4 theme add \uB97C \uB2E4\uC2DC \uC2E4\uD589\uD558\uAC70\uB098 \uC9C1\uC811 \uB123\uC73C\uC138\uC694.`
4495
- )
4496
- );
5112
+ lines.push(chalk9.yellow(` ! ${deferredComponentImportReason(d, plan.installCommand)}`));
4497
5113
  }
4498
5114
  if (css && css.otherBrands.length > 0) {
4499
5115
  lines.push(
@@ -4551,13 +5167,14 @@ function renderThemeAdd(plan, written) {
4551
5167
  );
4552
5168
  }
4553
5169
  for (const t of tw.contentMissing) {
4554
- lines.push(
4555
- chalk9.yellow(
4556
- ` ! content \uAC00 ${t.label} \uB97C \uB36E\uC9C0 ${tw.contentUnknown ? "\uC54A\uB294 \uAC83\uC73C\uB85C \uBCF4\uC785\uB2C8\uB2E4(\uC815\uC801 \uD310\uB3C5)" : "\uC54A\uC2B5\uB2C8\uB2E4"}. \uB123\uC73C\uC138\uC694: "${t.suggest}"`
4557
- )
4558
- );
5170
+ const not = tw.contentUnknown ? "\uC54A\uB294 \uAC83\uC73C\uB85C \uBCF4\uC785\uB2C8\uB2E4(\uC815\uC801 \uD310\uB3C5)" : "\uC54A\uC2B5\uB2C8\uB2E4";
5171
+ if (t.pnp?.state === "noNodeModules") lines.push(chalk9.yellow(` ! content \uAC00 ${t.label} \uB97C Plug'n'Play \uC5D0\uC11C \uC2A4\uCE94\uB418\uB294 \uACBD\uB85C\uB85C \uB36E\uC9C0 ${not}`));
5172
+ else if (t.pnp?.state === "rootOnly") lines.push(chalk9.yellow(` ! ${t.label} \uAC00 ${PNP_ROOT_ONLY_NOTE} \u2192 ${CONTENT_PNP_ROOT_ONLY_ACTION}`));
5173
+ else lines.push(chalk9.yellow(` ! content \uAC00 ${t.label} \uB97C \uB36E\uC9C0 ${not}. \uB123\uC73C\uC138\uC694: "${t.suggest}"`));
4559
5174
  }
4560
5175
  if (tw.contentMissing.some((t) => t.suggest.startsWith("../"))) lines.push(chalk9.gray(` ${CONTENT_PARENT_PATH_NOTE}`));
5176
+ const pnpNote = contentPnpNoteFor(tw.contentMissing);
5177
+ if (pnpNote !== void 0) lines.push(chalk9.gray(` ${pnpNote}`));
4561
5178
  }
4562
5179
  const act = plan.activation;
4563
5180
  lines.push("", chalk9.bold(`\uBE0C\uB79C\uB4DC \uCF1C\uAE30 (ThemeProvider \uB294 ${THEME_PACKAGE} ${THEME_MIN_VERSION} \uC774\uC0C1)`));
@@ -4639,7 +5256,7 @@ function registerThemeCommand(program2) {
4639
5256
  import chalk11 from "chalk";
4640
5257
 
4641
5258
  // ../axis-registry-core/src/registry/schema.ts
4642
- import { createHash } from "crypto";
5259
+ import { createHash as createHash2 } from "crypto";
4643
5260
  var REGISTRY_NAME_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
4644
5261
  var REGISTRY_NAME_MAX_LENGTH = 64;
4645
5262
  function isValidRegistryName(name) {
@@ -4772,8 +5389,8 @@ function validateRegistryIndex(data, where = "index.json") {
4772
5389
  if (!isValidRegistryName(raw.name)) throw new Error(`${at}: name \uC774 slug \uADDC\uCE59\uC5D0 \uB9DE\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4`);
4773
5390
  if (seen.has(raw.name)) throw new Error(`${at}: name '${raw.name}' \uAC00 \uC911\uBCF5\uC785\uB2C8\uB2E4`);
4774
5391
  seen.add(raw.name);
4775
- const sha256 = optionalString(raw, "sha256", at);
4776
- if (sha256 !== void 0 && !/^[0-9a-f]{64}$/.test(sha256)) {
5392
+ const sha2562 = optionalString(raw, "sha256", at);
5393
+ if (sha2562 !== void 0 && !/^[0-9a-f]{64}$/.test(sha2562)) {
4777
5394
  throw new Error(`${at}: sha256 \uD615\uC2DD\uC774 \uC544\uB2D9\uB2C8\uB2E4`);
4778
5395
  }
4779
5396
  return {
@@ -4781,7 +5398,7 @@ function validateRegistryIndex(data, where = "index.json") {
4781
5398
  type: requireType(raw, at),
4782
5399
  title: optionalString(raw, "title", at),
4783
5400
  description: optionalString(raw, "description", at),
4784
- ...sha256 !== void 0 ? { sha256 } : {}
5401
+ ...sha2562 !== void 0 ? { sha256: sha2562 } : {}
4785
5402
  };
4786
5403
  });
4787
5404
  return {
@@ -4829,7 +5446,7 @@ function validateRegistryItem(data, expectedName, where = `${expectedName}.json`
4829
5446
  };
4830
5447
  }
4831
5448
  function sha256Hex(text) {
4832
- return createHash("sha256").update(text, "utf8").digest("hex");
5449
+ return createHash2("sha256").update(text, "utf8").digest("hex");
4833
5450
  }
4834
5451
  function checkItemSha256(item, entry, where = `${item.name}.json`) {
4835
5452
  if (entry.sha256 === void 0) return;