@axis-ds/cli 1.7.7 → 1.7.9

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
@@ -11,6 +11,7 @@ import {
11
11
  componentCssResolution,
12
12
  componentCssResolvable,
13
13
  cssImportViaNote,
14
+ cssPackageLineResolution,
14
15
  declaredDependency,
15
16
  deferredComponentImportReason,
16
17
  dependencyInstallGuide,
@@ -20,20 +21,24 @@ import {
20
21
  findPnpUnpluggedPackages,
21
22
  globalCssSelectionNote,
22
23
  hasDependency,
24
+ installCommandPhrase,
23
25
  isPlainObject,
24
26
  isPnpProject,
25
27
  outsideCssPackageResolution,
28
+ pnpComponentSourceHidden,
26
29
  pnpProjectRoot,
27
30
  pnpRootOnlyDependency,
31
+ pnpUnplugSetupPhrase,
28
32
  projectFileExists,
29
33
  resolveBaseDir,
30
34
  rootDeclarationsAllowed,
31
35
  runScriptCommand,
32
36
  selectGlobalCss,
37
+ tailwindConfigImportResolution,
33
38
  tokensCssResolution,
34
39
  workspaceRootPackage,
35
40
  workspaceRunCommand
36
- } from "./chunk-EBFXCLSV.js";
41
+ } from "./chunk-EAUM5S4O.js";
37
42
  import {
38
43
  V0Client
39
44
  } from "./chunk-2PNCUPCG.js";
@@ -1848,11 +1853,199 @@ import ora3 from "ora";
1848
1853
 
1849
1854
  // src/template/post-install.ts
1850
1855
  import fs6 from "fs-extra";
1851
- import path6 from "path";
1852
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
1853
2045
  async function runPostInstall(patches, baseDir, dryRun = false) {
2046
+ assertTemplatePaths(baseDir, patches.map((p) => p.file));
1854
2047
  for (const patch of patches) {
1855
- const filePath = path6.resolve(baseDir, patch.file);
2048
+ const filePath = resolveTemplatePath(baseDir, patch.file);
1856
2049
  if (dryRun) {
1857
2050
  console.log(chalk4.gray(` [dry-run] patch ${patch.type}: ${patch.file}`));
1858
2051
  continue;
@@ -1939,7 +2132,7 @@ async function readAxisConfig(baseDir) {
1939
2132
  }
1940
2133
 
1941
2134
  // ../axis-registry-core/src/template/tailwind-core.ts
1942
- 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";
1943
2136
  import { basename, dirname, extname, isAbsolute, join, relative, resolve, sep } from "path";
1944
2137
  function declaredRange(baseDir, pkg, name) {
1945
2138
  return declaredDependency(baseDir, pkg, name)?.range;
@@ -1947,7 +2140,7 @@ function declaredRange(baseDir, pkg, name) {
1947
2140
  function declaredRangeForCheck(baseDir, pkg, name) {
1948
2141
  return declaredDependency(baseDir, pkg, name, void 0, { appOnlyInPnp: true })?.range;
1949
2142
  }
1950
- function isPlainObject2(value) {
2143
+ function isPlainObject3(value) {
1951
2144
  return typeof value === "object" && value !== null && !Array.isArray(value);
1952
2145
  }
1953
2146
  var VERSION = String.raw`v?(\d+)(?:\.(\d+|[xX*]))?(?:\.(\d+|[xX*]))?(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?`;
@@ -2124,10 +2317,10 @@ function regularFile(file) {
2124
2317
  }
2125
2318
  function expandGlobalCss(baseDirInput, entryPath, entryRel, entryCssDir) {
2126
2319
  const baseDir = resolveBaseDir(baseDirInput);
2127
- const entry = readFileSync(entryPath, "utf8");
2320
+ const entry = readFileSync2(entryPath, "utf8");
2128
2321
  let entryReal = entryPath;
2129
2322
  try {
2130
- entryReal = realpathSync(entryPath);
2323
+ entryReal = realpathSync2(entryPath);
2131
2324
  } catch {
2132
2325
  }
2133
2326
  const raws = /* @__PURE__ */ new Map([[entryReal, entry]]);
@@ -2184,7 +2377,7 @@ function walkRelativeCssImports(baseDir, entryReal, raws, limit, includeConditio
2184
2377
  if (target === void 0) continue;
2185
2378
  let real;
2186
2379
  try {
2187
- real = realpathSync(target);
2380
+ real = realpathSync2(target);
2188
2381
  } catch {
2189
2382
  continue;
2190
2383
  }
@@ -2197,7 +2390,7 @@ function walkRelativeCssImports(baseDir, entryReal, raws, limit, includeConditio
2197
2390
  if (rel3 === "" || rel3 === ".." || rel3.startsWith(`..${sep}`) || isAbsolute(rel3)) continue;
2198
2391
  if (!raws.has(real)) {
2199
2392
  try {
2200
- raws.set(real, readFileSync(real, "utf8"));
2393
+ raws.set(real, readFileSync2(real, "utf8"));
2201
2394
  } catch {
2202
2395
  continue;
2203
2396
  }
@@ -2227,10 +2420,10 @@ function findLayoutTokensCssImport(baseDirInput) {
2227
2420
  const baseDir = resolveBaseDir(baseDirInput);
2228
2421
  for (const candidate of ROOT_LAYOUT_FILES) {
2229
2422
  const file = join(baseDir, candidate);
2230
- if (!existsSync(file)) continue;
2423
+ if (!existsSync2(file)) continue;
2231
2424
  let text;
2232
2425
  try {
2233
- text = readFileSync(file, "utf8");
2426
+ text = readFileSync2(file, "utf8");
2234
2427
  } catch {
2235
2428
  continue;
2236
2429
  }
@@ -2248,12 +2441,12 @@ function outsideCssDir(selection) {
2248
2441
  function outsideCssUnresolvedIssue(spec, name) {
2249
2442
  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`;
2250
2443
  }
2251
- function tokensInstallPhrase(baseDir) {
2252
- const g = dependencyInstallGuide(baseDir, TOKENS_PACKAGE_NAME, `^${TAILWIND4_MIN_AXIS_VERSION}`);
2444
+ function tokensInstallPhrase(baseDir, range = `^${TAILWIND4_MIN_AXIS_VERSION}`) {
2445
+ const g = dependencyInstallGuide(baseDir, TOKENS_PACKAGE_NAME, range);
2253
2446
  if (g.kind === "install-at-root") return `\uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uB8E8\uD2B8\uC5D0\uC11C ${g.installCommand}`;
2254
2447
  return g.kind === "install" ? g.installCommand : g.addCommand;
2255
2448
  }
2256
- function tokensCssUnresolvedIssue(baseDir, pkg, spec, cssDir) {
2449
+ function tokensCssUnresolvedIssue(baseDir, pkg, spec, cssDir, lineIssue) {
2257
2450
  const r = tokensCssResolution(baseDir, pkg, TOKENS_PACKAGE_NAME);
2258
2451
  const head = `${spec} import \uAC00 \uC788\uC9C0\uB9CC`;
2259
2452
  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`;
@@ -2263,7 +2456,42 @@ function tokensCssUnresolvedIssue(baseDir, pkg, spec, cssDir) {
2263
2456
  if (cssDir !== void 0 && outsideCssPackageResolution(baseDir, cssDir, TOKENS_PACKAGE_NAME) === "unresolved") {
2264
2457
  return outsideCssUnresolvedIssue(spec, TOKENS_PACKAGE_NAME);
2265
2458
  }
2266
- return void 0;
2459
+ return lineIssue?.();
2460
+ }
2461
+ function packageNameOfSpec(spec) {
2462
+ const parts = spec.split("/");
2463
+ return parts.slice(0, spec.startsWith("@") ? 2 : 1).join("/");
2464
+ }
2465
+ function displayRel(baseDir, p) {
2466
+ return relative(baseDir, p).split(sep).join("/");
2467
+ }
2468
+ function packageLineShadowIssue(baseDir, expanded, origin, spec, opts = {}) {
2469
+ const name = packageNameOfSpec(spec);
2470
+ const lineDir = dirname(origin.path);
2471
+ const others = () => [...new Set(expanded.files.map((f) => dirname(f.path)))].filter((d) => d !== lineDir);
2472
+ const r = cssPackageLineResolution(baseDir, lineDir, spec, others);
2473
+ const head = `${spec} import \uAC00 \uC788\uC9C0\uB9CC \uADF8 \uC904\uC774 \uC788\uB294 \uD30C\uC77C \uC704\uCE58\uC5D0\uC11C`;
2474
+ const label = (pkgDir, version) => `${displayRel(baseDir, pkgDir)}(${version ?? "\uBC84\uC804 \uBAA8\uB984"})`;
2475
+ if (opts.tailwind3 === true && r.kind !== "shadow-not-exported") return void 0;
2476
+ switch (r.kind) {
2477
+ case "ok":
2478
+ return void 0;
2479
+ case "shadow-not-exported": {
2480
+ const current = opts.tailwind3 === true || r.version !== void 0 && (compareExactVersions(r.version, TAILWIND4_MIN_AXIS_VERSION) ?? -1) >= 0;
2481
+ const todo = current ? "\uB2E4\uC2DC \uC124\uCE58\uD558\uC138\uC694" : `${TAILWIND4_MIN_AXIS_VERSION} \uC774\uC0C1\uC73C\uB85C \uB9DE\uCD94\uC138\uC694`;
2482
+ 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}`;
2483
+ }
2484
+ case "shadow-target-missing":
2485
+ 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`;
2486
+ case "not-visible": {
2487
+ const there = expanded.files.find((f) => dirname(f.path) === r.fromDir);
2488
+ 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`;
2489
+ 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}`;
2490
+ }
2491
+ }
2492
+ }
2493
+ function isOutsideEntry(origin) {
2494
+ return origin.depth === 0 && origin.cssDir !== void 0;
2267
2495
  }
2268
2496
  function checkGlobalsCss(baseDirInput) {
2269
2497
  const baseDir = resolveBaseDir(baseDirInput);
@@ -2291,7 +2519,21 @@ function judgeGlobalsCss(baseDir, selection, candidate, expanded) {
2291
2519
  if (imported !== void 0) {
2292
2520
  const origin = evidenceOrigin(expanded, (f) => findTokensCssImport(f) === imported);
2293
2521
  via = cssImportViaNote(viaFiles([origin]));
2294
- const issue = tokensCssUnresolvedIssue(baseDir, pkg, imported, origin !== void 0 ? origin.cssDir : outsideCssDir(selection));
2522
+ const tailwind4 = (detectTailwind(baseDir, pkg).major ?? 0) >= 4;
2523
+ const inside = origin !== void 0 && !isOutsideEntry(origin);
2524
+ const issue = tailwind4 && inside ? tokensCssUnresolvedIssue(
2525
+ baseDir,
2526
+ pkg,
2527
+ imported,
2528
+ void 0,
2529
+ () => packageLineShadowIssue(baseDir, expanded, origin, imported)
2530
+ ) : tokensCssUnresolvedIssue(
2531
+ baseDir,
2532
+ pkg,
2533
+ imported,
2534
+ origin !== void 0 ? origin.cssDir : outsideCssDir(selection),
2535
+ inside ? () => packageLineShadowIssue(baseDir, expanded, origin, imported, { tailwind3: true }) : void 0
2536
+ );
2295
2537
  if (issue !== void 0) unresolved = `${candidate}\uC5D0 ${issue}`;
2296
2538
  else pass = `${candidate}\uC5D0 AXIS CSS \uBCC0\uC218\uAC00 \uC788\uC2B5\uB2C8\uB2E4 (${imported} import)`;
2297
2539
  } else if (AXIS_VARIABLE_DEFINITION.test(stripCssComments(expanded.evidence))) {
@@ -2495,6 +2737,8 @@ function stripJsComments(src) {
2495
2737
  }
2496
2738
  var TOKENS_TAILWIND3_PRESET = "@axis-ds/tokens/tailwind";
2497
2739
  var PRESET_REFERENCE = /(?:\brequire\s*\(\s*|\bimport\s*\(\s*|\bfrom\s*|\bimport\s+)(["'])@axis-ds\/tokens\/tailwind\1/;
2740
+ var PRESET_REQUIRE_REFERENCE = /\brequire\s*\(\s*(["'])@axis-ds\/tokens\/tailwind\1/;
2741
+ var PRESET_IMPORT_REFERENCE = /(?:\bimport\s*\(\s*|\bfrom\s*|\bimport\s+)(["'])@axis-ds\/tokens\/tailwind\1/;
2498
2742
  function hasTokensPresetReference(source) {
2499
2743
  return PRESET_REFERENCE.test(stripJsComments(source));
2500
2744
  }
@@ -2522,6 +2766,25 @@ function hasBareCjsPresetRequire(code) {
2522
2766
  function isCommonJsConfig(file, source) {
2523
2767
  return extname(file) === ".cjs" || /\bmodule\.exports\b/.test(source);
2524
2768
  }
2769
+ function presetTokensUnresolvedMessage(baseDir, pkg, file, bareCjs, code) {
2770
+ const r = tokensCssResolution(baseDir, pkg, TOKENS_PACKAGE_NAME);
2771
+ const head = `${file}\uC5D0 AXIS preset \uCC38\uC870\uAC00 \uC788\uC9C0\uB9CC ${TOKENS_PACKAGE_NAME} \uAC00`;
2772
+ if (r.kind === "not-installed") {
2773
+ 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}`)})`;
2774
+ }
2775
+ if (r.kind === "pnp-root-only" && !bareCjs) {
2776
+ 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`;
2777
+ }
2778
+ const e = tailwindConfigImportResolution(baseDir, TOKENS_TAILWIND3_PRESET, {
2779
+ require: PRESET_REQUIRE_REFERENCE.test(code),
2780
+ import: PRESET_IMPORT_REFERENCE.test(code)
2781
+ });
2782
+ if (e.kind === "not-exported") {
2783
+ const label = `${displayRel(baseDir, e.pkgDir)}(${e.version ?? "\uBC84\uC804 \uBAA8\uB984"})`;
2784
+ 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`;
2785
+ }
2786
+ return void 0;
2787
+ }
2525
2788
  function packageVersionGate(baseDirInput, pkg, name, min, options = {}) {
2526
2789
  const baseDir = resolveBaseDir(baseDirInput);
2527
2790
  if (!isPnpProject(baseDir)) {
@@ -2551,8 +2814,8 @@ function versionGateLabel(gate) {
2551
2814
  }
2552
2815
  function readPackageJson(baseDir) {
2553
2816
  try {
2554
- const parsed = JSON.parse(readFileSync(join(baseDir, "package.json"), "utf8"));
2555
- return isPlainObject2(parsed) ? parsed : void 0;
2817
+ const parsed = JSON.parse(readFileSync2(join(baseDir, "package.json"), "utf8"));
2818
+ return isPlainObject3(parsed) ? parsed : void 0;
2556
2819
  } catch {
2557
2820
  return void 0;
2558
2821
  }
@@ -2574,7 +2837,8 @@ function tailwind4Issues(input, pkg, versions, baseDir) {
2574
2837
  const r = resolutions.get(name);
2575
2838
  if (r.kind === "undeclared" || r.kind === "app-lockfile") continue;
2576
2839
  if (hasComponentTailwindImport(evidence, name) || hasComponentSource(evidence, name)) continue;
2577
- if (componentCssResolvable(r)) missing.push(name);
2840
+ if (r.kind === "app" && pnpComponentSourceHidden(baseDir, name, r.range)) unresolvedMissing.push(componentCssPnpMissingIssue(name));
2841
+ else if (componentCssResolvable(r)) missing.push(name);
2578
2842
  else unresolvedMissing.push(componentCssMissingIssue(baseDir, name, r));
2579
2843
  }
2580
2844
  if (missing.length > 0) {
@@ -2590,12 +2854,28 @@ function tailwind4Issues(input, pkg, versions, baseDir) {
2590
2854
  }
2591
2855
  for (const name of TAILWIND4_COMPONENT_PACKAGES) {
2592
2856
  if (!hasComponentTailwindImport(evidence, name)) continue;
2593
- const unresolved = componentCssPresentIssue(baseDir, name, resolutions.get(name));
2594
- const componentDir = cssDirOf(`${name}/tailwind.css`);
2595
- if (unresolved !== void 0) issues.push(unresolved);
2596
- else if (componentDir !== void 0 && outsideCssPackageResolution(baseDir, componentDir, name, "tailwind.css") === "unresolved") {
2597
- issues.push(outsideCssUnresolvedIssue(`${name}/tailwind.css`, name));
2598
- } 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`);
2857
+ const r = resolutions.get(name);
2858
+ const unresolved = componentCssPresentIssue(baseDir, name, r);
2859
+ const spec = `${name}/tailwind.css`;
2860
+ if (unresolved !== void 0) {
2861
+ issues.push(unresolved);
2862
+ continue;
2863
+ }
2864
+ if (r.kind === "app" && pnpComponentSourceHidden(baseDir, name, r.range)) {
2865
+ issues.push(componentCssPnpPresentIssue(name));
2866
+ continue;
2867
+ }
2868
+ const shadow = input.lineIssue === void 0 ? false : input.lineIssue(spec);
2869
+ let lineProblem;
2870
+ if (shadow !== false) lineProblem = shadow;
2871
+ else {
2872
+ const componentDir = cssDirOf(spec);
2873
+ if (componentDir !== void 0 && outsideCssPackageResolution(baseDir, componentDir, name, "tailwind.css") === "unresolved") {
2874
+ lineProblem = outsideCssUnresolvedIssue(spec, name);
2875
+ }
2876
+ }
2877
+ if (lineProblem !== void 0) issues.push(lineProblem);
2878
+ 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`);
2599
2879
  }
2600
2880
  return issues;
2601
2881
  }
@@ -2603,6 +2883,13 @@ function componentInstallPhrase(baseDir, name, range) {
2603
2883
  const g = dependencyInstallGuide(baseDir, name, range);
2604
2884
  return g.kind === "install-at-root" ? `\uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uB8E8\uD2B8\uC5D0\uC11C ${g.installCommand}` : g.installCommand;
2605
2885
  }
2886
+ 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`;
2887
+ function componentCssPnpMissingIssue(name) {
2888
+ return `${name} \uC758 tailwind.css \uB294 ${PNP_ZIP_SOURCE_NOTE} \u2192 ${pnpUnplugSetupPhrase(name)} \uB4A4 ${componentTailwindImportLine(name)}`;
2889
+ }
2890
+ function componentCssPnpPresentIssue(name) {
2891
+ return `${name}/tailwind.css import \uAC00 \uC788\uC9C0\uB9CC ${PNP_ZIP_SOURCE_NOTE} \u2192 ${pnpUnplugSetupPhrase(name)} \uD558\uC138\uC694`;
2892
+ }
2606
2893
  function componentCssMissingIssue(baseDir, name, r) {
2607
2894
  const line = componentTailwindImportLine(name);
2608
2895
  switch (r.kind) {
@@ -2663,7 +2950,17 @@ function checkTailwindSetup(baseDirInput) {
2663
2950
  );
2664
2951
  const versions = axisPackagesBelowTailwind4(pkg, baseDir);
2665
2952
  const issues = tailwind4Issues(
2666
- { entry: expanded.entry, evidence: expanded.evidence, cssDirOf: (spec) => packageLineCssDir(expanded, spec) },
2953
+ {
2954
+ entry: expanded.entry,
2955
+ evidence: expanded.evidence,
2956
+ cssDirOf: (spec) => packageLineCssDir(expanded, spec),
2957
+ lineIssue: (spec) => {
2958
+ const line = expanded.packageLines.find((l) => l.spec === spec);
2959
+ const origin = line !== void 0 ? expanded.files.find((f) => f.rel === line.file) : void 0;
2960
+ if (origin === void 0 || isOutsideEntry(origin)) return false;
2961
+ return packageLineShadowIssue(baseDir, expanded, origin, spec);
2962
+ }
2963
+ },
2667
2964
  pkg,
2668
2965
  versions,
2669
2966
  baseDir
@@ -2689,11 +2986,14 @@ function checkTailwindSetup(baseDirInput) {
2689
2986
  }
2690
2987
  for (const file of TAILWIND_CONFIG_FILES) {
2691
2988
  const path17 = join(baseDir, file);
2692
- if (!existsSync(path17)) continue;
2693
- const content = readFileSync(path17, "utf8");
2989
+ if (!existsSync2(path17)) continue;
2990
+ const content = readFileSync2(path17, "utf8");
2694
2991
  if (hasTokensPresetReference(content)) {
2695
2992
  const code = stripJsComments(content);
2696
- if (isCommonJsConfig(file, code) && hasBareCjsPresetRequire(code)) {
2993
+ const bareCjs = isCommonJsConfig(file, code) && hasBareCjsPresetRequire(code);
2994
+ const unresolved = presetTokensUnresolvedMessage(baseDir, pkg, file, bareCjs, code);
2995
+ if (unresolved !== void 0) return { name: "tailwind.config", severity: "warn", message: unresolved };
2996
+ if (bareCjs) {
2697
2997
  const gate = packageVersionGate(baseDir, pkg, "@axis-ds/tokens", TOKENS_CJS_PRESET_FIXED_VERSION, { appOnlyInPnp: true });
2698
2998
  if (gate.status === "unresolved") {
2699
2999
  return {
@@ -2724,8 +3024,8 @@ function checkTailwindSetup(baseDirInput) {
2724
3024
  }
2725
3025
  function readAxisConfigLike(baseDir) {
2726
3026
  try {
2727
- const parsed = JSON.parse(readFileSync(join(baseDir, "axis.config.json"), "utf8"));
2728
- return isPlainObject2(parsed) ? parsed : void 0;
3027
+ const parsed = JSON.parse(readFileSync2(join(baseDir, "axis.config.json"), "utf8"));
3028
+ return isPlainObject3(parsed) ? parsed : void 0;
2729
3029
  } catch {
2730
3030
  return void 0;
2731
3031
  }
@@ -2827,7 +3127,7 @@ function realpathPosix(p) {
2827
3127
  const tail = [];
2828
3128
  for (let i = 0; i < 64; i++) {
2829
3129
  try {
2830
- return [realpathSync(cur), ...tail].join(sep).split(sep).join("/");
3130
+ return [realpathSync2(cur), ...tail].join(sep).split(sep).join("/");
2831
3131
  } catch {
2832
3132
  const parent = dirname(cur);
2833
3133
  if (parent === cur) return void 0;
@@ -2883,15 +3183,15 @@ function relDirOf(baseDir, dir) {
2883
3183
  }
2884
3184
  function realDir(dir) {
2885
3185
  try {
2886
- return realpathSync(dir);
3186
+ return realpathSync2(dir);
2887
3187
  } catch {
2888
3188
  return void 0;
2889
3189
  }
2890
3190
  }
2891
3191
  function packageVersion(dir) {
2892
3192
  try {
2893
- const parsed = JSON.parse(readFileSync(join(dir, "package.json"), "utf8"));
2894
- return isPlainObject2(parsed) && typeof parsed.version === "string" ? parsed.version : void 0;
3193
+ const parsed = JSON.parse(readFileSync2(join(dir, "package.json"), "utf8"));
3194
+ return isPlainObject3(parsed) && typeof parsed.version === "string" ? parsed.version : void 0;
2895
3195
  } catch {
2896
3196
  return void 0;
2897
3197
  }
@@ -2926,7 +3226,7 @@ function packageContentTarget(baseDir, name, pkg) {
2926
3226
  let dir = dirname(resolve(found.dir, ...name.split("/").map(() => ".."), ".."));
2927
3227
  for (; ; ) {
2928
3228
  const candidate = join(dir, "node_modules", ...name.split("/"));
2929
- const rel3 = existsSync(join(candidate, "package.json")) ? relDirOf(baseDir, candidate) : void 0;
3229
+ const rel3 = existsSync2(join(candidate, "package.json")) ? relDirOf(baseDir, candidate) : void 0;
2930
3230
  if (rel3 !== void 0) {
2931
3231
  const candidateReal = realDir(candidate);
2932
3232
  if (candidateReal === real) alternates.push(`${rel3}/dist/index.js`);
@@ -3003,7 +3303,7 @@ function inspectTailwindContent(baseDirInput) {
3003
3303
  const pkg = readPackageJson(baseDir);
3004
3304
  const tailwind = detectTailwind(baseDir, pkg);
3005
3305
  if (tailwind.major !== void 0 && tailwind.major >= 4) return null;
3006
- const configFile = TAILWIND_CONFIG_FILES.find((f) => existsSync(join(baseDir, f)));
3306
+ const configFile = TAILWIND_CONFIG_FILES.find((f) => existsSync2(join(baseDir, f)));
3007
3307
  if (configFile === void 0) return null;
3008
3308
  const targets = [];
3009
3309
  const componentsDir = readAxisConfigLike(baseDir)?.componentsDir;
@@ -3017,7 +3317,7 @@ function inspectTailwindContent(baseDirInput) {
3017
3317
  }
3018
3318
  }
3019
3319
  if (targets.length === 0) return null;
3020
- const read = readTailwindContent(readFileSync(join(baseDir, configFile), "utf8"));
3320
+ const read = readTailwindContent(readFileSync2(join(baseDir, configFile), "utf8"));
3021
3321
  const globs = (read?.globs ?? []).filter((g) => !g.trim().startsWith("!"));
3022
3322
  return {
3023
3323
  configFile,
@@ -3085,7 +3385,7 @@ function componentsUseAnimation(baseDir, componentsDir) {
3085
3385
  const [dir, depth] = stack.pop();
3086
3386
  let names;
3087
3387
  try {
3088
- names = readdirSync(dir);
3388
+ names = readdirSync2(dir);
3089
3389
  } catch {
3090
3390
  continue;
3091
3391
  }
@@ -3094,7 +3394,7 @@ function componentsUseAnimation(baseDir, componentsDir) {
3094
3394
  const p = join(dir, name);
3095
3395
  let st;
3096
3396
  try {
3097
- st = lstatSync(p);
3397
+ st = lstatSync2(p);
3098
3398
  } catch {
3099
3399
  continue;
3100
3400
  }
@@ -3102,7 +3402,7 @@ function componentsUseAnimation(baseDir, componentsDir) {
3102
3402
  if (st.isDirectory()) {
3103
3403
  if (name !== "node_modules" && depth < ANIMATION_SCAN_DEPTH_LIMIT) stack.push([p, depth + 1]);
3104
3404
  } else if (st.isFile() && st.size <= ANIMATION_SCAN_FILE_BYTES && /\.(tsx|ts|jsx|js)$/.test(name)) {
3105
- if (/\banimate-(?:in|out)\b/.test(readFileSync(p, "utf8"))) return true;
3405
+ if (/\banimate-(?:in|out)\b/.test(readFileSync2(p, "utf8"))) return true;
3106
3406
  }
3107
3407
  }
3108
3408
  }
@@ -3152,8 +3452,8 @@ function checkAnimationPlugin(baseDirInput) {
3152
3452
  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}`
3153
3453
  };
3154
3454
  }
3155
- const configFile = TAILWIND_CONFIG_FILES.find((f) => existsSync(join(baseDir, f)));
3156
- const source = configFile !== void 0 ? stripJsComments(readFileSync(join(baseDir, configFile), "utf8")) : "";
3455
+ const configFile = TAILWIND_CONFIG_FILES.find((f) => existsSync2(join(baseDir, f)));
3456
+ const source = configFile !== void 0 ? stripJsComments(readFileSync2(join(baseDir, configFile), "utf8")) : "";
3157
3457
  const plugins = configFile !== void 0 ? readAnimationPluginUse(source) : "absent";
3158
3458
  const pluginReason = pluginProblem(ANIMATION_PLUGIN_TAILWIND3);
3159
3459
  if (plugins === "found" && pluginReason === void 0) {
@@ -3241,6 +3541,12 @@ function splitTopLevel(body) {
3241
3541
  }
3242
3542
 
3243
3543
  // src/template/template-apply.ts
3544
+ var ACTION_LABEL = {
3545
+ created: "\uC0DD\uC131",
3546
+ overwritten: "\uB36E\uC5B4\uC4F0\uAE30",
3547
+ merged: "\uD569\uCE58\uAE30"
3548
+ };
3549
+ var MERGED_HINT = "\uAE30\uC874 \uD544\uB4DC\uB97C \uB450\uACE0 \uD15C\uD50C\uB9BF \uD0A4\uB97C \uD569\uCE68";
3244
3550
  function templateDependencyCommands(installCommand, detail) {
3245
3551
  const lines = [];
3246
3552
  const deps = detail.dependencies ?? {};
@@ -3295,18 +3601,21 @@ async function applyTemplate(slug, options) {
3295
3601
  for (const w of await templateApplyWarnings(baseDir, detail)) {
3296
3602
  console.log(chalk5.yellow(`! ${w}`));
3297
3603
  }
3298
- const conflicts = [];
3299
- for (const file of detail.files) {
3300
- const dest = path8.join(baseDir, file.path);
3301
- if (await fs8.pathExists(dest)) {
3302
- conflicts.push(file.path);
3303
- }
3604
+ let plan;
3605
+ try {
3606
+ plan = planTemplateFiles(baseDir, detail.files, (detail.postInstall ?? []).map((p) => p.file));
3607
+ } catch (err) {
3608
+ if (!(err instanceof TemplatePathError)) throw err;
3609
+ console.error(chalk5.red(err.message));
3610
+ process.exitCode = 1;
3611
+ return false;
3304
3612
  }
3613
+ const conflicts = plan.filter((p) => p.action !== "created");
3305
3614
  if (conflicts.length > 0 && !options.yes && !options.dryRun) {
3306
3615
  console.log(chalk5.yellow(`
3307
3616
  \uAE30\uC874 \uD30C\uC77C\uACFC \uCDA9\uB3CC\uD558\uB294 ${conflicts.length}\uAC1C \uD30C\uC77C:`));
3308
3617
  for (const c of conflicts) {
3309
- console.log(chalk5.gray(` - ${c}`));
3618
+ console.log(chalk5.gray(` - ${c.path}${c.action === "merged" ? ` (${MERGED_HINT})` : ""}`));
3310
3619
  }
3311
3620
  const interactive = options.interactive ?? isInteractive();
3312
3621
  if (!interactive) {
@@ -3314,7 +3623,7 @@ async function applyTemplate(slug, options) {
3314
3623
  `\uB36E\uC5B4\uC4F0\uB824\uBA74: axis template apply ${slug} -y`,
3315
3624
  `\uBBF8\uB9AC\uBCF4\uAE30: axis template apply ${slug} --dry-run`
3316
3625
  ]);
3317
- return;
3626
+ return false;
3318
3627
  }
3319
3628
  const { proceed } = await ask(
3320
3629
  {
@@ -3327,16 +3636,16 @@ async function applyTemplate(slug, options) {
3327
3636
  );
3328
3637
  if (!proceed) {
3329
3638
  console.log(chalk5.gray("\uCDE8\uC18C\uB418\uC5C8\uC2B5\uB2C8\uB2E4."));
3330
- return;
3639
+ return false;
3331
3640
  }
3332
3641
  }
3333
3642
  if (options.dryRun) {
3334
3643
  console.log(chalk5.blue("\n[\uBBF8\uB9AC\uBCF4\uAE30] \uC0DD\uC131\uB420 \uD30C\uC77C:"));
3335
- for (const file of detail.files) {
3336
- const dest = path8.join(baseDir, file.path);
3337
- const exists = conflicts.includes(file.path);
3338
- const label = exists ? chalk5.yellow("\uB36E\uC5B4\uC4F0\uAE30") : chalk5.green("\uC0DD\uC131");
3339
- console.log(` ${label} ${dest}`);
3644
+ for (const item of plan) {
3645
+ const text = ACTION_LABEL[item.action];
3646
+ const label = item.action === "created" ? chalk5.green(text) : chalk5.yellow(text);
3647
+ console.log(` ${label} ${item.dest}${item.action === "merged" ? chalk5.gray(` (${MERGED_HINT})`) : ""}`);
3648
+ if (item.note) console.log(chalk5.yellow(` ! ${item.note}`));
3340
3649
  }
3341
3650
  if (detail.postInstall?.length) {
3342
3651
  console.log(chalk5.blue("\n[\uBBF8\uB9AC\uBCF4\uAE30] postInstall \uD328\uCE58:"));
@@ -3344,15 +3653,21 @@ async function applyTemplate(slug, options) {
3344
3653
  console.log(chalk5.gray(` ${p.type}: ${p.file}`));
3345
3654
  }
3346
3655
  }
3347
- return;
3656
+ return false;
3348
3657
  }
3349
3658
  const writeSpinner = ora3("\uD30C\uC77C \uC0DD\uC131 \uC911...").start();
3350
- for (const file of detail.files) {
3351
- const dest = path8.join(baseDir, file.path);
3352
- await fs8.ensureDir(path8.dirname(dest));
3353
- await fs8.writeFile(dest, file.content);
3659
+ try {
3660
+ writeTemplateFiles(plan);
3661
+ } catch (err) {
3662
+ writeSpinner.fail(err.message);
3663
+ process.exitCode = 1;
3664
+ return false;
3354
3665
  }
3355
3666
  writeSpinner.succeed(`${detail.files.length}\uAC1C \uD30C\uC77C \uC0DD\uC131 \uC644\uB8CC`);
3667
+ for (const item of plan) {
3668
+ if (item.action === "merged") console.log(chalk5.gray(` ${item.path}: ${MERGED_HINT}`));
3669
+ if (item.note) console.log(chalk5.yellow(`! ${item.note}`));
3670
+ }
3356
3671
  if (detail.postInstall?.length) {
3357
3672
  console.log(chalk5.blue("\npostInstall \uD328\uCE58 \uC2E4\uD589 \uC911..."));
3358
3673
  await runPostInstall(detail.postInstall, baseDir);
@@ -3366,6 +3681,7 @@ async function applyTemplate(slug, options) {
3366
3681
  }
3367
3682
  console.log(chalk5.green(`
3368
3683
  '${detail.name}' \uD15C\uD50C\uB9BF \uC801\uC6A9 \uC644\uB8CC!`));
3684
+ return true;
3369
3685
  }
3370
3686
  async function initTemplate(slug, options) {
3371
3687
  const interactive = options.interactive ?? isInteractive();
@@ -3451,7 +3767,7 @@ async function initTemplate(slug, options) {
3451
3767
  await fs8.ensureDir(resolved);
3452
3768
  }
3453
3769
  const nextSteps = templateInitNextSteps(resolved);
3454
- await applyTemplate(selectedSlug, { dir: targetDir, yes: true });
3770
+ if (!await applyTemplate(selectedSlug, { dir: targetDir, yes: true })) return;
3455
3771
  const configPath = path8.join(resolved, "axis.config.json");
3456
3772
  if (!await fs8.pathExists(configPath)) {
3457
3773
  const axisConfig = createTemplateConfig(selectedSlug);
@@ -3481,8 +3797,17 @@ async function diffTemplate(slug, options) {
3481
3797
  }
3482
3798
  const baseDir = path9.resolve(options.dir || ".");
3483
3799
  const entries = [];
3484
- for (const file of detail.files) {
3485
- const localPath = path9.join(baseDir, file.path);
3800
+ let localPaths;
3801
+ try {
3802
+ localPaths = detail.files.map((file) => resolveTemplatePath(baseDir, file.path));
3803
+ } catch (err) {
3804
+ if (!(err instanceof TemplatePathError)) throw err;
3805
+ console.error(chalk6.red(err.message));
3806
+ process.exitCode = 1;
3807
+ return;
3808
+ }
3809
+ for (const [i, file] of detail.files.entries()) {
3810
+ const localPath = localPaths[i];
3486
3811
  if (!await fs9.pathExists(localPath)) {
3487
3812
  entries.push({ path: file.path, status: "added" });
3488
3813
  continue;
@@ -3580,9 +3905,11 @@ import path10 from "path";
3580
3905
  import chalk7 from "chalk";
3581
3906
 
3582
3907
  // src/theme/brand-core.ts
3583
- import { existsSync as existsSync2, readFileSync as readFileSync2, statSync as statSync2 } from "fs";
3908
+ import { createHash } from "crypto";
3909
+ import { existsSync as existsSync3, readFileSync as readFileSync3, statSync as statSync2 } from "fs";
3584
3910
  import { createRequire } from "module";
3585
3911
  import { dirname as dirname2, join as join2, relative as relative2, resolve as resolve2, sep as sep2 } from "path";
3912
+ import { MessageChannel, Worker, receiveMessageOnPort } from "worker_threads";
3586
3913
  var TOKENS_PACKAGE = "@axis-ds/tokens";
3587
3914
  var BRAND_NAME_PATTERN = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/;
3588
3915
  var MIN_BRAND_TOKENS_VERSION = "1.3.0";
@@ -3603,18 +3930,20 @@ var KEY_TOKENS = [
3603
3930
  ];
3604
3931
  var BRAND_ADJUSTMENT_REFERENCE = "WI-0025 PRD \uBD80\uB85D B (docs/workitems/WI-0025-brand-theme/prd.md)";
3605
3932
  function readJsonFile(file) {
3606
- return JSON.parse(readFileSync2(file, "utf8"));
3933
+ return JSON.parse(readFileSync3(file, "utf8"));
3607
3934
  }
3608
3935
  function errorCode(err) {
3609
3936
  return typeof err === "object" && err !== null && "code" in err ? String(err.code) : void 0;
3610
3937
  }
3611
- function findTokensPackageJson(baseDir) {
3938
+ function tokensPackageJsonCandidates(baseDir) {
3939
+ const candidates = [];
3612
3940
  let dir = resolve2(baseDir);
3613
3941
  for (; ; ) {
3614
3942
  const candidate = join2(dir, "node_modules", TOKENS_PACKAGE, "package.json");
3615
- if (existsSync2(candidate)) return candidate;
3943
+ candidates.push(candidate);
3944
+ if (existsSync3(candidate)) return { found: candidate, candidates };
3616
3945
  const parent = dirname2(dir);
3617
- if (parent === dir) return void 0;
3946
+ if (parent === dir) return { candidates };
3618
3947
  dir = parent;
3619
3948
  }
3620
3949
  }
@@ -3624,21 +3953,203 @@ function projectRequire(baseDir) {
3624
3953
  function tokensSpecifier(subpath) {
3625
3954
  return `${TOKENS_PACKAGE}/${subpath.replace(/^\.\//, "")}`;
3626
3955
  }
3627
- function resolveTokens(baseDir) {
3628
- const pkgJson = findTokensPackageJson(baseDir);
3629
- if (!pkgJson) return { status: "not-installed" };
3630
- const pkg = readJsonFile(pkgJson);
3631
- const version = typeof pkg.version === "string" ? pkg.version : void 0;
3956
+ var nodeSeenStates = /* @__PURE__ */ new Map();
3957
+ var ABSENT = "absent";
3958
+ var UNKNOWN = "unknown";
3959
+ var isolationDisabled = false;
3960
+ var isolatedStats = { workers: 0, resolves: 0, fallbacks: 0 };
3961
+ var ISOLATED_RESOLVE_TIMEOUT_MS = 5e3;
3962
+ var ISOLATED_RESOLVE_SOURCE = `
3963
+ const { workerData } = require("node:worker_threads");
3964
+ const { createRequire } = require("node:module");
3965
+ const { port, signal, from } = workerData;
3966
+ const req = createRequire(from);
3967
+ port.on("message", (spec) => {
3968
+ let reply;
3969
+ try {
3970
+ reply = { path: req.resolve(spec) };
3971
+ } catch (err) {
3972
+ const code = err && typeof err === "object" && "code" in err ? String(err.code) : undefined;
3973
+ reply = { code, message: err && err.message ? String(err.message) : String(err) };
3974
+ }
3975
+ port.postMessage(reply);
3976
+ Atomics.store(signal, 0, 1);
3977
+ Atomics.notify(signal, 0);
3978
+ });
3979
+ `;
3980
+ var IsolationFailure = class extends Error {
3981
+ };
3982
+ function createWorkerResolveSession(from, source, timeoutMs) {
3983
+ const { port1, port2 } = new MessageChannel();
3984
+ const signal = new Int32Array(new SharedArrayBuffer(4));
3985
+ const worker = new Worker(source, {
3986
+ eval: true,
3987
+ workerData: { port: port2, signal, from },
3988
+ transferList: [port2]
3989
+ });
3990
+ worker.on("error", () => {
3991
+ });
3992
+ worker.unref();
3993
+ return {
3994
+ resolve(spec) {
3995
+ Atomics.store(signal, 0, 0);
3996
+ port1.postMessage(spec);
3997
+ const waited = Atomics.wait(signal, 0, 0, timeoutMs);
3998
+ const received = receiveMessageOnPort(port1);
3999
+ if (waited === "timed-out" || !received) throw new IsolationFailure("\uACA9\uB9AC \uD574\uC11D\uC774 \uC751\uB2F5\uD558\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4");
4000
+ const reply = received.message;
4001
+ if (typeof reply.path === "string") return reply.path;
4002
+ throw Object.assign(new Error(reply.message ?? spec), reply.code === void 0 ? {} : { code: reply.code });
4003
+ },
4004
+ close() {
4005
+ port1.close();
4006
+ void worker.terminate();
4007
+ }
4008
+ };
4009
+ }
4010
+ function workerResolveSession(from) {
4011
+ return createWorkerResolveSession(from, ISOLATED_RESOLVE_SOURCE, ISOLATED_RESOLVE_TIMEOUT_MS);
4012
+ }
4013
+ var isolatedFactory = workerResolveSession;
4014
+ function sha256(text) {
4015
+ return createHash("sha256").update(text).digest("hex");
4016
+ }
4017
+ function openTokensResolver(baseDir, candidates, pkgJson, pkgText) {
4018
+ const nodeRequire = projectRequire(baseDir);
4019
+ const key = sha256(pkgText);
4020
+ const current = candidates.map((c) => c === pkgJson ? key : ABSENT);
4021
+ const changed = candidates.some((c, i) => {
4022
+ const seen = nodeSeenStates.get(c);
4023
+ return seen !== void 0 && seen !== current[i];
4024
+ });
4025
+ let mode = changed ? "isolated" : "node";
4026
+ if (mode === "node") {
4027
+ candidates.forEach((c, i) => {
4028
+ if (!nodeSeenStates.has(c)) nodeSeenStates.set(c, current[i]);
4029
+ });
4030
+ }
4031
+ let session = null;
4032
+ let stale = false;
4033
+ let raced = false;
4034
+ let postChecked = false;
4035
+ const markStale = () => {
4036
+ if (!stale) isolatedStats.fallbacks += 1;
4037
+ stale = true;
4038
+ };
4039
+ const fallBack = () => {
4040
+ markStale();
4041
+ isolationDisabled = true;
4042
+ session?.close();
4043
+ session = null;
4044
+ };
4045
+ const startIsolation = () => {
4046
+ if (isolationDisabled) {
4047
+ markStale();
4048
+ return;
4049
+ }
4050
+ try {
4051
+ session = isolatedFactory(join2(resolve2(baseDir), "package.json"));
4052
+ isolatedStats.workers += 1;
4053
+ } catch {
4054
+ fallBack();
4055
+ }
4056
+ };
4057
+ if (mode === "isolated") startIsolation();
4058
+ const isolatedResolve = (spec) => {
4059
+ if (session) {
4060
+ try {
4061
+ const resolved = session.resolve(spec);
4062
+ isolatedStats.resolves += 1;
4063
+ return resolved;
4064
+ } catch (err) {
4065
+ if (!(err instanceof IsolationFailure)) {
4066
+ isolatedStats.resolves += 1;
4067
+ throw err;
4068
+ }
4069
+ fallBack();
4070
+ }
4071
+ }
4072
+ return nodeRequire.resolve(spec);
4073
+ };
4074
+ return {
4075
+ resolve(spec) {
4076
+ if (mode === "isolated") return isolatedResolve(spec);
4077
+ let resolved;
4078
+ let failure;
4079
+ let failed = false;
4080
+ try {
4081
+ resolved = nodeRequire.resolve(spec);
4082
+ } catch (err) {
4083
+ failed = true;
4084
+ failure = err;
4085
+ }
4086
+ if (!postChecked) {
4087
+ postChecked = true;
4088
+ let after;
4089
+ try {
4090
+ after = sha256(readFileSync3(pkgJson, "utf8"));
4091
+ } catch {
4092
+ after = UNKNOWN;
4093
+ }
4094
+ if (after !== key) {
4095
+ nodeSeenStates.set(pkgJson, UNKNOWN);
4096
+ raced = true;
4097
+ mode = "isolated";
4098
+ startIsolation();
4099
+ return isolatedResolve(spec);
4100
+ }
4101
+ }
4102
+ if (failed) throw failure;
4103
+ return resolved;
4104
+ },
4105
+ get stale() {
4106
+ return stale;
4107
+ },
4108
+ get raced() {
4109
+ return raced;
4110
+ },
4111
+ close() {
4112
+ session?.close();
4113
+ session = null;
4114
+ }
4115
+ };
4116
+ }
4117
+ function readVersion(pkgText) {
4118
+ const pkg = JSON.parse(pkgText);
4119
+ return typeof pkg.version === "string" ? pkg.version : void 0;
4120
+ }
4121
+ function openTokens(baseDir) {
4122
+ const { found: pkgJson, candidates } = tokensPackageJsonCandidates(baseDir);
4123
+ if (!pkgJson) return { resolution: { status: "not-installed" } };
4124
+ const pkgText = readFileSync3(pkgJson, "utf8");
4125
+ let version = readVersion(pkgText);
4126
+ const resolver = openTokensResolver(baseDir, candidates, pkgJson, pkgText);
4127
+ const finish = (status, indexPath) => {
4128
+ if (resolver.raced) {
4129
+ try {
4130
+ version = readVersion(readFileSync3(pkgJson, "utf8"));
4131
+ } catch {
4132
+ }
4133
+ }
4134
+ const resolution = indexPath === void 0 ? { status, version } : { status, version, indexPath };
4135
+ return { resolution: resolver.stale ? { ...resolution, stale: true } : resolution, resolver };
4136
+ };
3632
4137
  try {
3633
- const indexPath = projectRequire(baseDir).resolve(tokensSpecifier("./brands"));
3634
- return { status: "ok", version, indexPath };
4138
+ const indexPath = resolver.resolve(tokensSpecifier("./brands"));
4139
+ return finish("ok", indexPath);
3635
4140
  } catch (err) {
3636
4141
  const code = errorCode(err);
3637
- if (code === "ERR_PACKAGE_PATH_NOT_EXPORTED") return { status: "unsupported", version };
3638
- if (code === "MODULE_NOT_FOUND") return { status: "not-built", version };
4142
+ if (code === "ERR_PACKAGE_PATH_NOT_EXPORTED") return finish("unsupported");
4143
+ if (code === "MODULE_NOT_FOUND") return finish("not-built");
4144
+ resolver.close();
3639
4145
  throw err;
3640
4146
  }
3641
4147
  }
4148
+ function resolveTokens(baseDir) {
4149
+ const { resolution, resolver } = openTokens(baseDir);
4150
+ resolver?.close();
4151
+ return resolution;
4152
+ }
3642
4153
  function brandImportPath(entry) {
3643
4154
  return tokensSpecifier(entry.css);
3644
4155
  }
@@ -3668,7 +4179,7 @@ var AXIS_CONFIG_FILE_NAME = "axis.config.json";
3668
4179
  function readBrandConfig(baseDir) {
3669
4180
  let parsed;
3670
4181
  try {
3671
- parsed = JSON.parse(readFileSync2(join2(resolve2(baseDir), AXIS_CONFIG_FILE_NAME), "utf8"));
4182
+ parsed = JSON.parse(readFileSync3(join2(resolve2(baseDir), AXIS_CONFIG_FILE_NAME), "utf8"));
3672
4183
  } catch {
3673
4184
  return null;
3674
4185
  }
@@ -3711,8 +4222,8 @@ function readBrandIndex(indexPath) {
3711
4222
  }
3712
4223
  return data.brands;
3713
4224
  }
3714
- function readSummary(baseDir, entry) {
3715
- const metaPath = projectRequire(baseDir).resolve(tokensSpecifier(entry.meta));
4225
+ function readSummary(resolver, entry) {
4226
+ const metaPath = resolver.resolve(tokensSpecifier(entry.meta));
3716
4227
  const meta = readJsonFile(metaPath);
3717
4228
  return {
3718
4229
  name: entry.name,
@@ -3723,20 +4234,33 @@ function readSummary(baseDir, entry) {
3723
4234
  };
3724
4235
  }
3725
4236
  function listBrands(baseDir) {
3726
- const tokens = resolveTokens(baseDir);
3727
- if (tokens.status !== "ok" || !tokens.indexPath) {
4237
+ const { resolution: tokens, resolver } = openTokens(baseDir);
4238
+ try {
4239
+ return withStaleOf(resolver, listBrandsWith(tokens, resolver));
4240
+ } finally {
4241
+ resolver?.close();
4242
+ }
4243
+ }
4244
+ function listBrandsWith(tokens, resolver) {
4245
+ if (tokens.status !== "ok" || !tokens.indexPath || !resolver) {
3728
4246
  return { status: tokens.status, version: tokens.version, brands: [] };
3729
4247
  }
3730
4248
  const entries = readBrandIndex(tokens.indexPath);
3731
- let brands;
3732
- try {
3733
- brands = entries.map((entry) => readSummary(baseDir, entry));
3734
- } catch (err) {
3735
- if (isMissingBuildFile(err)) return { status: "not-built", version: tokens.version, brands: [] };
3736
- throw err;
4249
+ const brands = [];
4250
+ for (const entry of entries) {
4251
+ try {
4252
+ brands.push(readSummary(resolver, entry));
4253
+ } catch (err) {
4254
+ if (isMissingBuildFile(err)) return { status: "not-built", version: tokens.version, brands: [] };
4255
+ if (resolver.stale && errorCode(err) === "ERR_PACKAGE_PATH_NOT_EXPORTED") continue;
4256
+ throw err;
4257
+ }
3737
4258
  }
3738
4259
  return { status: "ok", version: tokens.version, brands };
3739
4260
  }
4261
+ function withStaleOf(resolver, result) {
4262
+ return resolver?.stale ? { ...result, stale: true } : result;
4263
+ }
3740
4264
  function stripComments(css) {
3741
4265
  return css.replace(/\/\*[\s\S]*?\*\//g, "");
3742
4266
  }
@@ -3804,13 +4328,13 @@ function findBrandActivation(baseDir) {
3804
4328
  const file = join2(root, candidate);
3805
4329
  if (!isFile(file)) continue;
3806
4330
  layoutFiles.push(candidate);
3807
- const text = stripJsLikeComments(readFileSync2(file, "utf8"));
4331
+ const text = stripJsLikeComments(readFileSync3(file, "utf8"));
3808
4332
  const providerTexts = [];
3809
4333
  for (const m of text.matchAll(/from\s+["']\.\/(providers?)["']/g)) {
3810
4334
  for (const ext of [".tsx", ".jsx", ".ts", ".js"]) {
3811
4335
  const rel3 = `${dirname2(candidate)}/${m[1]}${ext}`;
3812
4336
  const p = join2(root, rel3);
3813
- if (isFile(p)) providerTexts.push({ rel: rel3, text: stripJsLikeComments(readFileSync2(p, "utf8")) });
4337
+ if (isFile(p)) providerTexts.push({ rel: rel3, text: stripJsLikeComments(readFileSync3(p, "utf8")) });
3814
4338
  }
3815
4339
  }
3816
4340
  const all = [text, ...providerTexts.map((x) => x.text)];
@@ -3841,15 +4365,22 @@ function inspectBrandActivation(baseDir) {
3841
4365
  var THEME_PACKAGE = "@axis-ds/theme";
3842
4366
  function readProjectPackageJson(baseDir) {
3843
4367
  try {
3844
- const parsed = JSON.parse(readFileSync2(join2(resolve2(baseDir), "package.json"), "utf8"));
4368
+ const parsed = JSON.parse(readFileSync3(join2(resolve2(baseDir), "package.json"), "utf8"));
3845
4369
  return typeof parsed === "object" && parsed !== null && !Array.isArray(parsed) ? parsed : void 0;
3846
4370
  } catch {
3847
4371
  return void 0;
3848
4372
  }
3849
4373
  }
3850
4374
  function getBrand(baseDir, name) {
3851
- const tokens = resolveTokens(baseDir);
3852
- if (tokens.status !== "ok" || !tokens.indexPath) {
4375
+ const { resolution: tokens, resolver } = openTokens(baseDir);
4376
+ try {
4377
+ return withStaleOf(resolver, getBrandWith(tokens, resolver, name));
4378
+ } finally {
4379
+ resolver?.close();
4380
+ }
4381
+ }
4382
+ function getBrandWith(tokens, resolver, name) {
4383
+ if (tokens.status !== "ok" || !tokens.indexPath || !resolver) {
3853
4384
  return { status: tokens.status, version: tokens.version, brand: null, available: [] };
3854
4385
  }
3855
4386
  const entries = readBrandIndex(tokens.indexPath);
@@ -3861,11 +4392,14 @@ function getBrand(baseDir, name) {
3861
4392
  let summary;
3862
4393
  let parsed;
3863
4394
  try {
3864
- summary = readSummary(baseDir, entry);
3865
- const cssPath = projectRequire(baseDir).resolve(summary.importPath);
3866
- parsed = parseBrandCss(readFileSync2(cssPath, "utf8"), name);
4395
+ summary = readSummary(resolver, entry);
4396
+ const cssPath = resolver.resolve(summary.importPath);
4397
+ parsed = parseBrandCss(readFileSync3(cssPath, "utf8"), name);
3867
4398
  } catch (err) {
3868
4399
  if (isMissingBuildFile(err)) return { status: "not-built", version: tokens.version, brand: null, available: [] };
4400
+ if (resolver.stale && errorCode(err) === "ERR_PACKAGE_PATH_NOT_EXPORTED") {
4401
+ return { status: "ok", version: tokens.version, brand: null, available: available.filter((n) => n !== name) };
4402
+ }
3869
4403
  throw err;
3870
4404
  }
3871
4405
  return {
@@ -3882,7 +4416,7 @@ function getBrand(baseDir, name) {
3882
4416
  }
3883
4417
 
3884
4418
  // ../axis-registry-core/src/template/dependencies-core.ts
3885
- import { readFileSync as readFileSync3 } from "fs";
4419
+ import { readFileSync as readFileSync4 } from "fs";
3886
4420
  import { join as join3 } from "path";
3887
4421
  var REQUIRED_DEPENDENCIES = ["tailwindcss"];
3888
4422
  var RECOMMENDED_DEPENDENCIES = ["clsx", "tailwind-merge"];
@@ -3899,7 +4433,7 @@ function checkDependencies(baseDirInput) {
3899
4433
  const baseDir = resolveBaseDir(baseDirInput);
3900
4434
  let pkg;
3901
4435
  try {
3902
- const parsed = JSON.parse(readFileSync3(join3(baseDir, "package.json"), "utf8"));
4436
+ const parsed = JSON.parse(readFileSync4(join3(baseDir, "package.json"), "utf8"));
3903
4437
  if (!isPlainObject(parsed)) throw new Error("not object");
3904
4438
  pkg = parsed;
3905
4439
  } catch (err) {
@@ -3941,11 +4475,15 @@ function checkDependencies(baseDirInput) {
3941
4475
  if (missingRecommended.length > 0) problems.push(`\uAD8C\uC7A5 \uC758\uC874\uC131 \uB204\uB77D: ${missingRecommended.join(", ")}`);
3942
4476
  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`);
3943
4477
  if (pnpRootAxis.length > 0) problems.push(`${pnpRootAxis.join(", ")} \uAC00 ${PNP_ROOT_ONLY_NOTE} \u2192 \uC571 package.json \uC5D0 \uC120\uC5B8\uD558\uC138\uC694`);
4478
+ const installCommand = detectInstallCommand(baseDir);
3944
4479
  if (notInstalledOther.length > 0) {
3945
- problems.push(`\uC120\uC5B8\uB410\uC9C0\uB9CC \uC124\uCE58\uB418\uC9C0 \uC54A\uC740 \uC758\uC874\uC131: ${notInstalledOther.join(", ")} \u2192 ${detectInstallCommand(baseDir)}`);
4480
+ const phrase = installCommandPhrase(installCommand, notInstalledOther.some((d) => fromRoot(d)));
4481
+ problems.push(`\uC120\uC5B8\uB410\uC9C0\uB9CC \uC124\uCE58\uB418\uC9C0 \uC54A\uC740 \uC758\uC874\uC131: ${notInstalledOther.join(", ")} \u2192 ${phrase}`);
3946
4482
  }
3947
4483
  if (notInstalledRoot.length > 0) {
3948
- 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)}`);
4484
+ problems.push(
4485
+ `\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)}`
4486
+ );
3949
4487
  }
3950
4488
  if (problems.length > 0) {
3951
4489
  return { name: "dependencies", severity: "warn", message: problems.join(" / ") + (rootNote ? ` (${rootNote})` : "") };
@@ -4225,13 +4763,13 @@ import chalk9 from "chalk";
4225
4763
  import path12 from "path";
4226
4764
 
4227
4765
  // src/theme/theme-add.ts
4228
- import { accessSync, constants, existsSync as existsSync3, readFileSync as readFileSync4, realpathSync as realpathSync2, unlinkSync, writeFileSync } from "fs";
4766
+ import { accessSync, constants, existsSync as existsSync4, readFileSync as readFileSync5, realpathSync as realpathSync3, unlinkSync as unlinkSync2, writeFileSync as writeFileSync2 } from "fs";
4229
4767
  import path11 from "path";
4230
4768
  var TOKENS_DEPENDENCY_RANGE = `^${TOKENS_DEPENDENCY_MIN_VERSION}`;
4231
4769
  var TAILWIND3_BASE_IMPORTS = [`${TOKENS_PACKAGE}/css`, `${TOKENS_PACKAGE}/css/shadcn`];
4232
4770
  var THEME_MIN_VERSION = "1.3.0";
4233
4771
  function readText(file) {
4234
- return existsSync3(file) ? readFileSync4(file, "utf8") : null;
4772
+ return existsSync4(file) ? readFileSync5(file, "utf8") : null;
4235
4773
  }
4236
4774
  function eolOf(text) {
4237
4775
  return text.includes("\r\n") ? "\r\n" : "\n";
@@ -4322,8 +4860,8 @@ function compareVersions(a, b) {
4322
4860
  return 0;
4323
4861
  }
4324
4862
  function realPathInside(baseDir, file) {
4325
- const realBase = realpathSync2(baseDir);
4326
- const realPath = realpathSync2(file);
4863
+ const realBase = realpathSync3(baseDir);
4864
+ const realPath = realpathSync3(file);
4327
4865
  const relPath = path11.relative(realBase, realPath);
4328
4866
  const inside = relPath !== "" && !relPath.startsWith("..") && !path11.isAbsolute(relPath);
4329
4867
  return { inside, realPath };
@@ -4366,7 +4904,7 @@ function planThemeAdd(baseDirInput, brand) {
4366
4904
  }
4367
4905
  plan.tokens = resolveTokens(baseDir);
4368
4906
  if (plan.tokens.status === "ok" && plan.tokens.indexPath) {
4369
- const data = JSON.parse(readFileSync4(plan.tokens.indexPath, "utf8"));
4907
+ const data = JSON.parse(readFileSync5(plan.tokens.indexPath, "utf8"));
4370
4908
  const entries = Array.isArray(data.brands) ? data.brands : [];
4371
4909
  const entry = entries.find((e) => e.name === brand);
4372
4910
  if (!entry) {
@@ -4425,7 +4963,7 @@ function planThemeAdd(baseDirInput, brand) {
4425
4963
  plan.writes = [];
4426
4964
  return plan;
4427
4965
  }
4428
- const before = readFileSync4(location.path, "utf8");
4966
+ const before = readFileSync5(location.path, "utf8");
4429
4967
  const imported = findBrandImports(before);
4430
4968
  const otherBrands = [...new Set(imported.filter((n) => n !== brand))];
4431
4969
  const brandAdded = !imported.includes(brand);
@@ -4461,11 +4999,11 @@ function planThemeAdd(baseDirInput, brand) {
4461
4999
  };
4462
5000
  }
4463
5001
  if (!tailwind4) {
4464
- const configFile2 = TAILWIND_CONFIG_FILES.find((f) => existsSync3(path11.join(baseDir, f)));
5002
+ const configFile2 = TAILWIND_CONFIG_FILES.find((f) => existsSync4(path11.join(baseDir, f)));
4465
5003
  const content = inspectTailwindContent(baseDir);
4466
5004
  plan.tailwindConfig = {
4467
5005
  configFile: configFile2,
4468
- presetMissing: configFile2 === void 0 || !hasTokensPresetReference(readFileSync4(path11.join(baseDir, configFile2), "utf8")),
5006
+ presetMissing: configFile2 === void 0 || !hasTokensPresetReference(readFileSync5(path11.join(baseDir, configFile2), "utf8")),
4469
5007
  contentMissing: content?.targets.filter((t) => !t.covered) ?? [],
4470
5008
  contentUnknown: content !== null && (content.unreadable || content.dynamic)
4471
5009
  };
@@ -4550,15 +5088,15 @@ function applyThemeAdd(plan) {
4550
5088
  const done = [];
4551
5089
  for (const w of plan.writes) {
4552
5090
  try {
4553
- writeFileSync(w.file, w.after);
5091
+ writeFileSync2(w.file, w.after);
4554
5092
  done.push(w);
4555
5093
  } catch (err) {
4556
5094
  const restored = [];
4557
5095
  const restoreFailed = [];
4558
5096
  for (const d of done.reverse()) {
4559
5097
  try {
4560
- if (d.before === null) unlinkSync(d.file);
4561
- else writeFileSync(d.file, d.before);
5098
+ if (d.before === null) unlinkSync2(d.file);
5099
+ else writeFileSync2(d.file, d.before);
4562
5100
  restored.push(d.file);
4563
5101
  } catch {
4564
5102
  restoreFailed.push(d.file);
@@ -4610,6 +5148,10 @@ function installPhrase(g) {
4610
5148
  if (g.kind === "install-at-root") return `\uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uB8E8\uD2B8\uC5D0\uC11C ${chalk9.cyan(g.installCommand)}`;
4611
5149
  return chalk9.cyan(g.kind === "install" ? g.installCommand : g.addCommand);
4612
5150
  }
5151
+ function rootInstallPhrase(installCommand) {
5152
+ const phrase = installCommandPhrase(installCommand, true);
5153
+ return phrase === installCommand ? chalk9.cyan(installCommand) : `\uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uB8E8\uD2B8\uC5D0\uC11C ${chalk9.cyan(installCommand)}`;
5154
+ }
4613
5155
  function rebuildGuide(g) {
4614
5156
  return `\uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4\uBA74 ${chalk9.cyan(workspaceRunCommand(g.installCommand, TOKENS_PACKAGE, "build"))}, \uC544\uB2C8\uBA74 \uC7AC\uC124\uCE58: ${installPhrase(g)}`;
4615
5157
  }
@@ -4823,7 +5365,7 @@ function renderThemeAdd(plan, written) {
4823
5365
  );
4824
5366
  }
4825
5367
  for (const d of css?.deferredComponentImports ?? []) {
4826
- lines.push(chalk9.yellow(` ! ${deferredComponentImportReason(d, plan.installCommand)}`));
5368
+ lines.push(chalk9.yellow(` ! ${deferredComponentImportReason(d, installCommandPhrase(plan.installCommand, true))}`));
4827
5369
  }
4828
5370
  if (css && css.otherBrands.length > 0) {
4829
5371
  lines.push(
@@ -4844,7 +5386,7 @@ function renderThemeAdd(plan, written) {
4844
5386
  lines.push(
4845
5387
  ` ${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`
4846
5388
  );
4847
- if (plan.tokens.status === "not-installed") lines.push(` \uC124\uCE58: ${chalk9.cyan(plan.installCommand)}`);
5389
+ if (plan.tokens.status === "not-installed") lines.push(` \uC124\uCE58: ${rootInstallPhrase(plan.installCommand)}`);
4848
5390
  else if (plan.tokens.status === "not-built") lines.push(` ${rebuildGuide(tokensGuide)}`);
4849
5391
  } else if (dep?.action === "present") {
4850
5392
  lines.push(` ${chalk9.gray("-")} package.json: ${TOKENS_PACKAGE} ${dep.declaredRange} \uAC00 \uC774\uBBF8 \uC788\uC5B4 \uBC94\uC704\uB97C \uBC14\uAFB8\uC9C0 \uC54A\uC74C`);
@@ -4970,7 +5512,7 @@ function registerThemeCommand(program2) {
4970
5512
  import chalk11 from "chalk";
4971
5513
 
4972
5514
  // ../axis-registry-core/src/registry/schema.ts
4973
- import { createHash } from "crypto";
5515
+ import { createHash as createHash2 } from "crypto";
4974
5516
  var REGISTRY_NAME_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
4975
5517
  var REGISTRY_NAME_MAX_LENGTH = 64;
4976
5518
  function isValidRegistryName(name) {
@@ -5103,8 +5645,8 @@ function validateRegistryIndex(data, where = "index.json") {
5103
5645
  if (!isValidRegistryName(raw.name)) throw new Error(`${at}: name \uC774 slug \uADDC\uCE59\uC5D0 \uB9DE\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4`);
5104
5646
  if (seen.has(raw.name)) throw new Error(`${at}: name '${raw.name}' \uAC00 \uC911\uBCF5\uC785\uB2C8\uB2E4`);
5105
5647
  seen.add(raw.name);
5106
- const sha256 = optionalString(raw, "sha256", at);
5107
- if (sha256 !== void 0 && !/^[0-9a-f]{64}$/.test(sha256)) {
5648
+ const sha2562 = optionalString(raw, "sha256", at);
5649
+ if (sha2562 !== void 0 && !/^[0-9a-f]{64}$/.test(sha2562)) {
5108
5650
  throw new Error(`${at}: sha256 \uD615\uC2DD\uC774 \uC544\uB2D9\uB2C8\uB2E4`);
5109
5651
  }
5110
5652
  return {
@@ -5112,7 +5654,7 @@ function validateRegistryIndex(data, where = "index.json") {
5112
5654
  type: requireType(raw, at),
5113
5655
  title: optionalString(raw, "title", at),
5114
5656
  description: optionalString(raw, "description", at),
5115
- ...sha256 !== void 0 ? { sha256 } : {}
5657
+ ...sha2562 !== void 0 ? { sha256: sha2562 } : {}
5116
5658
  };
5117
5659
  });
5118
5660
  return {
@@ -5160,7 +5702,7 @@ function validateRegistryItem(data, expectedName, where = `${expectedName}.json`
5160
5702
  };
5161
5703
  }
5162
5704
  function sha256Hex(text) {
5163
- return createHash("sha256").update(text, "utf8").digest("hex");
5705
+ return createHash2("sha256").update(text, "utf8").digest("hex");
5164
5706
  }
5165
5707
  function checkItemSha256(item, entry, where = `${item.name}.json`) {
5166
5708
  if (entry.sha256 === void 0) return;
@@ -5270,13 +5812,13 @@ async function fetchRegistryJson(url, options = {}) {
5270
5812
  }
5271
5813
 
5272
5814
  // src/init/init.ts
5273
- 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";
5815
+ 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";
5274
5816
  import path14 from "path";
5275
5817
  import chalk10 from "chalk";
5276
5818
  import fs12 from "fs-extra";
5277
5819
 
5278
5820
  // ../axis-registry-core/src/add/safe-write.ts
5279
- import { constants as fsConstants, existsSync as existsSync4, lstatSync as lstatSync2, realpathSync as realpathSync3, statSync as statSync3 } from "fs";
5821
+ import { constants as fsConstants, existsSync as existsSync5, lstatSync as lstatSync3, realpathSync as realpathSync4, statSync as statSync3 } from "fs";
5280
5822
  import path13 from "path";
5281
5823
  import fs11 from "fs-extra";
5282
5824
  var NEW_FILE_FLAGS = fsConstants.O_WRONLY | fsConstants.O_CREAT | fsConstants.O_EXCL | (fsConstants.O_NOFOLLOW ?? 0);
@@ -5295,7 +5837,7 @@ function isSameOrInside(parent, child, impl = path13) {
5295
5837
  }
5296
5838
  function nearestExisting(p) {
5297
5839
  let cur = p;
5298
- while (!existsSync4(cur)) {
5840
+ while (!existsSync5(cur)) {
5299
5841
  const up = path13.dirname(cur);
5300
5842
  if (up === cur) return cur;
5301
5843
  cur = up;
@@ -5303,18 +5845,18 @@ function nearestExisting(p) {
5303
5845
  return cur;
5304
5846
  }
5305
5847
  function escapeReason(root, target, options = {}) {
5306
- const realRoot = realpathSync3(root);
5848
+ const realRoot = realpathSync4(root);
5307
5849
  if (!isSameOrInside(path13.resolve(root), path13.resolve(target)) || path13.resolve(target) === path13.resolve(root)) {
5308
5850
  return `\uACBD\uB85C\uAC00 \uD504\uB85C\uC81D\uD2B8 \uB514\uB809\uD130\uB9AC \uBC16\uC785\uB2C8\uB2E4(${target})`;
5309
5851
  }
5310
5852
  const anchor = nearestExisting(path13.dirname(target));
5311
- const realAnchor = realpathSync3(anchor);
5853
+ const realAnchor = realpathSync4(anchor);
5312
5854
  if (!isSameOrInside(realRoot, realAnchor)) {
5313
5855
  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`;
5314
5856
  }
5315
5857
  let st = null;
5316
5858
  try {
5317
- st = lstatSync2(target);
5859
+ st = lstatSync3(target);
5318
5860
  } catch {
5319
5861
  st = null;
5320
5862
  }
@@ -5323,7 +5865,7 @@ function escapeReason(root, target, options = {}) {
5323
5865
  const shown = path13.relative(path13.resolve(root), path13.resolve(target)).split(path13.sep).join("/");
5324
5866
  let realTarget;
5325
5867
  try {
5326
- realTarget = realpathSync3(target);
5868
+ realTarget = realpathSync4(target);
5327
5869
  } catch {
5328
5870
  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)`;
5329
5871
  }
@@ -5348,7 +5890,7 @@ function escapeReason(root, target, options = {}) {
5348
5890
  }
5349
5891
  function isSymlink(p) {
5350
5892
  try {
5351
- return lstatSync2(p).isSymbolicLink();
5893
+ return lstatSync3(p).isSymbolicLink();
5352
5894
  } catch {
5353
5895
  return false;
5354
5896
  }
@@ -5356,15 +5898,15 @@ function isSymlink(p) {
5356
5898
  function outsideLinkTarget(root, target) {
5357
5899
  if (!isSymlink(target)) return null;
5358
5900
  try {
5359
- const realTarget = realpathSync3(target);
5360
- return isSameOrInside(realpathSync3(root), realTarget) ? null : realTarget;
5901
+ const realTarget = realpathSync4(target);
5902
+ return isSameOrInside(realpathSync4(root), realTarget) ? null : realTarget;
5361
5903
  } catch {
5362
5904
  return null;
5363
5905
  }
5364
5906
  }
5365
5907
  function hardLinkCount(target) {
5366
5908
  try {
5367
- const st = lstatSync2(target);
5909
+ const st = lstatSync3(target);
5368
5910
  return st.isFile() && st.nlink >= 2 ? st.nlink : null;
5369
5911
  } catch {
5370
5912
  return null;
@@ -5374,10 +5916,10 @@ function hardLinkMessage(shownPath, nlink) {
5374
5916
  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`;
5375
5917
  }
5376
5918
  function writtenOutside(root, target) {
5377
- const realRoot = realpathSync3(root);
5919
+ const realRoot = realpathSync4(root);
5378
5920
  let realTarget;
5379
5921
  try {
5380
- realTarget = realpathSync3(target);
5922
+ realTarget = realpathSync4(target);
5381
5923
  } catch {
5382
5924
  return target;
5383
5925
  }
@@ -5423,8 +5965,8 @@ async function overwriteFollowingLinks(target, content) {
5423
5965
  }
5424
5966
  }
5425
5967
  function checkParentInside(root, target) {
5426
- const realRoot = realpathSync3(root);
5427
- const realParent = realpathSync3(path13.dirname(target));
5968
+ const realRoot = realpathSync4(root);
5969
+ const realParent = realpathSync4(path13.dirname(target));
5428
5970
  if (!isSameOrInside(realRoot, realParent)) {
5429
5971
  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`;
5430
5972
  }
@@ -5541,7 +6083,8 @@ function animationGuideLine(pkg, tailwind4, installCommand, baseDir) {
5541
6083
  if (pnp || findInstalledPackage(baseDir, candidate) !== void 0) return void 0;
5542
6084
  const declaredWhere = declared.source === "root" ? "\uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uB8E8\uD2B8\uC5D0 " : "";
5543
6085
  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`;
5544
- 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}.`;
6086
+ const install = installCommandPhrase(installCommand, declared.source === "root");
6087
+ 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}.`;
5545
6088
  }
5546
6089
  } else if (pkg !== void 0 && (hasDependency(pkg, ANIMATION_PLUGIN_TAILWIND3) !== void 0 || hasDependency(pkg, ANIMATION_PLUGIN_TAILWIND4) !== void 0)) {
5547
6090
  return void 0;
@@ -5558,7 +6101,7 @@ var TAILWIND4_TOKENS_VERSION = TAILWIND4_MIN_AXIS_VERSION;
5558
6101
  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.";
5559
6102
  function readPackageJsonSafe(baseDir) {
5560
6103
  try {
5561
- const text = readFileSync5(path14.join(baseDir, "package.json"), "utf8");
6104
+ const text = readFileSync6(path14.join(baseDir, "package.json"), "utf8");
5562
6105
  const parsed = JSON.parse(text.startsWith(BOM) ? text.slice(1) : text);
5563
6106
  return isPlainObject(parsed) ? parsed : void 0;
5564
6107
  } catch {
@@ -5632,7 +6175,7 @@ function planUtilsDependencies(baseDirInput) {
5632
6175
  addCommand: addCommandFor(installCommand, ranges0)
5633
6176
  };
5634
6177
  const pkgFile = path14.join(baseDir, "package.json");
5635
- if (!existsSync5(pkgFile)) return plan;
6178
+ if (!existsSync6(pkgFile)) return plan;
5636
6179
  const unwritable = (reason) => ({ ...plan, action: "unwritable", reason });
5637
6180
  let where;
5638
6181
  try {
@@ -5643,7 +6186,7 @@ function planUtilsDependencies(baseDirInput) {
5643
6186
  if (!where.inside) return unwritable(`\uC2E4\uC81C \uC704\uCE58(${where.realPath})\uAC00 \uD504\uB85C\uC81D\uD2B8 \uB514\uB809\uD130\uB9AC \uBC16\uC785\uB2C8\uB2E4`);
5644
6187
  let text;
5645
6188
  try {
5646
- text = readFileSync5(pkgFile, "utf8");
6189
+ text = readFileSync6(pkgFile, "utf8");
5647
6190
  } catch (err) {
5648
6191
  return unwritable(err.message);
5649
6192
  }
@@ -5681,12 +6224,12 @@ function planUtilsDependencies(baseDirInput) {
5681
6224
  const after = bom + formatJsonLike(body, { ...pkg, dependencies: deps });
5682
6225
  return { ...plan, action: "add", write: { file: pkgFile, before: text, after } };
5683
6226
  }
5684
- var defaultWriteFile = (file, data) => writeFileSync2(file, data);
6227
+ var defaultWriteFile = (file, data) => writeFileSync3(file, data);
5685
6228
  function applyUtilsDependencies(baseDirInput, plan, writeFile = defaultWriteFile) {
5686
6229
  const w = plan.write;
5687
6230
  if (plan.action !== "add" || !w) return false;
5688
6231
  const baseDir = path14.resolve(baseDirInput);
5689
- const current = existsSync5(w.file) ? readFileSync5(w.file, "utf8") : null;
6232
+ const current = existsSync6(w.file) ? readFileSync6(w.file, "utf8") : null;
5690
6233
  if (current !== w.before) {
5691
6234
  throw new Error(`${w.file} \uC774 \uACC4\uD68D \uB4A4\uC5D0 \uBC14\uB00C\uC5C8\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694.`);
5692
6235
  }
@@ -5702,7 +6245,7 @@ function applyUtilsDependencies(baseDirInput, plan, writeFile = defaultWriteFile
5702
6245
  let restored;
5703
6246
  try {
5704
6247
  writeFile(w.file, w.before);
5705
- 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");
6248
+ 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");
5706
6249
  restored = "\uC6D0\uB798 \uB0B4\uC6A9\uC73C\uB85C \uB418\uB3CC\uB838\uC2B5\uB2C8\uB2E4";
5707
6250
  } catch (restoreErr) {
5708
6251
  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`;
@@ -5716,6 +6259,8 @@ function reportDependencies(plan, log) {
5716
6259
  const rootPresent = plan.present.filter((p) => p.source === "root").map((p) => p.name);
5717
6260
  const rootNote = rootPresent.length > 0 ? ` (\uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uB8E8\uD2B8\uC5D0 \uC120\uC5B8: ${rootPresent.join(", ")})` : "";
5718
6261
  const basis = ` tailwind-merge \uBC94\uC704 \uAE30\uC900: ${describeTailwindBasis(plan.tailwind)}`;
6262
+ const installPhrase2 = installCommandPhrase(plan.installCommand, rootPresent.length > 0);
6263
+ const installText = installPhrase2 === plan.installCommand ? chalk10.cyan(plan.installCommand) : `\uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uB8E8\uD2B8\uC5D0\uC11C ${chalk10.cyan(plan.installCommand)}`;
5719
6264
  const logBasis = () => {
5720
6265
  log(chalk10.gray(basis));
5721
6266
  for (const w of tailwindWarnings(plan.tailwind, plan.installCommand)) log(chalk10.yellow(` ${w}`));
@@ -5725,10 +6270,10 @@ function reportDependencies(plan, log) {
5725
6270
  log(chalk10.green(`\u2713 package.json dependencies \uC5D0 \uCD94\uAC00: ${addedText}`));
5726
6271
  if (plan.present.length > 0) log(chalk10.gray(` \uC774\uBBF8 \uC788\uC74C(\uBC84\uC804 \uC720\uC9C0): ${presentText}${rootNote}`));
5727
6272
  if (plan.added.includes("tailwind-merge")) logBasis();
5728
- log(chalk10.yellow(` \uC124\uCE58\uB294 \uC2E4\uD589\uD558\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. \uC124\uCE58: ${chalk10.cyan(plan.installCommand)}`));
6273
+ log(chalk10.yellow(` \uC124\uCE58\uB294 \uC2E4\uD589\uD558\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. \uC124\uCE58: ${installText}`));
5729
6274
  } else if (plan.action === "present") {
5730
6275
  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}`));
5731
- log(chalk10.yellow(` \uC124\uCE58\uB294 \uC2E4\uD589\uD558\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. \uC124\uCE58: ${chalk10.cyan(plan.installCommand)}`));
6276
+ log(chalk10.yellow(` \uC124\uCE58\uB294 \uC2E4\uD589\uD558\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. \uC124\uCE58: ${installText}`));
5732
6277
  } else if (plan.action === "no-package-json") {
5733
6278
  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."));
5734
6279
  log(chalk10.yellow(` \uC124\uCE58: ${chalk10.cyan(plan.addCommand)}`));
@@ -5787,7 +6332,7 @@ function planUtilsWrite(baseDirInput, utilsPath) {
5787
6332
  const shown = path14.relative(baseDir, utilsPath).split(path14.sep).join("/") || utilsPath;
5788
6333
  let st;
5789
6334
  try {
5790
- st = lstatSync3(utilsPath);
6335
+ st = lstatSync4(utilsPath);
5791
6336
  } catch (e) {
5792
6337
  if (e.code === "ENOENT") return { action: "create" };
5793
6338
  return { action: "reject", reason: `${shown} \uC758 \uC815\uBCF4\uB97C \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4(${errCode(e)})` };
@@ -5795,13 +6340,13 @@ function planUtilsWrite(baseDirInput, utilsPath) {
5795
6340
  if (st.isSymbolicLink()) {
5796
6341
  let real;
5797
6342
  try {
5798
- real = realpathSync4(utilsPath);
6343
+ real = realpathSync5(utilsPath);
5799
6344
  } catch {
5800
6345
  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` };
5801
6346
  }
5802
6347
  let outside = null;
5803
6348
  try {
5804
- outside = isSameOrInside(realpathSync4(baseDir), real) ? null : real;
6349
+ outside = isSameOrInside(realpathSync5(baseDir), real) ? null : real;
5805
6350
  } catch {
5806
6351
  outside = null;
5807
6352
  }
@@ -5815,7 +6360,7 @@ function planUtilsWrite(baseDirInput, utilsPath) {
5815
6360
  if (!target.isFile()) return { action: "reject", reason: `${shown} \uB9C1\uD06C \uB300\uC0C1(${real})\uC774 \uC77C\uBC18 \uD30C\uC77C\uC774 \uC544\uB2D9\uB2C8\uB2E4` };
5816
6361
  let content2;
5817
6362
  try {
5818
- content2 = readFileSync5(utilsPath, "utf8");
6363
+ content2 = readFileSync6(utilsPath, "utf8");
5819
6364
  } catch (e) {
5820
6365
  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)})` };
5821
6366
  }
@@ -5830,7 +6375,7 @@ function planUtilsWrite(baseDirInput, utilsPath) {
5830
6375
  if (!st.isFile()) return { action: "reject", reason: `${shown} \uC774 \uC77C\uBC18 \uD30C\uC77C\uC774 \uC544\uB2C8\uB77C \uC4F0\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4` };
5831
6376
  let content;
5832
6377
  try {
5833
- content = readFileSync5(utilsPath, "utf8");
6378
+ content = readFileSync6(utilsPath, "utf8");
5834
6379
  } catch (e) {
5835
6380
  return { action: "reject", reason: `\uAE30\uC874 ${shown} \uC744 \uC77D\uC9C0 \uBABB\uD574 \uBE44\uAD50\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4(${errCode(e)})` };
5836
6381
  }
@@ -6042,18 +6587,18 @@ function registerInitCommand(program2, registryUrl = DEFAULT_REGISTRY_URL, deps
6042
6587
  import chalk12 from "chalk";
6043
6588
 
6044
6589
  // ../axis-registry-core/src/add/add.ts
6045
- import { existsSync as existsSync7, readFileSync as readFileSync7, statSync as statSync5 } from "fs";
6590
+ import { existsSync as existsSync8, readFileSync as readFileSync8, statSync as statSync5 } from "fs";
6046
6591
  import path16 from "path";
6047
6592
  import fs13 from "fs-extra";
6048
6593
 
6049
6594
  // ../axis-registry-core/src/registry/bundled.ts
6050
- import { existsSync as existsSync6, readFileSync as readFileSync6 } from "fs";
6595
+ import { existsSync as existsSync7, readFileSync as readFileSync7 } from "fs";
6051
6596
  import path15 from "path";
6052
6597
  import { fileURLToPath } from "url";
6053
6598
  function findBundledRegistryDir(moduleUrl = import.meta.url) {
6054
6599
  const here = path15.dirname(fileURLToPath(moduleUrl));
6055
6600
  for (const dir of [path15.join(here, "registry"), path15.join(here, "..", "registry")]) {
6056
- if (existsSync6(path15.join(dir, "index.json"))) return dir;
6601
+ if (existsSync7(path15.join(dir, "index.json"))) return dir;
6057
6602
  }
6058
6603
  return null;
6059
6604
  }
@@ -6061,7 +6606,7 @@ function readBundledJson(dir, fileName) {
6061
6606
  const file = path15.join(dir, fileName);
6062
6607
  let text;
6063
6608
  try {
6064
- text = readFileSync6(file, "utf8");
6609
+ text = readFileSync7(file, "utf8");
6065
6610
  } catch {
6066
6611
  throw new Error(`\uB3D9\uBD09 \uB808\uC9C0\uC2A4\uD2B8\uB9AC\uC5D0 ${fileName} \uAC00 \uC5C6\uC2B5\uB2C8\uB2E4(${dir})`);
6067
6612
  }
@@ -6776,7 +7321,7 @@ function missingDependencies(root, items) {
6776
7321
  const installCommand = detectInstallCommand(root);
6777
7322
  let pkg;
6778
7323
  try {
6779
- const text = readFileSync7(path16.join(root, "package.json"), "utf8").replace(/^\uFEFF/, "");
7324
+ const text = readFileSync8(path16.join(root, "package.json"), "utf8").replace(/^\uFEFF/, "");
6780
7325
  const parsed = JSON.parse(text);
6781
7326
  pkg = isPlainObject(parsed) ? parsed : void 0;
6782
7327
  } catch {
@@ -6891,12 +7436,12 @@ async function runAdd(cwd, requested, options, ctx) {
6891
7436
  const existing = /* @__PURE__ */ new Map();
6892
7437
  const readErrors = [];
6893
7438
  for (const file of plan.files) {
6894
- if (!existsSync7(file.target)) {
7439
+ if (!existsSync8(file.target)) {
6895
7440
  existing.set(file, null);
6896
7441
  continue;
6897
7442
  }
6898
7443
  try {
6899
- existing.set(file, readFileSync7(file.target, "utf8"));
7444
+ existing.set(file, readFileSync8(file.target, "utf8"));
6900
7445
  } catch (e) {
6901
7446
  readErrors.push(
6902
7447
  `${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})`