@axis-ds/cli 1.7.8 → 1.7.10

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
@@ -21,20 +21,24 @@ import {
21
21
  findPnpUnpluggedPackages,
22
22
  globalCssSelectionNote,
23
23
  hasDependency,
24
+ installCommandPhrase,
24
25
  isPlainObject,
25
26
  isPnpProject,
26
27
  outsideCssPackageResolution,
28
+ pnpComponentSourceHidden,
27
29
  pnpProjectRoot,
28
30
  pnpRootOnlyDependency,
31
+ pnpUnplugSetupPhrase,
29
32
  projectFileExists,
30
33
  resolveBaseDir,
31
34
  rootDeclarationsAllowed,
32
35
  runScriptCommand,
33
36
  selectGlobalCss,
37
+ tailwindConfigImportResolution,
34
38
  tokensCssResolution,
35
39
  workspaceRootPackage,
36
40
  workspaceRunCommand
37
- } from "./chunk-C2T7NVDG.js";
41
+ } from "./chunk-EAUM5S4O.js";
38
42
  import {
39
43
  V0Client
40
44
  } from "./chunk-2PNCUPCG.js";
@@ -1849,11 +1853,199 @@ import ora3 from "ora";
1849
1853
 
1850
1854
  // src/template/post-install.ts
1851
1855
  import fs6 from "fs-extra";
1852
- import path6 from "path";
1853
1856
  import chalk4 from "chalk";
1857
+
1858
+ // ../axis-registry-core/src/template/apply-files.ts
1859
+ import { existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, realpathSync, rmdirSync, unlinkSync, writeFileSync } from "fs";
1860
+ import path6 from "path";
1861
+ var TemplatePathError = class extends Error {
1862
+ constructor(relPath, reason) {
1863
+ super(`\uD15C\uD50C\uB9BF \uACBD\uB85C '${relPath}' \uAC00 \uB300\uC0C1 \uB514\uB809\uD130\uB9AC \uBC16\uC744 \uAC00\uB9AC\uCF1C(${reason}) \uC911\uB2E8\uD588\uC2B5\uB2C8\uB2E4. \uC544\uBB34 \uD30C\uC77C\uB3C4 \uBC14\uAFB8\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4`);
1864
+ this.relPath = relPath;
1865
+ this.reason = reason;
1866
+ this.name = "TemplatePathError";
1867
+ }
1868
+ };
1869
+ function realpathOfExisting(p) {
1870
+ const rest = [];
1871
+ let cur = p;
1872
+ for (; ; ) {
1873
+ try {
1874
+ lstatSync(cur);
1875
+ break;
1876
+ } catch {
1877
+ const parent = path6.dirname(cur);
1878
+ if (parent === cur) break;
1879
+ rest.unshift(path6.basename(cur));
1880
+ cur = parent;
1881
+ }
1882
+ }
1883
+ try {
1884
+ return path6.join(realpathSync(cur), ...rest);
1885
+ } catch {
1886
+ return void 0;
1887
+ }
1888
+ }
1889
+ function isInside(root, target) {
1890
+ const rel3 = path6.relative(root, target);
1891
+ return rel3 !== "" && !rel3.startsWith("..") && !path6.isAbsolute(rel3);
1892
+ }
1893
+ function resolveTemplatePath(baseDir, relPath) {
1894
+ if (typeof relPath !== "string" || relPath === "" || relPath.includes("\0")) {
1895
+ throw new TemplatePathError(String(relPath), "\uBE48 \uACBD\uB85C \uB610\uB294 \uC798\uBABB\uB41C \uBB38\uC790");
1896
+ }
1897
+ if (path6.isAbsolute(relPath) || path6.win32.isAbsolute(relPath)) throw new TemplatePathError(relPath, "\uC808\uB300 \uACBD\uB85C");
1898
+ const base = path6.resolve(baseDir);
1899
+ const dest = path6.resolve(base, relPath);
1900
+ if (!isInside(base, dest)) throw new TemplatePathError(relPath, "\uC0C1\uC704 \uB514\uB809\uD130\uB9AC\uB85C \uB098\uAC10");
1901
+ const baseReal = realpathOfExisting(base);
1902
+ const destReal = realpathOfExisting(dest);
1903
+ if (!baseReal || !destReal || !isInside(baseReal, destReal)) {
1904
+ throw new TemplatePathError(relPath, "\uC2EC\uBCFC\uB9AD \uB9C1\uD06C\uAC00 \uB300\uC0C1 \uB514\uB809\uD130\uB9AC \uBC16\uC744 \uAC00\uB9AC\uD0B4");
1905
+ }
1906
+ return dest;
1907
+ }
1908
+ function assertTemplatePaths(baseDir, relPaths) {
1909
+ for (const p of relPaths) resolveTemplatePath(baseDir, p);
1910
+ }
1911
+ var PACKAGE_JSON_MERGED_MAPS = [
1912
+ "scripts",
1913
+ "dependencies",
1914
+ "devDependencies",
1915
+ "peerDependencies",
1916
+ "optionalDependencies"
1917
+ ];
1918
+ function isPlainObject2(v) {
1919
+ return typeof v === "object" && v !== null && !Array.isArray(v);
1920
+ }
1921
+ function parseObject(text) {
1922
+ try {
1923
+ const v = JSON.parse(text);
1924
+ return isPlainObject2(v) ? v : void 0;
1925
+ } catch {
1926
+ return void 0;
1927
+ }
1928
+ }
1929
+ function mergePackageJson(user, template) {
1930
+ const maps = new Set(PACKAGE_JSON_MERGED_MAPS);
1931
+ const out = {};
1932
+ for (const [key, value] of Object.entries(user)) {
1933
+ const tpl = template[key];
1934
+ if (maps.has(key) && isPlainObject2(tpl)) {
1935
+ out[key] = isPlainObject2(value) ? { ...value, ...tpl } : tpl;
1936
+ } else {
1937
+ out[key] = value;
1938
+ }
1939
+ }
1940
+ for (const [key, value] of Object.entries(template)) {
1941
+ if (!(key in out)) out[key] = value;
1942
+ }
1943
+ return out;
1944
+ }
1945
+ function mergeAxisConfigJson(user, template) {
1946
+ return { ...user, ...template };
1947
+ }
1948
+ function detectJsonIndent(text) {
1949
+ const m = /^([ \t]+)\S/m.exec(text);
1950
+ if (!m) return 2;
1951
+ return m[1].startsWith(" ") ? " " : m[1].length;
1952
+ }
1953
+ function serializeLike(before, value) {
1954
+ const crlf = before.includes("\r\n");
1955
+ const trailing = /\r?\n$/.test(before);
1956
+ let text = JSON.stringify(value, null, detectJsonIndent(before));
1957
+ if (trailing) text += "\n";
1958
+ return crlf ? text.replace(/\n/g, "\r\n") : text;
1959
+ }
1960
+ var MERGERS = {
1961
+ "package.json": mergePackageJson,
1962
+ "axis.config.json": mergeAxisConfigJson
1963
+ };
1964
+ function planTemplateFileContent(relPath, templateContent, before) {
1965
+ if (before === void 0) return { action: "created", content: templateContent };
1966
+ const merger = MERGERS[relPath.replace(/^\.\//, "")];
1967
+ if (!merger) return { action: "overwritten", content: templateContent };
1968
+ const user = parseObject(before);
1969
+ const template = parseObject(templateContent);
1970
+ if (!user || !template) {
1971
+ return {
1972
+ action: "overwritten",
1973
+ content: templateContent,
1974
+ note: `\uAE30\uC874 ${relPath} \uC744 JSON \uAC1D\uCCB4\uB85C \uC77D\uC744 \uC218 \uC5C6\uC5B4 \uD15C\uD50C\uB9BF \uB0B4\uC6A9\uC73C\uB85C \uB36E\uC5B4\uC501\uB2C8\uB2E4`
1975
+ };
1976
+ }
1977
+ return { action: "merged", content: serializeLike(before, merger(user, template)) };
1978
+ }
1979
+ function planTemplateFiles(baseDir, files, extraPaths = []) {
1980
+ const dests = files.map((file) => resolveTemplatePath(baseDir, file.path));
1981
+ assertTemplatePaths(baseDir, extraPaths);
1982
+ return files.map((file, i) => {
1983
+ const dest = dests[i];
1984
+ const before = existsSync(dest) ? readFileSync(dest, "utf8") : void 0;
1985
+ return { path: file.path, dest, before, ...planTemplateFileContent(file.path, file.content, before) };
1986
+ });
1987
+ }
1988
+ var TemplateApplyError = class extends Error {
1989
+ constructor(message, restored, unrestored) {
1990
+ super(message);
1991
+ this.restored = restored;
1992
+ this.unrestored = unrestored;
1993
+ this.name = "TemplateApplyError";
1994
+ }
1995
+ };
1996
+ function writeTemplateFiles(plan) {
1997
+ const done = [];
1998
+ const madeDirs = [];
1999
+ try {
2000
+ for (const item of plan) {
2001
+ const dir = path6.dirname(item.dest);
2002
+ if (!existsSync(dir)) {
2003
+ const fresh = [];
2004
+ for (let d = dir; !existsSync(d); d = path6.dirname(d)) fresh.unshift(d);
2005
+ mkdirSync(dir, { recursive: true });
2006
+ madeDirs.push(...fresh);
2007
+ }
2008
+ writeFileSync(item.dest, item.content);
2009
+ done.push(item);
2010
+ }
2011
+ } catch (err) {
2012
+ const restored = [];
2013
+ const unrestored = [];
2014
+ const failed = plan[done.length];
2015
+ const targets = failed ? [...done, failed] : done;
2016
+ for (const item of targets.reverse()) {
2017
+ try {
2018
+ if (item.before === void 0) {
2019
+ if (existsSync(item.dest)) unlinkSync(item.dest);
2020
+ } else {
2021
+ writeFileSync(item.dest, item.before);
2022
+ }
2023
+ restored.push(item.path);
2024
+ } catch {
2025
+ unrestored.push(item.path);
2026
+ }
2027
+ }
2028
+ for (const d of madeDirs.reverse()) {
2029
+ try {
2030
+ if (existsSync(d) && readdirSync(d).length === 0) rmdirSync(d);
2031
+ } catch {
2032
+ }
2033
+ }
2034
+ const reason = err instanceof Error ? err.message : String(err);
2035
+ const tail = unrestored.length > 0 ? ` \uB418\uB3CC\uB9AC\uC9C0 \uBABB\uD55C \uD30C\uC77C: ${unrestored.join(", ")}` : "";
2036
+ throw new TemplateApplyError(
2037
+ `\uD15C\uD50C\uB9BF \uD30C\uC77C\uC744 \uC4F0\uB294 \uB3C4\uC911 \uC2E4\uD328\uD574 \uAC74\uB4DC\uB9B0 \uD30C\uC77C ${restored.length}\uAC1C\uB97C \uC6D0\uB798\uB300\uB85C \uB418\uB3CC\uB838\uC2B5\uB2C8\uB2E4(${reason}).${tail}`,
2038
+ restored.reverse(),
2039
+ unrestored
2040
+ );
2041
+ }
2042
+ }
2043
+
2044
+ // src/template/post-install.ts
1854
2045
  async function runPostInstall(patches, baseDir, dryRun = false) {
2046
+ assertTemplatePaths(baseDir, patches.map((p) => p.file));
1855
2047
  for (const patch of patches) {
1856
- const filePath = path6.resolve(baseDir, patch.file);
2048
+ const filePath = resolveTemplatePath(baseDir, patch.file);
1857
2049
  if (dryRun) {
1858
2050
  console.log(chalk4.gray(` [dry-run] patch ${patch.type}: ${patch.file}`));
1859
2051
  continue;
@@ -1940,15 +2132,12 @@ async function readAxisConfig(baseDir) {
1940
2132
  }
1941
2133
 
1942
2134
  // ../axis-registry-core/src/template/tailwind-core.ts
1943
- import { existsSync, lstatSync, readdirSync, readFileSync, realpathSync, statSync } from "fs";
2135
+ import { existsSync as existsSync2, lstatSync as lstatSync2, readdirSync as readdirSync2, readFileSync as readFileSync2, realpathSync as realpathSync2, statSync } from "fs";
1944
2136
  import { basename, dirname, extname, isAbsolute, join, relative, resolve, sep } from "path";
1945
2137
  function declaredRange(baseDir, pkg, name) {
1946
2138
  return declaredDependency(baseDir, pkg, name)?.range;
1947
2139
  }
1948
- function declaredRangeForCheck(baseDir, pkg, name) {
1949
- return declaredDependency(baseDir, pkg, name, void 0, { appOnlyInPnp: true })?.range;
1950
- }
1951
- function isPlainObject2(value) {
2140
+ function isPlainObject3(value) {
1952
2141
  return typeof value === "object" && value !== null && !Array.isArray(value);
1953
2142
  }
1954
2143
  var VERSION = String.raw`v?(\d+)(?:\.(\d+|[xX*]))?(?:\.(\d+|[xX*]))?(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?`;
@@ -2125,10 +2314,10 @@ function regularFile(file) {
2125
2314
  }
2126
2315
  function expandGlobalCss(baseDirInput, entryPath, entryRel, entryCssDir) {
2127
2316
  const baseDir = resolveBaseDir(baseDirInput);
2128
- const entry = readFileSync(entryPath, "utf8");
2317
+ const entry = readFileSync2(entryPath, "utf8");
2129
2318
  let entryReal = entryPath;
2130
2319
  try {
2131
- entryReal = realpathSync(entryPath);
2320
+ entryReal = realpathSync2(entryPath);
2132
2321
  } catch {
2133
2322
  }
2134
2323
  const raws = /* @__PURE__ */ new Map([[entryReal, entry]]);
@@ -2185,7 +2374,7 @@ function walkRelativeCssImports(baseDir, entryReal, raws, limit, includeConditio
2185
2374
  if (target === void 0) continue;
2186
2375
  let real;
2187
2376
  try {
2188
- real = realpathSync(target);
2377
+ real = realpathSync2(target);
2189
2378
  } catch {
2190
2379
  continue;
2191
2380
  }
@@ -2198,7 +2387,7 @@ function walkRelativeCssImports(baseDir, entryReal, raws, limit, includeConditio
2198
2387
  if (rel3 === "" || rel3 === ".." || rel3.startsWith(`..${sep}`) || isAbsolute(rel3)) continue;
2199
2388
  if (!raws.has(real)) {
2200
2389
  try {
2201
- raws.set(real, readFileSync(real, "utf8"));
2390
+ raws.set(real, readFileSync2(real, "utf8"));
2202
2391
  } catch {
2203
2392
  continue;
2204
2393
  }
@@ -2228,10 +2417,10 @@ function findLayoutTokensCssImport(baseDirInput) {
2228
2417
  const baseDir = resolveBaseDir(baseDirInput);
2229
2418
  for (const candidate of ROOT_LAYOUT_FILES) {
2230
2419
  const file = join(baseDir, candidate);
2231
- if (!existsSync(file)) continue;
2420
+ if (!existsSync2(file)) continue;
2232
2421
  let text;
2233
2422
  try {
2234
- text = readFileSync(file, "utf8");
2423
+ text = readFileSync2(file, "utf8");
2235
2424
  } catch {
2236
2425
  continue;
2237
2426
  }
@@ -2273,18 +2462,19 @@ function packageNameOfSpec(spec) {
2273
2462
  function displayRel(baseDir, p) {
2274
2463
  return relative(baseDir, p).split(sep).join("/");
2275
2464
  }
2276
- function packageLineShadowIssue(baseDir, expanded, origin, spec) {
2465
+ function packageLineShadowIssue(baseDir, expanded, origin, spec, opts = {}) {
2277
2466
  const name = packageNameOfSpec(spec);
2278
2467
  const lineDir = dirname(origin.path);
2279
2468
  const others = () => [...new Set(expanded.files.map((f) => dirname(f.path)))].filter((d) => d !== lineDir);
2280
2469
  const r = cssPackageLineResolution(baseDir, lineDir, spec, others);
2281
2470
  const head = `${spec} import \uAC00 \uC788\uC9C0\uB9CC \uADF8 \uC904\uC774 \uC788\uB294 \uD30C\uC77C \uC704\uCE58\uC5D0\uC11C`;
2282
2471
  const label = (pkgDir, version) => `${displayRel(baseDir, pkgDir)}(${version ?? "\uBC84\uC804 \uBAA8\uB984"})`;
2472
+ if (opts.tailwind3 === true && r.kind !== "shadow-not-exported") return void 0;
2283
2473
  switch (r.kind) {
2284
2474
  case "ok":
2285
2475
  return void 0;
2286
2476
  case "shadow-not-exported": {
2287
- const current = r.version !== void 0 && (compareExactVersions(r.version, TAILWIND4_MIN_AXIS_VERSION) ?? -1) >= 0;
2477
+ const current = opts.tailwind3 === true || r.version !== void 0 && (compareExactVersions(r.version, TAILWIND4_MIN_AXIS_VERSION) ?? -1) >= 0;
2288
2478
  const todo = current ? "\uB2E4\uC2DC \uC124\uCE58\uD558\uC138\uC694" : `${TAILWIND4_MIN_AXIS_VERSION} \uC774\uC0C1\uC73C\uB85C \uB9DE\uCD94\uC138\uC694`;
2289
2479
  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
2480
  }
@@ -2327,13 +2517,20 @@ function judgeGlobalsCss(baseDir, selection, candidate, expanded) {
2327
2517
  const origin = evidenceOrigin(expanded, (f) => findTokensCssImport(f) === imported);
2328
2518
  via = cssImportViaNote(viaFiles([origin]));
2329
2519
  const tailwind4 = (detectTailwind(baseDir, pkg).major ?? 0) >= 4;
2330
- const issue = tailwind4 && origin !== void 0 && !isOutsideEntry(origin) ? tokensCssUnresolvedIssue(
2520
+ const inside = origin !== void 0 && !isOutsideEntry(origin);
2521
+ const issue = tailwind4 && inside ? tokensCssUnresolvedIssue(
2331
2522
  baseDir,
2332
2523
  pkg,
2333
2524
  imported,
2334
2525
  void 0,
2335
2526
  () => packageLineShadowIssue(baseDir, expanded, origin, imported)
2336
- ) : tokensCssUnresolvedIssue(baseDir, pkg, imported, origin !== void 0 ? origin.cssDir : outsideCssDir(selection));
2527
+ ) : tokensCssUnresolvedIssue(
2528
+ baseDir,
2529
+ pkg,
2530
+ imported,
2531
+ origin !== void 0 ? origin.cssDir : outsideCssDir(selection),
2532
+ inside ? () => packageLineShadowIssue(baseDir, expanded, origin, imported, { tailwind3: true }) : void 0
2533
+ );
2337
2534
  if (issue !== void 0) unresolved = `${candidate}\uC5D0 ${issue}`;
2338
2535
  else pass = `${candidate}\uC5D0 AXIS CSS \uBCC0\uC218\uAC00 \uC788\uC2B5\uB2C8\uB2E4 (${imported} import)`;
2339
2536
  } else if (AXIS_VARIABLE_DEFINITION.test(stripCssComments(expanded.evidence))) {
@@ -2537,6 +2734,8 @@ function stripJsComments(src) {
2537
2734
  }
2538
2735
  var TOKENS_TAILWIND3_PRESET = "@axis-ds/tokens/tailwind";
2539
2736
  var PRESET_REFERENCE = /(?:\brequire\s*\(\s*|\bimport\s*\(\s*|\bfrom\s*|\bimport\s+)(["'])@axis-ds\/tokens\/tailwind\1/;
2737
+ var PRESET_REQUIRE_REFERENCE = /\brequire\s*\(\s*(["'])@axis-ds\/tokens\/tailwind\1/;
2738
+ var PRESET_IMPORT_REFERENCE = /(?:\bimport\s*\(\s*|\bfrom\s*|\bimport\s+)(["'])@axis-ds\/tokens\/tailwind\1/;
2540
2739
  function hasTokensPresetReference(source) {
2541
2740
  return PRESET_REFERENCE.test(stripJsComments(source));
2542
2741
  }
@@ -2564,7 +2763,7 @@ function hasBareCjsPresetRequire(code) {
2564
2763
  function isCommonJsConfig(file, source) {
2565
2764
  return extname(file) === ".cjs" || /\bmodule\.exports\b/.test(source);
2566
2765
  }
2567
- function presetTokensUnresolvedMessage(baseDir, pkg, file, bareCjs) {
2766
+ function presetTokensUnresolvedMessage(baseDir, pkg, file, bareCjs, code) {
2568
2767
  const r = tokensCssResolution(baseDir, pkg, TOKENS_PACKAGE_NAME);
2569
2768
  const head = `${file}\uC5D0 AXIS preset \uCC38\uC870\uAC00 \uC788\uC9C0\uB9CC ${TOKENS_PACKAGE_NAME} \uAC00`;
2570
2769
  if (r.kind === "not-installed") {
@@ -2573,6 +2772,14 @@ function presetTokensUnresolvedMessage(baseDir, pkg, file, bareCjs) {
2573
2772
  if (r.kind === "pnp-root-only" && !bareCjs) {
2574
2773
  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
2774
  }
2775
+ const e = tailwindConfigImportResolution(baseDir, TOKENS_TAILWIND3_PRESET, {
2776
+ require: PRESET_REQUIRE_REFERENCE.test(code),
2777
+ import: PRESET_IMPORT_REFERENCE.test(code)
2778
+ });
2779
+ if (e.kind === "not-exported") {
2780
+ const label = `${displayRel(baseDir, e.pkgDir)}(${e.version ?? "\uBC84\uC804 \uBAA8\uB984"})`;
2781
+ return `${file}\uC5D0 AXIS preset \uCC38\uC870\uAC00 \uC788\uC9C0\uB9CC \uBA3C\uC800 \uC7A1\uD788\uB294 ${label}\uAC00 ${e.subpath} \uB97C \uB0B4\uBCF4\uB0B4\uC9C0 \uC54A\uC544 \uD574\uC11D\uB418\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4 \u2192 \uADF8 node_modules \uC758 ${TOKENS_PACKAGE_NAME} \uB97C \uC9C0\uC6B0\uAC70\uB098 \uB2E4\uC2DC \uC124\uCE58\uD558\uC138\uC694`;
2782
+ }
2576
2783
  return void 0;
2577
2784
  }
2578
2785
  function packageVersionGate(baseDirInput, pkg, name, min, options = {}) {
@@ -2604,8 +2811,8 @@ function versionGateLabel(gate) {
2604
2811
  }
2605
2812
  function readPackageJson(baseDir) {
2606
2813
  try {
2607
- const parsed = JSON.parse(readFileSync(join(baseDir, "package.json"), "utf8"));
2608
- return isPlainObject2(parsed) ? parsed : void 0;
2814
+ const parsed = JSON.parse(readFileSync2(join(baseDir, "package.json"), "utf8"));
2815
+ return isPlainObject3(parsed) ? parsed : void 0;
2609
2816
  } catch {
2610
2817
  return void 0;
2611
2818
  }
@@ -2627,7 +2834,8 @@ function tailwind4Issues(input, pkg, versions, baseDir) {
2627
2834
  const r = resolutions.get(name);
2628
2835
  if (r.kind === "undeclared" || r.kind === "app-lockfile") continue;
2629
2836
  if (hasComponentTailwindImport(evidence, name) || hasComponentSource(evidence, name)) continue;
2630
- if (componentCssResolvable(r)) missing.push(name);
2837
+ if (r.kind === "app" && pnpComponentSourceHidden(baseDir, name, r.range)) unresolvedMissing.push(componentCssPnpMissingIssue(name));
2838
+ else if (componentCssResolvable(r)) missing.push(name);
2631
2839
  else unresolvedMissing.push(componentCssMissingIssue(baseDir, name, r));
2632
2840
  }
2633
2841
  if (missing.length > 0) {
@@ -2643,12 +2851,17 @@ function tailwind4Issues(input, pkg, versions, baseDir) {
2643
2851
  }
2644
2852
  for (const name of TAILWIND4_COMPONENT_PACKAGES) {
2645
2853
  if (!hasComponentTailwindImport(evidence, name)) continue;
2646
- const unresolved = componentCssPresentIssue(baseDir, name, resolutions.get(name));
2854
+ const r = resolutions.get(name);
2855
+ const unresolved = componentCssPresentIssue(baseDir, name, r);
2647
2856
  const spec = `${name}/tailwind.css`;
2648
2857
  if (unresolved !== void 0) {
2649
2858
  issues.push(unresolved);
2650
2859
  continue;
2651
2860
  }
2861
+ if (r.kind === "app" && pnpComponentSourceHidden(baseDir, name, r.range)) {
2862
+ issues.push(componentCssPnpPresentIssue(name));
2863
+ continue;
2864
+ }
2652
2865
  const shadow = input.lineIssue === void 0 ? false : input.lineIssue(spec);
2653
2866
  let lineProblem;
2654
2867
  if (shadow !== false) lineProblem = shadow;
@@ -2667,6 +2880,13 @@ function componentInstallPhrase(baseDir, name, range) {
2667
2880
  const g = dependencyInstallGuide(baseDir, name, range);
2668
2881
  return g.kind === "install-at-root" ? `\uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uB8E8\uD2B8\uC5D0\uC11C ${g.installCommand}` : g.installCommand;
2669
2882
  }
2883
+ var PNP_ZIP_SOURCE_NOTE = `Plug'n'Play \uC5D0\uC11C @source "./dist" \uAC00 .yarn/cache zip \uC548\uC744 \uAC00\uB9AC\uCF1C \uCEF4\uD3EC\uB10C\uD2B8 \uD074\uB798\uC2A4\uAC00 \uC0DD\uC131\uB418\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4`;
2884
+ function componentCssPnpMissingIssue(name) {
2885
+ return `${name} \uC758 tailwind.css \uB294 ${PNP_ZIP_SOURCE_NOTE} \u2192 ${pnpUnplugSetupPhrase(name)} \uB4A4 ${componentTailwindImportLine(name)}`;
2886
+ }
2887
+ function componentCssPnpPresentIssue(name) {
2888
+ return `${name}/tailwind.css import \uAC00 \uC788\uC9C0\uB9CC ${PNP_ZIP_SOURCE_NOTE} \u2192 ${pnpUnplugSetupPhrase(name)} \uD558\uC138\uC694`;
2889
+ }
2670
2890
  function componentCssMissingIssue(baseDir, name, r) {
2671
2891
  const line = componentTailwindImportLine(name);
2672
2892
  switch (r.kind) {
@@ -2763,12 +2983,12 @@ function checkTailwindSetup(baseDirInput) {
2763
2983
  }
2764
2984
  for (const file of TAILWIND_CONFIG_FILES) {
2765
2985
  const path17 = join(baseDir, file);
2766
- if (!existsSync(path17)) continue;
2767
- const content = readFileSync(path17, "utf8");
2986
+ if (!existsSync2(path17)) continue;
2987
+ const content = readFileSync2(path17, "utf8");
2768
2988
  if (hasTokensPresetReference(content)) {
2769
2989
  const code = stripJsComments(content);
2770
2990
  const bareCjs = isCommonJsConfig(file, code) && hasBareCjsPresetRequire(code);
2771
- const unresolved = presetTokensUnresolvedMessage(baseDir, pkg, file, bareCjs);
2991
+ const unresolved = presetTokensUnresolvedMessage(baseDir, pkg, file, bareCjs, code);
2772
2992
  if (unresolved !== void 0) return { name: "tailwind.config", severity: "warn", message: unresolved };
2773
2993
  if (bareCjs) {
2774
2994
  const gate = packageVersionGate(baseDir, pkg, "@axis-ds/tokens", TOKENS_CJS_PRESET_FIXED_VERSION, { appOnlyInPnp: true });
@@ -2801,8 +3021,8 @@ function checkTailwindSetup(baseDirInput) {
2801
3021
  }
2802
3022
  function readAxisConfigLike(baseDir) {
2803
3023
  try {
2804
- const parsed = JSON.parse(readFileSync(join(baseDir, "axis.config.json"), "utf8"));
2805
- return isPlainObject2(parsed) ? parsed : void 0;
3024
+ const parsed = JSON.parse(readFileSync2(join(baseDir, "axis.config.json"), "utf8"));
3025
+ return isPlainObject3(parsed) ? parsed : void 0;
2806
3026
  } catch {
2807
3027
  return void 0;
2808
3028
  }
@@ -2904,7 +3124,7 @@ function realpathPosix(p) {
2904
3124
  const tail = [];
2905
3125
  for (let i = 0; i < 64; i++) {
2906
3126
  try {
2907
- return [realpathSync(cur), ...tail].join(sep).split(sep).join("/");
3127
+ return [realpathSync2(cur), ...tail].join(sep).split(sep).join("/");
2908
3128
  } catch {
2909
3129
  const parent = dirname(cur);
2910
3130
  if (parent === cur) return void 0;
@@ -2960,15 +3180,15 @@ function relDirOf(baseDir, dir) {
2960
3180
  }
2961
3181
  function realDir(dir) {
2962
3182
  try {
2963
- return realpathSync(dir);
3183
+ return realpathSync2(dir);
2964
3184
  } catch {
2965
3185
  return void 0;
2966
3186
  }
2967
3187
  }
2968
3188
  function packageVersion(dir) {
2969
3189
  try {
2970
- const parsed = JSON.parse(readFileSync(join(dir, "package.json"), "utf8"));
2971
- return isPlainObject2(parsed) && typeof parsed.version === "string" ? parsed.version : void 0;
3190
+ const parsed = JSON.parse(readFileSync2(join(dir, "package.json"), "utf8"));
3191
+ return isPlainObject3(parsed) && typeof parsed.version === "string" ? parsed.version : void 0;
2972
3192
  } catch {
2973
3193
  return void 0;
2974
3194
  }
@@ -3003,7 +3223,7 @@ function packageContentTarget(baseDir, name, pkg) {
3003
3223
  let dir = dirname(resolve(found.dir, ...name.split("/").map(() => ".."), ".."));
3004
3224
  for (; ; ) {
3005
3225
  const candidate = join(dir, "node_modules", ...name.split("/"));
3006
- const rel3 = existsSync(join(candidate, "package.json")) ? relDirOf(baseDir, candidate) : void 0;
3226
+ const rel3 = existsSync2(join(candidate, "package.json")) ? relDirOf(baseDir, candidate) : void 0;
3007
3227
  if (rel3 !== void 0) {
3008
3228
  const candidateReal = realDir(candidate);
3009
3229
  if (candidateReal === real) alternates.push(`${rel3}/dist/index.js`);
@@ -3080,7 +3300,7 @@ function inspectTailwindContent(baseDirInput) {
3080
3300
  const pkg = readPackageJson(baseDir);
3081
3301
  const tailwind = detectTailwind(baseDir, pkg);
3082
3302
  if (tailwind.major !== void 0 && tailwind.major >= 4) return null;
3083
- const configFile = TAILWIND_CONFIG_FILES.find((f) => existsSync(join(baseDir, f)));
3303
+ const configFile = TAILWIND_CONFIG_FILES.find((f) => existsSync2(join(baseDir, f)));
3084
3304
  if (configFile === void 0) return null;
3085
3305
  const targets = [];
3086
3306
  const componentsDir = readAxisConfigLike(baseDir)?.componentsDir;
@@ -3094,7 +3314,7 @@ function inspectTailwindContent(baseDirInput) {
3094
3314
  }
3095
3315
  }
3096
3316
  if (targets.length === 0) return null;
3097
- const read = readTailwindContent(readFileSync(join(baseDir, configFile), "utf8"));
3317
+ const read = readTailwindContent(readFileSync2(join(baseDir, configFile), "utf8"));
3098
3318
  const globs = (read?.globs ?? []).filter((g) => !g.trim().startsWith("!"));
3099
3319
  return {
3100
3320
  configFile,
@@ -3162,7 +3382,7 @@ function componentsUseAnimation(baseDir, componentsDir) {
3162
3382
  const [dir, depth] = stack.pop();
3163
3383
  let names;
3164
3384
  try {
3165
- names = readdirSync(dir);
3385
+ names = readdirSync2(dir);
3166
3386
  } catch {
3167
3387
  continue;
3168
3388
  }
@@ -3171,7 +3391,7 @@ function componentsUseAnimation(baseDir, componentsDir) {
3171
3391
  const p = join(dir, name);
3172
3392
  let st;
3173
3393
  try {
3174
- st = lstatSync(p);
3394
+ st = lstatSync2(p);
3175
3395
  } catch {
3176
3396
  continue;
3177
3397
  }
@@ -3179,12 +3399,39 @@ function componentsUseAnimation(baseDir, componentsDir) {
3179
3399
  if (st.isDirectory()) {
3180
3400
  if (name !== "node_modules" && depth < ANIMATION_SCAN_DEPTH_LIMIT) stack.push([p, depth + 1]);
3181
3401
  } else if (st.isFile() && st.size <= ANIMATION_SCAN_FILE_BYTES && /\.(tsx|ts|jsx|js)$/.test(name)) {
3182
- if (/\banimate-(?:in|out)\b/.test(readFileSync(p, "utf8"))) return true;
3402
+ if (/\banimate-(?:in|out)\b/.test(readFileSync2(p, "utf8"))) return true;
3183
3403
  }
3184
3404
  }
3185
3405
  }
3186
3406
  return false;
3187
3407
  }
3408
+ function animationPluginProblem(baseDir, pkg, name, pnp) {
3409
+ const declared = declaredDependency(baseDir, pkg, name, void 0, { appOnlyInPnp: true });
3410
+ if (declared === void 0) {
3411
+ return pnpRootOnlyDependency(baseDir, pkg, name) !== void 0 ? { name, kind: "pnpRootOnly", why: `${name} \uAC00 ${PNP_ROOT_ONLY_NOTE}` } : { name, kind: "undeclared", why: `${name} \uC120\uC5B8 \uC5C6\uC74C` };
3412
+ }
3413
+ if (!pnp && findInstalledPackage(baseDir, name) === void 0) {
3414
+ return { name, kind: "notInstalled", why: `${name} \uBBF8\uC124\uCE58(\uC120\uC5B8\uB9CC \uC788\uC74C)`, root: declared.source === "root" };
3415
+ }
3416
+ return void 0;
3417
+ }
3418
+ function inspectTailwind4Animation(baseDirInput, pkgInput) {
3419
+ const baseDir = resolveBaseDir(baseDirInput);
3420
+ const pkg = pkgInput ?? readPackageJson(baseDir);
3421
+ const pnp = isPnpProject(baseDir);
3422
+ const selection = selectCheckGlobalCss(baseDir);
3423
+ const note = globalCssSelectionNote(selection);
3424
+ const expanded = selection.path !== void 0 && selection.rel !== void 0 ? expandGlobalCss(baseDir, selection.path, selection.rel, outsideCssDir(selection)) : void 0;
3425
+ const css = expanded !== void 0 ? stripCssComments(expanded.evidence) : "";
3426
+ const twAnimate = new RegExp(`@import\\s+(?:url\\(\\s*)?["']${ANIMATION_PLUGIN_TAILWIND4}["']`);
3427
+ const animatePlugin = new RegExp(`@plugin\\s+["']${ANIMATION_PLUGIN_TAILWIND3}["']`);
3428
+ const lines = [];
3429
+ if (twAnimate.test(css)) lines.push(ANIMATION_PLUGIN_TAILWIND4);
3430
+ if (animatePlugin.test(css)) lines.push(ANIMATION_PLUGIN_TAILWIND3);
3431
+ const via = expanded !== void 0 ? cssImportViaNote(viaFiles([evidenceOrigin(expanded, (f) => twAnimate.test(f)), evidenceOrigin(expanded, (f) => animatePlugin.test(f))])) : "";
3432
+ const problems = lines.map((name) => animationPluginProblem(baseDir, pkg, name, pnp)).filter((p) => p !== void 0);
3433
+ return { selection, file: selection.rel, note, via, lines, problems };
3434
+ }
3188
3435
  function checkAnimationPlugin(baseDirInput) {
3189
3436
  const baseDir = resolveBaseDir(baseDirInput);
3190
3437
  const pkg = readPackageJson(baseDir);
@@ -3195,25 +3442,8 @@ function checkAnimationPlugin(baseDirInput) {
3195
3442
  const by = declared ? "@axis-ds/ui-react \uC120\uC5B8" : "componentsDir \uC758 animate-in \uB958 \uD074\uB798\uC2A4";
3196
3443
  const tailwind = detectTailwind(baseDir, pkg);
3197
3444
  const pnp = isPnpProject(baseDir);
3198
- const pluginProblem = (name) => {
3199
- if (declaredRangeForCheck(baseDir, pkg, name) === void 0) {
3200
- return pnpRootOnlyDependency(baseDir, pkg, name) !== void 0 ? `${name} \uAC00 ${PNP_ROOT_ONLY_NOTE}` : `${name} \uC120\uC5B8 \uC5C6\uC74C`;
3201
- }
3202
- if (!pnp && findInstalledPackage(baseDir, name) === void 0) return `${name} \uBBF8\uC124\uCE58(\uC120\uC5B8\uB9CC \uC788\uC74C)`;
3203
- return void 0;
3204
- };
3205
3445
  if (tailwind.major !== void 0 && tailwind.major >= 4) {
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}["']`);
3213
- const lines = [];
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))])) : "";
3446
+ const { file, note, via, lines, problems } = inspectTailwind4Animation(baseDir, pkg);
3217
3447
  if (lines.length === 0) {
3218
3448
  return {
3219
3449
  name: "animation",
@@ -3221,7 +3451,6 @@ function checkAnimationPlugin(baseDirInput) {
3221
3451
  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}`
3222
3452
  };
3223
3453
  }
3224
- const problems = lines.map((name) => ({ name, why: pluginProblem(name) })).filter((x) => x.why !== void 0);
3225
3454
  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}` };
3226
3455
  return {
3227
3456
  name: "animation",
@@ -3229,10 +3458,10 @@ function checkAnimationPlugin(baseDirInput) {
3229
3458
  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}`
3230
3459
  };
3231
3460
  }
3232
- const configFile = TAILWIND_CONFIG_FILES.find((f) => existsSync(join(baseDir, f)));
3233
- const source = configFile !== void 0 ? stripJsComments(readFileSync(join(baseDir, configFile), "utf8")) : "";
3461
+ const configFile = TAILWIND_CONFIG_FILES.find((f) => existsSync2(join(baseDir, f)));
3462
+ const source = configFile !== void 0 ? stripJsComments(readFileSync2(join(baseDir, configFile), "utf8")) : "";
3234
3463
  const plugins = configFile !== void 0 ? readAnimationPluginUse(source) : "absent";
3235
- const pluginReason = pluginProblem(ANIMATION_PLUGIN_TAILWIND3);
3464
+ const pluginReason = animationPluginProblem(baseDir, pkg, ANIMATION_PLUGIN_TAILWIND3, pnp)?.why;
3236
3465
  if (plugins === "found" && pluginReason === void 0) {
3237
3466
  return { name: "animation", severity: "pass", message: `${configFile}\uC758 plugins \uC5D0 ${ANIMATION_PLUGIN_TAILWIND3} \uAC00 \uC788\uC2B5\uB2C8\uB2E4` };
3238
3467
  }
@@ -3318,6 +3547,12 @@ function splitTopLevel(body) {
3318
3547
  }
3319
3548
 
3320
3549
  // src/template/template-apply.ts
3550
+ var ACTION_LABEL = {
3551
+ created: "\uC0DD\uC131",
3552
+ overwritten: "\uB36E\uC5B4\uC4F0\uAE30",
3553
+ merged: "\uD569\uCE58\uAE30"
3554
+ };
3555
+ var MERGED_HINT = "\uAE30\uC874 \uD544\uB4DC\uB97C \uB450\uACE0 \uD15C\uD50C\uB9BF \uD0A4\uB97C \uD569\uCE68";
3321
3556
  function templateDependencyCommands(installCommand, detail) {
3322
3557
  const lines = [];
3323
3558
  const deps = detail.dependencies ?? {};
@@ -3372,18 +3607,21 @@ async function applyTemplate(slug, options) {
3372
3607
  for (const w of await templateApplyWarnings(baseDir, detail)) {
3373
3608
  console.log(chalk5.yellow(`! ${w}`));
3374
3609
  }
3375
- const conflicts = [];
3376
- for (const file of detail.files) {
3377
- const dest = path8.join(baseDir, file.path);
3378
- if (await fs8.pathExists(dest)) {
3379
- conflicts.push(file.path);
3380
- }
3610
+ let plan;
3611
+ try {
3612
+ plan = planTemplateFiles(baseDir, detail.files, (detail.postInstall ?? []).map((p) => p.file));
3613
+ } catch (err) {
3614
+ if (!(err instanceof TemplatePathError)) throw err;
3615
+ console.error(chalk5.red(err.message));
3616
+ process.exitCode = 1;
3617
+ return false;
3381
3618
  }
3619
+ const conflicts = plan.filter((p) => p.action !== "created");
3382
3620
  if (conflicts.length > 0 && !options.yes && !options.dryRun) {
3383
3621
  console.log(chalk5.yellow(`
3384
3622
  \uAE30\uC874 \uD30C\uC77C\uACFC \uCDA9\uB3CC\uD558\uB294 ${conflicts.length}\uAC1C \uD30C\uC77C:`));
3385
3623
  for (const c of conflicts) {
3386
- console.log(chalk5.gray(` - ${c}`));
3624
+ console.log(chalk5.gray(` - ${c.path}${c.action === "merged" ? ` (${MERGED_HINT})` : ""}`));
3387
3625
  }
3388
3626
  const interactive = options.interactive ?? isInteractive();
3389
3627
  if (!interactive) {
@@ -3391,7 +3629,7 @@ async function applyTemplate(slug, options) {
3391
3629
  `\uB36E\uC5B4\uC4F0\uB824\uBA74: axis template apply ${slug} -y`,
3392
3630
  `\uBBF8\uB9AC\uBCF4\uAE30: axis template apply ${slug} --dry-run`
3393
3631
  ]);
3394
- return;
3632
+ return false;
3395
3633
  }
3396
3634
  const { proceed } = await ask(
3397
3635
  {
@@ -3404,16 +3642,16 @@ async function applyTemplate(slug, options) {
3404
3642
  );
3405
3643
  if (!proceed) {
3406
3644
  console.log(chalk5.gray("\uCDE8\uC18C\uB418\uC5C8\uC2B5\uB2C8\uB2E4."));
3407
- return;
3645
+ return false;
3408
3646
  }
3409
3647
  }
3410
3648
  if (options.dryRun) {
3411
3649
  console.log(chalk5.blue("\n[\uBBF8\uB9AC\uBCF4\uAE30] \uC0DD\uC131\uB420 \uD30C\uC77C:"));
3412
- for (const file of detail.files) {
3413
- const dest = path8.join(baseDir, file.path);
3414
- const exists = conflicts.includes(file.path);
3415
- const label = exists ? chalk5.yellow("\uB36E\uC5B4\uC4F0\uAE30") : chalk5.green("\uC0DD\uC131");
3416
- console.log(` ${label} ${dest}`);
3650
+ for (const item of plan) {
3651
+ const text = ACTION_LABEL[item.action];
3652
+ const label = item.action === "created" ? chalk5.green(text) : chalk5.yellow(text);
3653
+ console.log(` ${label} ${item.dest}${item.action === "merged" ? chalk5.gray(` (${MERGED_HINT})`) : ""}`);
3654
+ if (item.note) console.log(chalk5.yellow(` ! ${item.note}`));
3417
3655
  }
3418
3656
  if (detail.postInstall?.length) {
3419
3657
  console.log(chalk5.blue("\n[\uBBF8\uB9AC\uBCF4\uAE30] postInstall \uD328\uCE58:"));
@@ -3421,15 +3659,21 @@ async function applyTemplate(slug, options) {
3421
3659
  console.log(chalk5.gray(` ${p.type}: ${p.file}`));
3422
3660
  }
3423
3661
  }
3424
- return;
3662
+ return false;
3425
3663
  }
3426
3664
  const writeSpinner = ora3("\uD30C\uC77C \uC0DD\uC131 \uC911...").start();
3427
- for (const file of detail.files) {
3428
- const dest = path8.join(baseDir, file.path);
3429
- await fs8.ensureDir(path8.dirname(dest));
3430
- await fs8.writeFile(dest, file.content);
3665
+ try {
3666
+ writeTemplateFiles(plan);
3667
+ } catch (err) {
3668
+ writeSpinner.fail(err.message);
3669
+ process.exitCode = 1;
3670
+ return false;
3431
3671
  }
3432
3672
  writeSpinner.succeed(`${detail.files.length}\uAC1C \uD30C\uC77C \uC0DD\uC131 \uC644\uB8CC`);
3673
+ for (const item of plan) {
3674
+ if (item.action === "merged") console.log(chalk5.gray(` ${item.path}: ${MERGED_HINT}`));
3675
+ if (item.note) console.log(chalk5.yellow(`! ${item.note}`));
3676
+ }
3433
3677
  if (detail.postInstall?.length) {
3434
3678
  console.log(chalk5.blue("\npostInstall \uD328\uCE58 \uC2E4\uD589 \uC911..."));
3435
3679
  await runPostInstall(detail.postInstall, baseDir);
@@ -3443,6 +3687,7 @@ async function applyTemplate(slug, options) {
3443
3687
  }
3444
3688
  console.log(chalk5.green(`
3445
3689
  '${detail.name}' \uD15C\uD50C\uB9BF \uC801\uC6A9 \uC644\uB8CC!`));
3690
+ return true;
3446
3691
  }
3447
3692
  async function initTemplate(slug, options) {
3448
3693
  const interactive = options.interactive ?? isInteractive();
@@ -3528,7 +3773,7 @@ async function initTemplate(slug, options) {
3528
3773
  await fs8.ensureDir(resolved);
3529
3774
  }
3530
3775
  const nextSteps = templateInitNextSteps(resolved);
3531
- await applyTemplate(selectedSlug, { dir: targetDir, yes: true });
3776
+ if (!await applyTemplate(selectedSlug, { dir: targetDir, yes: true })) return;
3532
3777
  const configPath = path8.join(resolved, "axis.config.json");
3533
3778
  if (!await fs8.pathExists(configPath)) {
3534
3779
  const axisConfig = createTemplateConfig(selectedSlug);
@@ -3558,8 +3803,17 @@ async function diffTemplate(slug, options) {
3558
3803
  }
3559
3804
  const baseDir = path9.resolve(options.dir || ".");
3560
3805
  const entries = [];
3561
- for (const file of detail.files) {
3562
- const localPath = path9.join(baseDir, file.path);
3806
+ let localPaths;
3807
+ try {
3808
+ localPaths = detail.files.map((file) => resolveTemplatePath(baseDir, file.path));
3809
+ } catch (err) {
3810
+ if (!(err instanceof TemplatePathError)) throw err;
3811
+ console.error(chalk6.red(err.message));
3812
+ process.exitCode = 1;
3813
+ return;
3814
+ }
3815
+ for (const [i, file] of detail.files.entries()) {
3816
+ const localPath = localPaths[i];
3563
3817
  if (!await fs9.pathExists(localPath)) {
3564
3818
  entries.push({ path: file.path, status: "added" });
3565
3819
  continue;
@@ -3658,7 +3912,7 @@ import chalk7 from "chalk";
3658
3912
 
3659
3913
  // src/theme/brand-core.ts
3660
3914
  import { createHash } from "crypto";
3661
- import { existsSync as existsSync2, readFileSync as readFileSync2, statSync as statSync2 } from "fs";
3915
+ import { existsSync as existsSync3, readFileSync as readFileSync3, statSync as statSync2 } from "fs";
3662
3916
  import { createRequire } from "module";
3663
3917
  import { dirname as dirname2, join as join2, relative as relative2, resolve as resolve2, sep as sep2 } from "path";
3664
3918
  import { MessageChannel, Worker, receiveMessageOnPort } from "worker_threads";
@@ -3682,7 +3936,7 @@ var KEY_TOKENS = [
3682
3936
  ];
3683
3937
  var BRAND_ADJUSTMENT_REFERENCE = "WI-0025 PRD \uBD80\uB85D B (docs/workitems/WI-0025-brand-theme/prd.md)";
3684
3938
  function readJsonFile(file) {
3685
- return JSON.parse(readFileSync2(file, "utf8"));
3939
+ return JSON.parse(readFileSync3(file, "utf8"));
3686
3940
  }
3687
3941
  function errorCode(err) {
3688
3942
  return typeof err === "object" && err !== null && "code" in err ? String(err.code) : void 0;
@@ -3693,7 +3947,7 @@ function tokensPackageJsonCandidates(baseDir) {
3693
3947
  for (; ; ) {
3694
3948
  const candidate = join2(dir, "node_modules", TOKENS_PACKAGE, "package.json");
3695
3949
  candidates.push(candidate);
3696
- if (existsSync2(candidate)) return { found: candidate, candidates };
3950
+ if (existsSync3(candidate)) return { found: candidate, candidates };
3697
3951
  const parent = dirname2(dir);
3698
3952
  if (parent === dir) return { candidates };
3699
3953
  dir = parent;
@@ -3839,7 +4093,7 @@ function openTokensResolver(baseDir, candidates, pkgJson, pkgText) {
3839
4093
  postChecked = true;
3840
4094
  let after;
3841
4095
  try {
3842
- after = sha256(readFileSync2(pkgJson, "utf8"));
4096
+ after = sha256(readFileSync3(pkgJson, "utf8"));
3843
4097
  } catch {
3844
4098
  after = UNKNOWN;
3845
4099
  }
@@ -3873,13 +4127,13 @@ function readVersion(pkgText) {
3873
4127
  function openTokens(baseDir) {
3874
4128
  const { found: pkgJson, candidates } = tokensPackageJsonCandidates(baseDir);
3875
4129
  if (!pkgJson) return { resolution: { status: "not-installed" } };
3876
- const pkgText = readFileSync2(pkgJson, "utf8");
4130
+ const pkgText = readFileSync3(pkgJson, "utf8");
3877
4131
  let version = readVersion(pkgText);
3878
4132
  const resolver = openTokensResolver(baseDir, candidates, pkgJson, pkgText);
3879
4133
  const finish = (status, indexPath) => {
3880
4134
  if (resolver.raced) {
3881
4135
  try {
3882
- version = readVersion(readFileSync2(pkgJson, "utf8"));
4136
+ version = readVersion(readFileSync3(pkgJson, "utf8"));
3883
4137
  } catch {
3884
4138
  }
3885
4139
  }
@@ -3931,7 +4185,7 @@ var AXIS_CONFIG_FILE_NAME = "axis.config.json";
3931
4185
  function readBrandConfig(baseDir) {
3932
4186
  let parsed;
3933
4187
  try {
3934
- parsed = JSON.parse(readFileSync2(join2(resolve2(baseDir), AXIS_CONFIG_FILE_NAME), "utf8"));
4188
+ parsed = JSON.parse(readFileSync3(join2(resolve2(baseDir), AXIS_CONFIG_FILE_NAME), "utf8"));
3935
4189
  } catch {
3936
4190
  return null;
3937
4191
  }
@@ -4080,13 +4334,13 @@ function findBrandActivation(baseDir) {
4080
4334
  const file = join2(root, candidate);
4081
4335
  if (!isFile(file)) continue;
4082
4336
  layoutFiles.push(candidate);
4083
- const text = stripJsLikeComments(readFileSync2(file, "utf8"));
4337
+ const text = stripJsLikeComments(readFileSync3(file, "utf8"));
4084
4338
  const providerTexts = [];
4085
4339
  for (const m of text.matchAll(/from\s+["']\.\/(providers?)["']/g)) {
4086
4340
  for (const ext of [".tsx", ".jsx", ".ts", ".js"]) {
4087
4341
  const rel3 = `${dirname2(candidate)}/${m[1]}${ext}`;
4088
4342
  const p = join2(root, rel3);
4089
- if (isFile(p)) providerTexts.push({ rel: rel3, text: stripJsLikeComments(readFileSync2(p, "utf8")) });
4343
+ if (isFile(p)) providerTexts.push({ rel: rel3, text: stripJsLikeComments(readFileSync3(p, "utf8")) });
4090
4344
  }
4091
4345
  }
4092
4346
  const all = [text, ...providerTexts.map((x) => x.text)];
@@ -4117,7 +4371,7 @@ function inspectBrandActivation(baseDir) {
4117
4371
  var THEME_PACKAGE = "@axis-ds/theme";
4118
4372
  function readProjectPackageJson(baseDir) {
4119
4373
  try {
4120
- const parsed = JSON.parse(readFileSync2(join2(resolve2(baseDir), "package.json"), "utf8"));
4374
+ const parsed = JSON.parse(readFileSync3(join2(resolve2(baseDir), "package.json"), "utf8"));
4121
4375
  return typeof parsed === "object" && parsed !== null && !Array.isArray(parsed) ? parsed : void 0;
4122
4376
  } catch {
4123
4377
  return void 0;
@@ -4146,7 +4400,7 @@ function getBrandWith(tokens, resolver, name) {
4146
4400
  try {
4147
4401
  summary = readSummary(resolver, entry);
4148
4402
  const cssPath = resolver.resolve(summary.importPath);
4149
- parsed = parseBrandCss(readFileSync2(cssPath, "utf8"), name);
4403
+ parsed = parseBrandCss(readFileSync3(cssPath, "utf8"), name);
4150
4404
  } catch (err) {
4151
4405
  if (isMissingBuildFile(err)) return { status: "not-built", version: tokens.version, brand: null, available: [] };
4152
4406
  if (resolver.stale && errorCode(err) === "ERR_PACKAGE_PATH_NOT_EXPORTED") {
@@ -4168,7 +4422,7 @@ function getBrandWith(tokens, resolver, name) {
4168
4422
  }
4169
4423
 
4170
4424
  // ../axis-registry-core/src/template/dependencies-core.ts
4171
- import { readFileSync as readFileSync3 } from "fs";
4425
+ import { readFileSync as readFileSync4 } from "fs";
4172
4426
  import { join as join3 } from "path";
4173
4427
  var REQUIRED_DEPENDENCIES = ["tailwindcss"];
4174
4428
  var RECOMMENDED_DEPENDENCIES = ["clsx", "tailwind-merge"];
@@ -4185,7 +4439,7 @@ function checkDependencies(baseDirInput) {
4185
4439
  const baseDir = resolveBaseDir(baseDirInput);
4186
4440
  let pkg;
4187
4441
  try {
4188
- const parsed = JSON.parse(readFileSync3(join3(baseDir, "package.json"), "utf8"));
4442
+ const parsed = JSON.parse(readFileSync4(join3(baseDir, "package.json"), "utf8"));
4189
4443
  if (!isPlainObject(parsed)) throw new Error("not object");
4190
4444
  pkg = parsed;
4191
4445
  } catch (err) {
@@ -4227,11 +4481,15 @@ function checkDependencies(baseDirInput) {
4227
4481
  if (missingRecommended.length > 0) problems.push(`\uAD8C\uC7A5 \uC758\uC874\uC131 \uB204\uB77D: ${missingRecommended.join(", ")}`);
4228
4482
  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`);
4229
4483
  if (pnpRootAxis.length > 0) problems.push(`${pnpRootAxis.join(", ")} \uAC00 ${PNP_ROOT_ONLY_NOTE} \u2192 \uC571 package.json \uC5D0 \uC120\uC5B8\uD558\uC138\uC694`);
4484
+ const installCommand = detectInstallCommand(baseDir);
4230
4485
  if (notInstalledOther.length > 0) {
4231
- problems.push(`\uC120\uC5B8\uB410\uC9C0\uB9CC \uC124\uCE58\uB418\uC9C0 \uC54A\uC740 \uC758\uC874\uC131: ${notInstalledOther.join(", ")} \u2192 ${detectInstallCommand(baseDir)}`);
4486
+ const phrase = installCommandPhrase(installCommand, notInstalledOther.some((d) => fromRoot(d)));
4487
+ problems.push(`\uC120\uC5B8\uB410\uC9C0\uB9CC \uC124\uCE58\uB418\uC9C0 \uC54A\uC740 \uC758\uC874\uC131: ${notInstalledOther.join(", ")} \u2192 ${phrase}`);
4232
4488
  }
4233
4489
  if (notInstalledRoot.length > 0) {
4234
- 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)}`);
4490
+ problems.push(
4491
+ `\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 ${installCommandPhrase(installCommand, true)}`
4492
+ );
4235
4493
  }
4236
4494
  if (problems.length > 0) {
4237
4495
  return { name: "dependencies", severity: "warn", message: problems.join(" / ") + (rootNote ? ` (${rootNote})` : "") };
@@ -4511,13 +4769,13 @@ import chalk9 from "chalk";
4511
4769
  import path12 from "path";
4512
4770
 
4513
4771
  // src/theme/theme-add.ts
4514
- import { accessSync, constants, existsSync as existsSync3, readFileSync as readFileSync4, realpathSync as realpathSync2, unlinkSync, writeFileSync } from "fs";
4772
+ import { accessSync, constants, existsSync as existsSync4, readFileSync as readFileSync5, realpathSync as realpathSync3, unlinkSync as unlinkSync2, writeFileSync as writeFileSync2 } from "fs";
4515
4773
  import path11 from "path";
4516
4774
  var TOKENS_DEPENDENCY_RANGE = `^${TOKENS_DEPENDENCY_MIN_VERSION}`;
4517
4775
  var TAILWIND3_BASE_IMPORTS = [`${TOKENS_PACKAGE}/css`, `${TOKENS_PACKAGE}/css/shadcn`];
4518
4776
  var THEME_MIN_VERSION = "1.3.0";
4519
4777
  function readText(file) {
4520
- return existsSync3(file) ? readFileSync4(file, "utf8") : null;
4778
+ return existsSync4(file) ? readFileSync5(file, "utf8") : null;
4521
4779
  }
4522
4780
  function eolOf(text) {
4523
4781
  return text.includes("\r\n") ? "\r\n" : "\n";
@@ -4608,8 +4866,8 @@ function compareVersions(a, b) {
4608
4866
  return 0;
4609
4867
  }
4610
4868
  function realPathInside(baseDir, file) {
4611
- const realBase = realpathSync2(baseDir);
4612
- const realPath = realpathSync2(file);
4869
+ const realBase = realpathSync3(baseDir);
4870
+ const realPath = realpathSync3(file);
4613
4871
  const relPath = path11.relative(realBase, realPath);
4614
4872
  const inside = relPath !== "" && !relPath.startsWith("..") && !path11.isAbsolute(relPath);
4615
4873
  return { inside, realPath };
@@ -4652,7 +4910,7 @@ function planThemeAdd(baseDirInput, brand) {
4652
4910
  }
4653
4911
  plan.tokens = resolveTokens(baseDir);
4654
4912
  if (plan.tokens.status === "ok" && plan.tokens.indexPath) {
4655
- const data = JSON.parse(readFileSync4(plan.tokens.indexPath, "utf8"));
4913
+ const data = JSON.parse(readFileSync5(plan.tokens.indexPath, "utf8"));
4656
4914
  const entries = Array.isArray(data.brands) ? data.brands : [];
4657
4915
  const entry = entries.find((e) => e.name === brand);
4658
4916
  if (!entry) {
@@ -4711,7 +4969,7 @@ function planThemeAdd(baseDirInput, brand) {
4711
4969
  plan.writes = [];
4712
4970
  return plan;
4713
4971
  }
4714
- const before = readFileSync4(location.path, "utf8");
4972
+ const before = readFileSync5(location.path, "utf8");
4715
4973
  const imported = findBrandImports(before);
4716
4974
  const otherBrands = [...new Set(imported.filter((n) => n !== brand))];
4717
4975
  const brandAdded = !imported.includes(brand);
@@ -4747,11 +5005,11 @@ function planThemeAdd(baseDirInput, brand) {
4747
5005
  };
4748
5006
  }
4749
5007
  if (!tailwind4) {
4750
- const configFile2 = TAILWIND_CONFIG_FILES.find((f) => existsSync3(path11.join(baseDir, f)));
5008
+ const configFile2 = TAILWIND_CONFIG_FILES.find((f) => existsSync4(path11.join(baseDir, f)));
4751
5009
  const content = inspectTailwindContent(baseDir);
4752
5010
  plan.tailwindConfig = {
4753
5011
  configFile: configFile2,
4754
- presetMissing: configFile2 === void 0 || !hasTokensPresetReference(readFileSync4(path11.join(baseDir, configFile2), "utf8")),
5012
+ presetMissing: configFile2 === void 0 || !hasTokensPresetReference(readFileSync5(path11.join(baseDir, configFile2), "utf8")),
4755
5013
  contentMissing: content?.targets.filter((t) => !t.covered) ?? [],
4756
5014
  contentUnknown: content !== null && (content.unreadable || content.dynamic)
4757
5015
  };
@@ -4836,15 +5094,15 @@ function applyThemeAdd(plan) {
4836
5094
  const done = [];
4837
5095
  for (const w of plan.writes) {
4838
5096
  try {
4839
- writeFileSync(w.file, w.after);
5097
+ writeFileSync2(w.file, w.after);
4840
5098
  done.push(w);
4841
5099
  } catch (err) {
4842
5100
  const restored = [];
4843
5101
  const restoreFailed = [];
4844
5102
  for (const d of done.reverse()) {
4845
5103
  try {
4846
- if (d.before === null) unlinkSync(d.file);
4847
- else writeFileSync(d.file, d.before);
5104
+ if (d.before === null) unlinkSync2(d.file);
5105
+ else writeFileSync2(d.file, d.before);
4848
5106
  restored.push(d.file);
4849
5107
  } catch {
4850
5108
  restoreFailed.push(d.file);
@@ -4896,6 +5154,10 @@ function installPhrase(g) {
4896
5154
  if (g.kind === "install-at-root") return `\uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uB8E8\uD2B8\uC5D0\uC11C ${chalk9.cyan(g.installCommand)}`;
4897
5155
  return chalk9.cyan(g.kind === "install" ? g.installCommand : g.addCommand);
4898
5156
  }
5157
+ function rootInstallPhrase(installCommand) {
5158
+ const phrase = installCommandPhrase(installCommand, true);
5159
+ return phrase === installCommand ? chalk9.cyan(installCommand) : `\uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uB8E8\uD2B8\uC5D0\uC11C ${chalk9.cyan(installCommand)}`;
5160
+ }
4899
5161
  function rebuildGuide(g) {
4900
5162
  return `\uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4\uBA74 ${chalk9.cyan(workspaceRunCommand(g.installCommand, TOKENS_PACKAGE, "build"))}, \uC544\uB2C8\uBA74 \uC7AC\uC124\uCE58: ${installPhrase(g)}`;
4901
5163
  }
@@ -5109,7 +5371,7 @@ function renderThemeAdd(plan, written) {
5109
5371
  );
5110
5372
  }
5111
5373
  for (const d of css?.deferredComponentImports ?? []) {
5112
- lines.push(chalk9.yellow(` ! ${deferredComponentImportReason(d, plan.installCommand)}`));
5374
+ lines.push(chalk9.yellow(` ! ${deferredComponentImportReason(d, installCommandPhrase(plan.installCommand, true))}`));
5113
5375
  }
5114
5376
  if (css && css.otherBrands.length > 0) {
5115
5377
  lines.push(
@@ -5130,7 +5392,7 @@ function renderThemeAdd(plan, written) {
5130
5392
  lines.push(
5131
5393
  ` ${chalk9.gray("-")} package.json: ${TOKENS_PACKAGE} ${dep.declaredRange} \uAC00 \uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uB8E8\uD2B8\uC5D0 \uC120\uC5B8\uB3FC \uC788\uC5B4 \uC571 package.json \uC740 \uBC14\uAFB8\uC9C0 \uC54A\uC74C`
5132
5394
  );
5133
- if (plan.tokens.status === "not-installed") lines.push(` \uC124\uCE58: ${chalk9.cyan(plan.installCommand)}`);
5395
+ if (plan.tokens.status === "not-installed") lines.push(` \uC124\uCE58: ${rootInstallPhrase(plan.installCommand)}`);
5134
5396
  else if (plan.tokens.status === "not-built") lines.push(` ${rebuildGuide(tokensGuide)}`);
5135
5397
  } else if (dep?.action === "present") {
5136
5398
  lines.push(` ${chalk9.gray("-")} package.json: ${TOKENS_PACKAGE} ${dep.declaredRange} \uAC00 \uC774\uBBF8 \uC788\uC5B4 \uBC94\uC704\uB97C \uBC14\uAFB8\uC9C0 \uC54A\uC74C`);
@@ -5556,13 +5818,13 @@ async function fetchRegistryJson(url, options = {}) {
5556
5818
  }
5557
5819
 
5558
5820
  // src/init/init.ts
5559
- import { accessSync as accessSync2, constants as constants2, existsSync as existsSync5, lstatSync as lstatSync3, readFileSync as readFileSync5, realpathSync as realpathSync4, statSync as statSync4, writeFileSync as writeFileSync2 } from "fs";
5821
+ import { accessSync as accessSync2, constants as constants2, existsSync as existsSync6, lstatSync as lstatSync4, readFileSync as readFileSync6, realpathSync as realpathSync5, statSync as statSync4, writeFileSync as writeFileSync3 } from "fs";
5560
5822
  import path14 from "path";
5561
5823
  import chalk10 from "chalk";
5562
5824
  import fs12 from "fs-extra";
5563
5825
 
5564
5826
  // ../axis-registry-core/src/add/safe-write.ts
5565
- import { constants as fsConstants, existsSync as existsSync4, lstatSync as lstatSync2, realpathSync as realpathSync3, statSync as statSync3 } from "fs";
5827
+ import { constants as fsConstants, existsSync as existsSync5, lstatSync as lstatSync3, realpathSync as realpathSync4, statSync as statSync3 } from "fs";
5566
5828
  import path13 from "path";
5567
5829
  import fs11 from "fs-extra";
5568
5830
  var NEW_FILE_FLAGS = fsConstants.O_WRONLY | fsConstants.O_CREAT | fsConstants.O_EXCL | (fsConstants.O_NOFOLLOW ?? 0);
@@ -5581,7 +5843,7 @@ function isSameOrInside(parent, child, impl = path13) {
5581
5843
  }
5582
5844
  function nearestExisting(p) {
5583
5845
  let cur = p;
5584
- while (!existsSync4(cur)) {
5846
+ while (!existsSync5(cur)) {
5585
5847
  const up = path13.dirname(cur);
5586
5848
  if (up === cur) return cur;
5587
5849
  cur = up;
@@ -5589,18 +5851,18 @@ function nearestExisting(p) {
5589
5851
  return cur;
5590
5852
  }
5591
5853
  function escapeReason(root, target, options = {}) {
5592
- const realRoot = realpathSync3(root);
5854
+ const realRoot = realpathSync4(root);
5593
5855
  if (!isSameOrInside(path13.resolve(root), path13.resolve(target)) || path13.resolve(target) === path13.resolve(root)) {
5594
5856
  return `\uACBD\uB85C\uAC00 \uD504\uB85C\uC81D\uD2B8 \uB514\uB809\uD130\uB9AC \uBC16\uC785\uB2C8\uB2E4(${target})`;
5595
5857
  }
5596
5858
  const anchor = nearestExisting(path13.dirname(target));
5597
- const realAnchor = realpathSync3(anchor);
5859
+ const realAnchor = realpathSync4(anchor);
5598
5860
  if (!isSameOrInside(realRoot, realAnchor)) {
5599
5861
  return `\uC0C1\uC704 \uB514\uB809\uD130\uB9AC\uC758 \uC2E4\uC81C \uC704\uCE58(${realAnchor})\uAC00 \uD504\uB85C\uC81D\uD2B8 \uB514\uB809\uD130\uB9AC \uBC16\uC785\uB2C8\uB2E4`;
5600
5862
  }
5601
5863
  let st = null;
5602
5864
  try {
5603
- st = lstatSync2(target);
5865
+ st = lstatSync3(target);
5604
5866
  } catch {
5605
5867
  st = null;
5606
5868
  }
@@ -5609,7 +5871,7 @@ function escapeReason(root, target, options = {}) {
5609
5871
  const shown = path13.relative(path13.resolve(root), path13.resolve(target)).split(path13.sep).join("/");
5610
5872
  let realTarget;
5611
5873
  try {
5612
- realTarget = realpathSync3(target);
5874
+ realTarget = realpathSync4(target);
5613
5875
  } catch {
5614
5876
  return `\uAE30\uC874 \uD30C\uC77C ${shown} \uC774 \uAE68\uC9C4 \uC2EC\uBCFC\uB9AD \uB9C1\uD06C\uB77C \uB530\uB77C\uAC08 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4(\uB9C1\uD06C\uB97C \uC9C0\uC6B0\uAC70\uB098 \uACE0\uCE5C \uB4A4 \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694)`;
5615
5877
  }
@@ -5634,7 +5896,7 @@ function escapeReason(root, target, options = {}) {
5634
5896
  }
5635
5897
  function isSymlink(p) {
5636
5898
  try {
5637
- return lstatSync2(p).isSymbolicLink();
5899
+ return lstatSync3(p).isSymbolicLink();
5638
5900
  } catch {
5639
5901
  return false;
5640
5902
  }
@@ -5642,15 +5904,15 @@ function isSymlink(p) {
5642
5904
  function outsideLinkTarget(root, target) {
5643
5905
  if (!isSymlink(target)) return null;
5644
5906
  try {
5645
- const realTarget = realpathSync3(target);
5646
- return isSameOrInside(realpathSync3(root), realTarget) ? null : realTarget;
5907
+ const realTarget = realpathSync4(target);
5908
+ return isSameOrInside(realpathSync4(root), realTarget) ? null : realTarget;
5647
5909
  } catch {
5648
5910
  return null;
5649
5911
  }
5650
5912
  }
5651
5913
  function hardLinkCount(target) {
5652
5914
  try {
5653
- const st = lstatSync2(target);
5915
+ const st = lstatSync3(target);
5654
5916
  return st.isFile() && st.nlink >= 2 ? st.nlink : null;
5655
5917
  } catch {
5656
5918
  return null;
@@ -5660,10 +5922,10 @@ function hardLinkMessage(shownPath, nlink) {
5660
5922
  return `\uAE30\uC874 \uD30C\uC77C ${shownPath} \uC774 \uB2E4\uB978 \uACBD\uB85C\uC640 \uD558\uB4DC\uB9C1\uD06C\uB85C \uC774\uC5B4\uC9C4 \uD30C\uC77C\uC774\uB77C(\uB9C1\uD06C \uC218 ${nlink}) \uB36E\uC5B4\uC4F0\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uB36E\uC5B4\uC4F0\uBA74 \uC774\uC5B4\uC9C4 \uB2E4\uB978 \uACBD\uB85C\uC758 \uB0B4\uC6A9\uB3C4 \uBC14\uB01D\uB2C8\uB2E4. \uD558\uB4DC\uB9C1\uD06C\uB97C \uB04A\uC740(\uD30C\uC77C\uC744 \uBCF5\uC0AC\uD574 \uBC14\uAFBC) \uB4A4 \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694`;
5661
5923
  }
5662
5924
  function writtenOutside(root, target) {
5663
- const realRoot = realpathSync3(root);
5925
+ const realRoot = realpathSync4(root);
5664
5926
  let realTarget;
5665
5927
  try {
5666
- realTarget = realpathSync3(target);
5928
+ realTarget = realpathSync4(target);
5667
5929
  } catch {
5668
5930
  return target;
5669
5931
  }
@@ -5709,8 +5971,8 @@ async function overwriteFollowingLinks(target, content) {
5709
5971
  }
5710
5972
  }
5711
5973
  function checkParentInside(root, target) {
5712
- const realRoot = realpathSync3(root);
5713
- const realParent = realpathSync3(path13.dirname(target));
5974
+ const realRoot = realpathSync4(root);
5975
+ const realParent = realpathSync4(path13.dirname(target));
5714
5976
  if (!isSameOrInside(realRoot, realParent)) {
5715
5977
  return `\uBD80\uBAA8 \uB514\uB809\uD130\uB9AC\uC758 \uC2E4\uC81C \uC704\uCE58(${realParent})\uAC00 \uD504\uB85C\uC81D\uD2B8 \uB514\uB809\uD130\uB9AC \uBC16\uC785\uB2C8\uB2E4`;
5716
5978
  }
@@ -5813,6 +6075,7 @@ async function resolveInitAnswers(baseDirInput, tailwind4) {
5813
6075
  }
5814
6076
  function animationGuideLine(pkg, tailwind4, installCommand, baseDir) {
5815
6077
  const name = tailwind4 ? ANIMATION_PLUGIN_TAILWIND4 : ANIMATION_PLUGIN_TAILWIND3;
6078
+ const setupOf = (candidate) => !tailwind4 ? `tailwind.config \uC758 plugins \uC5D0 require("${candidate}") \uB97C \uB123\uC73C\uC138\uC694` : `\uC804\uC5ED CSS \uC5D0 ${tailwind4AnimationLine(candidate)} \uB97C \uB123\uC73C\uC138\uC694`;
5816
6079
  if (baseDir !== void 0) {
5817
6080
  const pnp = isPnpProject(baseDir);
5818
6081
  const candidates = tailwind4 ? [ANIMATION_PLUGIN_TAILWIND4, ANIMATION_PLUGIN_TAILWIND3] : [ANIMATION_PLUGIN_TAILWIND3];
@@ -5821,13 +6084,26 @@ function animationGuideLine(pkg, tailwind4, installCommand, baseDir) {
5821
6084
  if (pnp) return hasDependency(pkg, n) !== void 0 ? { source: "app" } : void 0;
5822
6085
  return declaredDependency(baseDir, pkg, n);
5823
6086
  };
6087
+ const usable = (n) => declaredOf(n) !== void 0 && (pnp || findInstalledPackage(baseDir, n) !== void 0);
6088
+ const css = tailwind4 && pkg !== void 0 ? inspectTailwind4Animation(baseDir, pkg) : void 0;
6089
+ const cssFile = css?.file !== void 0 ? `${css.file}${css.via}` : void 0;
6090
+ if (css !== void 0 && cssFile !== void 0 && css.lines.length > 0) {
6091
+ if (css.problems.length === 0) return void 0;
6092
+ return tailwind4AnimationProblemLine(cssFile, css.lines, css.problems, installCommand, candidates.filter(usable));
6093
+ }
5824
6094
  for (const candidate of candidates) {
5825
6095
  const declared = declaredOf(candidate);
5826
6096
  if (declared === void 0) continue;
5827
- if (pnp || findInstalledPackage(baseDir, candidate) !== void 0) return void 0;
6097
+ if (pnp || findInstalledPackage(baseDir, candidate) !== void 0) {
6098
+ if (css !== void 0 && cssFile !== void 0 && css.lines.length === 0) {
6099
+ return `\uC560\uB2C8\uBA54\uC774\uC158: ${candidate} \uB294 ${pnp ? "\uC120\uC5B8" : "\uC124\uCE58"}\uB3FC \uC788\uC9C0\uB9CC ${cssFile}\uC5D0 \uC560\uB2C8\uBA54\uC774\uC158 \uC904\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. ${setupOf(candidate)}.`;
6100
+ }
6101
+ return void 0;
6102
+ }
5828
6103
  const declaredWhere = declared.source === "root" ? "\uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uB8E8\uD2B8\uC5D0 " : "";
5829
- const setup = !tailwind4 ? `tailwind.config \uC758 plugins \uC5D0 require("${candidate}") \uB97C \uB123\uC73C\uC138\uC694` : candidate === ANIMATION_PLUGIN_TAILWIND4 ? `\uC804\uC5ED CSS \uC5D0 @import "${candidate}"; \uB97C \uB123\uC73C\uC138\uC694` : `\uC804\uC5ED CSS \uC5D0 @plugin "${candidate}"; \uB97C \uB123\uC73C\uC138\uC694`;
5830
- return `\uC560\uB2C8\uBA54\uC774\uC158: ${candidate} \uB294 ${declaredWhere}\uC120\uC5B8\uB3FC \uC788\uC9C0\uB9CC \uC124\uCE58\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. ${installCommand} \uB4A4 ${setup}.`;
6104
+ const setup = setupOf(candidate);
6105
+ const install = installCommandPhrase(installCommand, declared.source === "root");
6106
+ return `\uC560\uB2C8\uBA54\uC774\uC158: ${candidate} \uB294 ${declaredWhere}\uC120\uC5B8\uB3FC \uC788\uC9C0\uB9CC \uC124\uCE58\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. ${install} \uB4A4 ${setup}.`;
5831
6107
  }
5832
6108
  } else if (pkg !== void 0 && (hasDependency(pkg, ANIMATION_PLUGIN_TAILWIND3) !== void 0 || hasDependency(pkg, ANIMATION_PLUGIN_TAILWIND4) !== void 0)) {
5833
6109
  return void 0;
@@ -5836,6 +6112,25 @@ function animationGuideLine(pkg, tailwind4, installCommand, baseDir) {
5836
6112
  const where = tailwind4 ? `\uC804\uC5ED CSS \uC5D0 @import "${name}"; \uB97C \uB123\uC73C\uC138\uC694` : `tailwind.config \uC758 plugins \uC5D0 require("${name}") \uB97C \uB123\uC73C\uC138\uC694`;
5837
6113
  return `\uC560\uB2C8\uBA54\uC774\uC158: Dialog \xB7 Select \uB4F1\uC758 \uC5F4\uACE0 \uB2EB\uB294 \uC560\uB2C8\uBA54\uC774\uC158(animate-in \uB958)\uC740 \uD50C\uB7EC\uADF8\uC778\uC774 \uD544\uC694\uD569\uB2C8\uB2E4. ${add} \uB4A4 ${where}.`;
5838
6114
  }
6115
+ function pnpRootOnlyTailwindLine(baseDir, pkg) {
6116
+ return pnpRootOnlyDependency(baseDir, pkg, "tailwindcss") !== void 0 ? `! \uD544\uC218 \uC758\uC874\uC131 tailwindcss \uAC00 ${PNP_ROOT_ONLY_NOTE} \u2192 \uC571 package.json \uC5D0 \uC120\uC5B8\uD558\uC138\uC694` : void 0;
6117
+ }
6118
+ function tailwind4AnimationLine(name) {
6119
+ return name === ANIMATION_PLUGIN_TAILWIND4 ? `@import "${name}";` : `@plugin "${name}";`;
6120
+ }
6121
+ function tailwind4AnimationProblemLine(cssFile, lines, problems, installCommand, usable) {
6122
+ const commands = [];
6123
+ const undeclared = problems.filter((p) => p.kind !== "notInstalled").map((p) => p.name);
6124
+ if (undeclared.length > 0) commands.push(`${addCommandFor(installCommand, {}).trimEnd()} ${undeclared.join(" ")}`);
6125
+ const notInstalled = problems.filter((p) => p.kind === "notInstalled");
6126
+ if (notInstalled.length > 0) commands.push(installCommandPhrase(installCommand, notInstalled.some((p) => p.root === true)));
6127
+ const why = problems.map((p) => p.why).join(" \xB7 ");
6128
+ const problemLines = problems.map((p) => tailwind4AnimationLine(p.name)).join(" \xB7 ");
6129
+ const other = usable.find((n) => !problems.some((p) => p.name === n));
6130
+ const install = `\uC124\uCE58\uD558\uC138\uC694: ${commands.join(" \xB7 ")}`;
6131
+ const action = other === void 0 ? install : lines.includes(other) ? `\uC774\uBBF8 \uC124\uCE58\uB41C ${other} \uB9CC \uC4F0\uB824\uBA74 ${problemLines} \uC904\uC744 \uC9C0\uC6B0\uACE0, \uC544\uB2C8\uBA74 ${install}` : `\uC774\uBBF8 \uC124\uCE58\uB41C ${other} \uB97C \uC4F0\uB824\uBA74 ${problemLines} \uC904\uC744 ${tailwind4AnimationLine(other)} \uB85C \uBC14\uAFB8\uACE0, \uC544\uB2C8\uBA74 ${install}`;
6132
+ return `\uC560\uB2C8\uBA54\uC774\uC158: ${cssFile}\uC758 \uC560\uB2C8\uBA54\uC774\uC158 \uC904\uC744 \uC4F8 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4(${why}). ${action}`;
6133
+ }
5839
6134
  var INIT_NEXT_STEP_COMMAND = "npx @axis-ds/cli add button";
5840
6135
  function isTailwind4(tailwind) {
5841
6136
  return tailwind.major !== void 0 && tailwind.major >= 4;
@@ -5844,7 +6139,7 @@ var TAILWIND4_TOKENS_VERSION = TAILWIND4_MIN_AXIS_VERSION;
5844
6139
  var TAILWIND4_CONFLICT_LINE = " ! create-next-app \uAE30\uBCF8 globals.css \uC758 :root \xB7 @theme inline \xB7 @media (prefers-color-scheme: dark) \xB7 body \uBE14\uB85D\uC740 AXIS \uC640 \uAC19\uC740 \uC774\uB984(--background \xB7 --foreground \xB7 --color-background \xB7 --font-sans \xB7 --font-mono)\uC744 \uB2E4\uB978 \uAC12\uC73C\uB85C \uC815\uC758\uD569\uB2C8\uB2E4. \uC774 \uBE14\uB85D\uB4E4\uC744 \uC9C0\uC6B0\uC138\uC694.";
5845
6140
  function readPackageJsonSafe(baseDir) {
5846
6141
  try {
5847
- const text = readFileSync5(path14.join(baseDir, "package.json"), "utf8");
6142
+ const text = readFileSync6(path14.join(baseDir, "package.json"), "utf8");
5848
6143
  const parsed = JSON.parse(text.startsWith(BOM) ? text.slice(1) : text);
5849
6144
  return isPlainObject(parsed) ? parsed : void 0;
5850
6145
  } catch {
@@ -5852,15 +6147,20 @@ function readPackageJsonSafe(baseDir) {
5852
6147
  }
5853
6148
  }
5854
6149
  function tailwind4GuideLines(pkg, installCommand, globalCss, baseDir) {
5855
- const declared = (name) => pkg !== void 0 && (baseDir !== void 0 ? declaredDependency(baseDir, pkg, name) : hasDependency(pkg, name)) !== void 0;
6150
+ const declared = (name) => pkg !== void 0 && (baseDir !== void 0 ? declaredDependency(baseDir, pkg, name, void 0, { appOnlyInPnp: true }) : hasDependency(pkg, name)) !== void 0;
6151
+ const pnpRootOnly = (name) => baseDir !== void 0 && pnpRootOnlyDependency(baseDir, pkg, name) !== void 0;
5856
6152
  const used = TAILWIND4_COMPONENT_PACKAGES.filter((name) => declared(name));
6153
+ const rootOnlyComponents = TAILWIND4_COMPONENT_PACKAGES.filter((name) => pnpRootOnly(name));
5857
6154
  const lines = [
5858
6155
  `Tailwind 4: \uC804\uC5ED CSS(${globalCss}) \uB9E8 \uC704\uC5D0 \uB2E4\uC74C \uC904\uC744 \uB123\uC73C\uC138\uC694(\uD30C\uC77C\uC740 \uACE0\uCE58\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4).`,
5859
6156
  ' @import "tailwindcss";',
5860
6157
  ` ${TOKENS_TAILWIND4_IMPORT_LINE}`,
5861
6158
  ...used.map((name) => ` ${componentTailwindImportLine(name)}`)
5862
6159
  ];
5863
- if (used.length === 0) {
6160
+ for (const name of rootOnlyComponents) {
6161
+ lines.push(` ! ${name} \uAC00 ${PNP_ROOT_ONLY_NOTE} \u2192 \uC571 package.json \uC5D0 \uC120\uC5B8\uD55C \uB4A4 ${componentTailwindImportLine(name)}`);
6162
+ }
6163
+ if (used.length === 0 && rootOnlyComponents.length === 0) {
5864
6164
  lines.push(
5865
6165
  ` npm \uD328\uD0A4\uC9C0 \uCEF4\uD3EC\uB10C\uD2B8\uB97C \uC4F0\uBA74 \uADF8 \uD328\uD0A4\uC9C0\uC758 tailwind.css \uB3C4 \uB123\uC73C\uC138\uC694(\uC608: @import "${TAILWIND4_COMPONENT_PACKAGES[0]}/tailwind.css";).`
5866
6166
  );
@@ -5868,7 +6168,8 @@ function tailwind4GuideLines(pkg, installCommand, globalCss, baseDir) {
5868
6168
  lines.push(TAILWIND4_CONFLICT_LINE);
5869
6169
  if (!declared(TOKENS_PACKAGE)) {
5870
6170
  const add = addCommandFor(installCommand, { [TOKENS_PACKAGE]: `^${TAILWIND4_TOKENS_VERSION}` });
5871
- lines.push(` ${TOKENS_PACKAGE} \uC124\uCE58: ${add}`);
6171
+ const why = pnpRootOnly(TOKENS_PACKAGE) ? `(${PNP_ROOT_ONLY_NOTE})` : "";
6172
+ lines.push(` ${TOKENS_PACKAGE} \uC124\uCE58${why}: ${add}`);
5872
6173
  }
5873
6174
  const versions = axisPackagesBelowTailwind4(pkg, baseDir);
5874
6175
  const unknown = versions.filter((v) => v.status === "unknown");
@@ -5912,13 +6213,14 @@ function planUtilsDependencies(baseDirInput) {
5912
6213
  action: "no-package-json",
5913
6214
  added: [],
5914
6215
  present: [],
6216
+ pnpRootOnly: [],
5915
6217
  ranges: ranges0,
5916
6218
  tailwind: tailwind0,
5917
6219
  installCommand,
5918
6220
  addCommand: addCommandFor(installCommand, ranges0)
5919
6221
  };
5920
6222
  const pkgFile = path14.join(baseDir, "package.json");
5921
- if (!existsSync5(pkgFile)) return plan;
6223
+ if (!existsSync6(pkgFile)) return plan;
5922
6224
  const unwritable = (reason) => ({ ...plan, action: "unwritable", reason });
5923
6225
  let where;
5924
6226
  try {
@@ -5929,7 +6231,7 @@ function planUtilsDependencies(baseDirInput) {
5929
6231
  if (!where.inside) return unwritable(`\uC2E4\uC81C \uC704\uCE58(${where.realPath})\uAC00 \uD504\uB85C\uC81D\uD2B8 \uB514\uB809\uD130\uB9AC \uBC16\uC785\uB2C8\uB2E4`);
5930
6232
  let text;
5931
6233
  try {
5932
- text = readFileSync5(pkgFile, "utf8");
6234
+ text = readFileSync6(pkgFile, "utf8");
5933
6235
  } catch (err) {
5934
6236
  return unwritable(err.message);
5935
6237
  }
@@ -5948,9 +6250,12 @@ function planUtilsDependencies(baseDirInput) {
5948
6250
  plan.addCommand = addCommandFor(installCommand, plan.ranges);
5949
6251
  const missing = {};
5950
6252
  for (const [name, range] of Object.entries(plan.ranges)) {
5951
- const declared = declaredDependency(baseDir, pkg, name);
6253
+ const declared = declaredDependency(baseDir, pkg, name, void 0, { appOnlyInPnp: true });
5952
6254
  if (declared !== void 0) plan.present.push({ name, range: declared.range, source: declared.source });
5953
- else missing[name] = range;
6255
+ else {
6256
+ missing[name] = range;
6257
+ if (pnpRootOnlyDependency(baseDir, pkg, name) !== void 0) plan.pnpRootOnly.push(name);
6258
+ }
5954
6259
  }
5955
6260
  plan.added = Object.keys(missing);
5956
6261
  plan.addCommand = addCommandFor(installCommand, plan.added.length > 0 ? missing : plan.ranges);
@@ -5967,12 +6272,12 @@ function planUtilsDependencies(baseDirInput) {
5967
6272
  const after = bom + formatJsonLike(body, { ...pkg, dependencies: deps });
5968
6273
  return { ...plan, action: "add", write: { file: pkgFile, before: text, after } };
5969
6274
  }
5970
- var defaultWriteFile = (file, data) => writeFileSync2(file, data);
6275
+ var defaultWriteFile = (file, data) => writeFileSync3(file, data);
5971
6276
  function applyUtilsDependencies(baseDirInput, plan, writeFile = defaultWriteFile) {
5972
6277
  const w = plan.write;
5973
6278
  if (plan.action !== "add" || !w) return false;
5974
6279
  const baseDir = path14.resolve(baseDirInput);
5975
- const current = existsSync5(w.file) ? readFileSync5(w.file, "utf8") : null;
6280
+ const current = existsSync6(w.file) ? readFileSync6(w.file, "utf8") : null;
5976
6281
  if (current !== w.before) {
5977
6282
  throw new Error(`${w.file} \uC774 \uACC4\uD68D \uB4A4\uC5D0 \uBC14\uB00C\uC5C8\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694.`);
5978
6283
  }
@@ -5988,7 +6293,7 @@ function applyUtilsDependencies(baseDirInput, plan, writeFile = defaultWriteFile
5988
6293
  let restored;
5989
6294
  try {
5990
6295
  writeFile(w.file, w.before);
5991
- if (readFileSync5(w.file, "utf8") !== w.before) throw new Error("\uB418\uB3CC\uB9B0 \uB0B4\uC6A9\uC774 \uC6D0\uB798 \uB0B4\uC6A9\uACFC \uB2E4\uB985\uB2C8\uB2E4");
6296
+ if (readFileSync6(w.file, "utf8") !== w.before) throw new Error("\uB418\uB3CC\uB9B0 \uB0B4\uC6A9\uC774 \uC6D0\uB798 \uB0B4\uC6A9\uACFC \uB2E4\uB985\uB2C8\uB2E4");
5992
6297
  restored = "\uC6D0\uB798 \uB0B4\uC6A9\uC73C\uB85C \uB418\uB3CC\uB838\uC2B5\uB2C8\uB2E4";
5993
6298
  } catch (restoreErr) {
5994
6299
  restored = `\uC6D0\uB798 \uB0B4\uC6A9\uC73C\uB85C \uB418\uB3CC\uB9AC\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4(${restoreErr.message}). \uD30C\uC77C\uC774 \uC798\uB838\uAC70\uB098 \uBE44\uC5C8\uC744 \uC218 \uC788\uC73C\uB2C8 \uBC84\uC804 \uAD00\uB9AC \uB3C4\uAD6C \uB4F1\uC73C\uB85C \uBCF5\uAD6C\uD558\uC138\uC694`;
@@ -6002,6 +6307,8 @@ function reportDependencies(plan, log) {
6002
6307
  const rootPresent = plan.present.filter((p) => p.source === "root").map((p) => p.name);
6003
6308
  const rootNote = rootPresent.length > 0 ? ` (\uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uB8E8\uD2B8\uC5D0 \uC120\uC5B8: ${rootPresent.join(", ")})` : "";
6004
6309
  const basis = ` tailwind-merge \uBC94\uC704 \uAE30\uC900: ${describeTailwindBasis(plan.tailwind)}`;
6310
+ const installPhrase2 = installCommandPhrase(plan.installCommand, rootPresent.length > 0);
6311
+ const installText = installPhrase2 === plan.installCommand ? chalk10.cyan(plan.installCommand) : `\uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uB8E8\uD2B8\uC5D0\uC11C ${chalk10.cyan(plan.installCommand)}`;
6005
6312
  const logBasis = () => {
6006
6313
  log(chalk10.gray(basis));
6007
6314
  for (const w of tailwindWarnings(plan.tailwind, plan.installCommand)) log(chalk10.yellow(` ${w}`));
@@ -6009,12 +6316,13 @@ function reportDependencies(plan, log) {
6009
6316
  if (plan.action === "add") {
6010
6317
  const addedText = plan.added.map((n) => `${n}@${plan.ranges[n]}`).join(", ");
6011
6318
  log(chalk10.green(`\u2713 package.json dependencies \uC5D0 \uCD94\uAC00: ${addedText}`));
6319
+ if (plan.pnpRootOnly.length > 0) log(chalk10.gray(` ${plan.pnpRootOnly.join(", ")} \uB294 ${PNP_ROOT_ONLY_NOTE}`));
6012
6320
  if (plan.present.length > 0) log(chalk10.gray(` \uC774\uBBF8 \uC788\uC74C(\uBC84\uC804 \uC720\uC9C0): ${presentText}${rootNote}`));
6013
6321
  if (plan.added.includes("tailwind-merge")) logBasis();
6014
- log(chalk10.yellow(` \uC124\uCE58\uB294 \uC2E4\uD589\uD558\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. \uC124\uCE58: ${chalk10.cyan(plan.installCommand)}`));
6322
+ log(chalk10.yellow(` \uC124\uCE58\uB294 \uC2E4\uD589\uD558\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. \uC124\uCE58: ${installText}`));
6015
6323
  } else if (plan.action === "present") {
6016
6324
  log(chalk10.green(`\u2713 utils.ts \uC758\uC874\uC131\uC774 package.json \uC5D0 \uC774\uBBF8 \uC788\uC2B5\uB2C8\uB2E4(\uBC84\uC804 \uC720\uC9C0): ${presentText}${rootNote}`));
6017
- log(chalk10.yellow(` \uC124\uCE58\uB294 \uC2E4\uD589\uD558\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. \uC124\uCE58: ${chalk10.cyan(plan.installCommand)}`));
6325
+ log(chalk10.yellow(` \uC124\uCE58\uB294 \uC2E4\uD589\uD558\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. \uC124\uCE58: ${installText}`));
6018
6326
  } else if (plan.action === "no-package-json") {
6019
6327
  log(chalk10.yellow("! package.json \uC774 \uC5C6\uC5B4 utils.ts \uC758\uC874\uC131(clsx, tailwind-merge)\uC744 \uCD94\uAC00\uD558\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4."));
6020
6328
  log(chalk10.yellow(` \uC124\uCE58: ${chalk10.cyan(plan.addCommand)}`));
@@ -6073,7 +6381,7 @@ function planUtilsWrite(baseDirInput, utilsPath) {
6073
6381
  const shown = path14.relative(baseDir, utilsPath).split(path14.sep).join("/") || utilsPath;
6074
6382
  let st;
6075
6383
  try {
6076
- st = lstatSync3(utilsPath);
6384
+ st = lstatSync4(utilsPath);
6077
6385
  } catch (e) {
6078
6386
  if (e.code === "ENOENT") return { action: "create" };
6079
6387
  return { action: "reject", reason: `${shown} \uC758 \uC815\uBCF4\uB97C \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4(${errCode(e)})` };
@@ -6081,13 +6389,13 @@ function planUtilsWrite(baseDirInput, utilsPath) {
6081
6389
  if (st.isSymbolicLink()) {
6082
6390
  let real;
6083
6391
  try {
6084
- real = realpathSync4(utilsPath);
6392
+ real = realpathSync5(utilsPath);
6085
6393
  } catch {
6086
6394
  return { action: "reject", reason: `${shown} \uC774 \uAE68\uC9C4 \uC2EC\uBCFC\uB9AD \uB9C1\uD06C\uB77C \uC4F0\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uB9C1\uD06C\uB97C \uC9C0\uC6B0\uAC70\uB098 \uACE0\uCE5C \uB4A4 \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694` };
6087
6395
  }
6088
6396
  let outside = null;
6089
6397
  try {
6090
- outside = isSameOrInside(realpathSync4(baseDir), real) ? null : real;
6398
+ outside = isSameOrInside(realpathSync5(baseDir), real) ? null : real;
6091
6399
  } catch {
6092
6400
  outside = null;
6093
6401
  }
@@ -6101,7 +6409,7 @@ function planUtilsWrite(baseDirInput, utilsPath) {
6101
6409
  if (!target.isFile()) return { action: "reject", reason: `${shown} \uB9C1\uD06C \uB300\uC0C1(${real})\uC774 \uC77C\uBC18 \uD30C\uC77C\uC774 \uC544\uB2D9\uB2C8\uB2E4` };
6102
6410
  let content2;
6103
6411
  try {
6104
- content2 = readFileSync5(utilsPath, "utf8");
6412
+ content2 = readFileSync6(utilsPath, "utf8");
6105
6413
  } catch (e) {
6106
6414
  return { action: "reject", reason: `${shown} \uB9C1\uD06C \uB300\uC0C1(${real})\uC744 \uC77D\uC9C0 \uBABB\uD574 \uBE44\uAD50\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4(${errCode(e)})` };
6107
6415
  }
@@ -6116,7 +6424,7 @@ function planUtilsWrite(baseDirInput, utilsPath) {
6116
6424
  if (!st.isFile()) return { action: "reject", reason: `${shown} \uC774 \uC77C\uBC18 \uD30C\uC77C\uC774 \uC544\uB2C8\uB77C \uC4F0\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4` };
6117
6425
  let content;
6118
6426
  try {
6119
- content = readFileSync5(utilsPath, "utf8");
6427
+ content = readFileSync6(utilsPath, "utf8");
6120
6428
  } catch (e) {
6121
6429
  return { action: "reject", reason: `\uAE30\uC874 ${shown} \uC744 \uC77D\uC9C0 \uBABB\uD574 \uBE44\uAD50\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4(${errCode(e)})` };
6122
6430
  }
@@ -6268,6 +6576,8 @@ async function runInit(baseDirInput, answers, registryUrl, log = console.log, op
6268
6576
  return;
6269
6577
  }
6270
6578
  reportDependencies(plan, log);
6579
+ const tailwindRootOnly = pnpRootOnlyTailwindLine(baseDir, readPackageJsonSafe(baseDir));
6580
+ if (tailwindRootOnly !== void 0) log(chalk10.yellow(` ${tailwindRootOnly}`));
6271
6581
  const animation = animationGuideLine(readPackageJsonSafe(baseDir), tailwind4, plan.installCommand, baseDir);
6272
6582
  if (animation !== void 0) log(chalk10.yellow(` ${animation}`));
6273
6583
  if (tailwind4) {
@@ -6328,18 +6638,18 @@ function registerInitCommand(program2, registryUrl = DEFAULT_REGISTRY_URL, deps
6328
6638
  import chalk12 from "chalk";
6329
6639
 
6330
6640
  // ../axis-registry-core/src/add/add.ts
6331
- import { existsSync as existsSync7, readFileSync as readFileSync7, statSync as statSync5 } from "fs";
6641
+ import { existsSync as existsSync8, readFileSync as readFileSync8, statSync as statSync5 } from "fs";
6332
6642
  import path16 from "path";
6333
6643
  import fs13 from "fs-extra";
6334
6644
 
6335
6645
  // ../axis-registry-core/src/registry/bundled.ts
6336
- import { existsSync as existsSync6, readFileSync as readFileSync6 } from "fs";
6646
+ import { existsSync as existsSync7, readFileSync as readFileSync7 } from "fs";
6337
6647
  import path15 from "path";
6338
6648
  import { fileURLToPath } from "url";
6339
6649
  function findBundledRegistryDir(moduleUrl = import.meta.url) {
6340
6650
  const here = path15.dirname(fileURLToPath(moduleUrl));
6341
6651
  for (const dir of [path15.join(here, "registry"), path15.join(here, "..", "registry")]) {
6342
- if (existsSync6(path15.join(dir, "index.json"))) return dir;
6652
+ if (existsSync7(path15.join(dir, "index.json"))) return dir;
6343
6653
  }
6344
6654
  return null;
6345
6655
  }
@@ -6347,7 +6657,7 @@ function readBundledJson(dir, fileName) {
6347
6657
  const file = path15.join(dir, fileName);
6348
6658
  let text;
6349
6659
  try {
6350
- text = readFileSync6(file, "utf8");
6660
+ text = readFileSync7(file, "utf8");
6351
6661
  } catch {
6352
6662
  throw new Error(`\uB3D9\uBD09 \uB808\uC9C0\uC2A4\uD2B8\uB9AC\uC5D0 ${fileName} \uAC00 \uC5C6\uC2B5\uB2C8\uB2E4(${dir})`);
6353
6663
  }
@@ -7062,7 +7372,7 @@ function missingDependencies(root, items) {
7062
7372
  const installCommand = detectInstallCommand(root);
7063
7373
  let pkg;
7064
7374
  try {
7065
- const text = readFileSync7(path16.join(root, "package.json"), "utf8").replace(/^\uFEFF/, "");
7375
+ const text = readFileSync8(path16.join(root, "package.json"), "utf8").replace(/^\uFEFF/, "");
7066
7376
  const parsed = JSON.parse(text);
7067
7377
  pkg = isPlainObject(parsed) ? parsed : void 0;
7068
7378
  } catch {
@@ -7074,7 +7384,7 @@ function missingDependencies(root, items) {
7074
7384
  for (const item of items) {
7075
7385
  for (const dep of item.dependencies) {
7076
7386
  const name = dependencyName(dep);
7077
- if (declaredDependency(root, pkg, name, rootPkg) !== void 0) continue;
7387
+ if (declaredDependency(root, pkg, name, rootPkg, { appOnlyInPnp: true }) !== void 0) continue;
7078
7388
  if (name in specs) continue;
7079
7389
  const explicit = dep.length > name.length ? dep.slice(name.length + 1) : void 0;
7080
7390
  specs[name] = explicit ?? ranges[name];
@@ -7177,12 +7487,12 @@ async function runAdd(cwd, requested, options, ctx) {
7177
7487
  const existing = /* @__PURE__ */ new Map();
7178
7488
  const readErrors = [];
7179
7489
  for (const file of plan.files) {
7180
- if (!existsSync7(file.target)) {
7490
+ if (!existsSync8(file.target)) {
7181
7491
  existing.set(file, null);
7182
7492
  continue;
7183
7493
  }
7184
7494
  try {
7185
- existing.set(file, readFileSync7(file.target, "utf8"));
7495
+ existing.set(file, readFileSync8(file.target, "utf8"));
7186
7496
  } catch (e) {
7187
7497
  readErrors.push(
7188
7498
  `${file.item.name}: \uAE30\uC874 \uD30C\uC77C ${rel2(root, file.target)} \uC744 \uC77D\uC9C0 \uBABB\uD574 \uBE44\uAD50\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4(${e.code ?? e.message})`