@axis-ds/mcp 1.4.7 → 1.4.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.
Files changed (3) hide show
  1. package/README.md +2 -1
  2. package/dist/index.js +345 -81
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -41,7 +41,8 @@ Claude Desktop 또는 기타 MCP 호환 클라이언트에서 설정:
41
41
  - 이름은 레지스트리 이름 그대로입니다. Agentic UI 는 `agentic-` 접두를 붙입니다(예: `agentic-run-progress`). 의존 항목(`utils` · `agentic-a11y-labels`)은 함께 설치됩니다.
42
42
  - `targetDir` 는 이미 있는 프로젝트 루트입니다(상대 경로는 서버의 현재 디렉터리 기준). `axis.config.json` 이 있으면 그 `componentsDir` · `agenticDir` 에, 없으면 `components/ui` · `components/agentic` 에 설치하고 그 사실을 알립니다. 프로젝트 밖으로 나가는 경로는 아무것도 쓰지 않고 실패합니다.
43
43
  - 내용이 다른 기존 파일은 덮어쓰지 않고 건너뛰며 응답 첫머리에 건너뛴 수를 적습니다. `overwrite: true` 일 때만 덮어씁니다.
44
- - 의존성은 설치하지 않고 lockfile 에 맞는 명령(`pnpm add` · `npm install` · `yarn add`)만 안내합니다. lockfile 이 없으면 `package.json` 의 `packageManager` 를 봅니다(1.4.2 부터). `axis.apply_template` 의 「필요한 의존성」 · `axis.list_brands` · `axis.get_brand` 의 설치 안내도 1.4.2 부터 같은 방식으로 `targetDir` 의 매니저를 따릅니다(1.4.1 까지는 `pnpm` 고정).
44
+ - 의존성은 설치하지 않고 lockfile 에 맞는 명령(`pnpm add` · `npm install` · `yarn add`)만 안내합니다. 워크스페이스 루트 `package.json` 에 선언된 의존성은 안내하지 않고, 1.4.8 다음 patch 부터(WI-0095) Yarn Plug'n'Play 에서는 루트에만 선언한 의존성도 앱이 해석하지 못하므로 안내 명령에 넣습니다(CLI `axis add` 와 같음). lockfile 이 없으면 `package.json` 의 `packageManager` 를 봅니다(1.4.2 부터). `axis.apply_template` 의 「필요한 의존성」 · `axis.list_brands` · `axis.get_brand` 의 설치 안내도 1.4.2 부터 같은 방식으로 `targetDir` 의 매니저를 따릅니다(1.4.1 까지는 `pnpm` 고정).
45
+ - `axis.apply_template` 은 `targetDir` 에 이미 있는 `package.json` · `axis.config.json`(템플릿 루트의 것)을 덮어쓰지 않고 CLI `axis template apply` 와 같은 규칙으로 합칩니다(WI-0088). `packageManager` 등 사용자 필드가 남고, 결과의 파일 목록에 「합치기」로 표시합니다. 파일을 쓰는 도중 실패하면 건드린 파일을 되돌리고 오류로 응답합니다. 템플릿 경로가 `targetDir` 밖(절대 경로 · `..` · 밖을 가리키는 심볼릭 링크 경유)이면 `axis.apply_template` · `axis.diff_template` 은 아무 파일도 쓰거나 읽지 않고 오류로 응답합니다.
45
46
 
46
47
  ## 토큰 도구
47
48
 
package/dist/index.js CHANGED
@@ -58,8 +58,8 @@ function listTokens(category) {
58
58
  }
59
59
  return tokens;
60
60
  }
61
- function getToken(path11) {
62
- const q = path11.trim().toLowerCase();
61
+ function getToken(path12) {
62
+ const q = path12.trim().toLowerCase();
63
63
  return loadTokens().tokens.find(
64
64
  (t) => t.path.toLowerCase() === q || (t.aliases ?? []).some((a) => a.toLowerCase() === q) || t.cssVariable.toLowerCase() === q
65
65
  );
@@ -1020,6 +1020,9 @@ function dependencyInstallGuide(baseDirInput, name, range) {
1020
1020
  ...base
1021
1021
  };
1022
1022
  }
1023
+ function installCommandPhrase(installCommand, rootDeclared) {
1024
+ return rootDeclared && packageManagerOf(installCommand) === "npm" ? `\uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uB8E8\uD2B8\uC5D0\uC11C ${installCommand}` : installCommand;
1025
+ }
1023
1026
  function isPlainObject(value) {
1024
1027
  return typeof value === "object" && value !== null && !Array.isArray(value);
1025
1028
  }
@@ -1195,20 +1198,20 @@ function splitPackageSpec(spec) {
1195
1198
  if (parts.length < n || parts.slice(0, n).some((p) => p === "" || p === "." || p === "..")) return void 0;
1196
1199
  return { name: parts.slice(0, n).join("/"), rest: parts.slice(n).join("/") };
1197
1200
  }
1198
- function resolveExportTarget(value) {
1201
+ function resolveExportTarget(value, conditions = CSS_EXPORT_CONDITIONS) {
1199
1202
  if (typeof value === "string") return value;
1200
1203
  if (Array.isArray(value)) {
1201
1204
  for (const v of value) {
1202
- const r = resolveExportTarget(v);
1205
+ const r = resolveExportTarget(v, conditions);
1203
1206
  if (r !== void 0) return r;
1204
1207
  }
1205
1208
  return void 0;
1206
1209
  }
1207
1210
  if (isPlainObject(value)) {
1208
1211
  for (const [key, v] of Object.entries(value)) {
1209
- if (!CSS_EXPORT_CONDITIONS.has(key)) continue;
1212
+ if (!conditions.has(key)) continue;
1210
1213
  if (v === null) return void 0;
1211
- const r = resolveExportTarget(v);
1214
+ const r = resolveExportTarget(v, conditions);
1212
1215
  if (r !== void 0) return r;
1213
1216
  }
1214
1217
  }
@@ -1217,10 +1220,10 @@ function resolveExportTarget(value) {
1217
1220
  function cssFileCandidates(p) {
1218
1221
  return [p, `${p}.css`, path3.join(p, "index.css")];
1219
1222
  }
1220
- function exportsTarget(exportsField, subpath) {
1223
+ function exportsTarget(exportsField, subpath, conditions = CSS_EXPORT_CONDITIONS) {
1221
1224
  const map = isPlainObject(exportsField) && Object.keys(exportsField).some((k) => k.startsWith(".")) ? exportsField : { ".": exportsField };
1222
1225
  if (Object.prototype.hasOwnProperty.call(map, subpath)) {
1223
- const t = resolveExportTarget(map[subpath]);
1226
+ const t = resolveExportTarget(map[subpath], conditions);
1224
1227
  if (t === void 0) return void 0;
1225
1228
  return t.includes("*") || !t.startsWith("./") ? "?" : t;
1226
1229
  }
@@ -1228,6 +1231,9 @@ function exportsTarget(exportsField, subpath) {
1228
1231
  return void 0;
1229
1232
  }
1230
1233
  function resolveCssPackageImport(fromDir, spec) {
1234
+ return resolvePackageSubpath(fromDir, spec, CSS_EXPORT_CONDITIONS, cssFileCandidates);
1235
+ }
1236
+ function resolvePackageSubpath(fromDir, spec, conditions, candidates) {
1231
1237
  const parsed = splitPackageSpec(spec);
1232
1238
  if (parsed === void 0 || parsed.rest === "") return { kind: "unknown" };
1233
1239
  const subpath = `./${parsed.rest}`;
@@ -1244,16 +1250,16 @@ function resolveCssPackageImport(fromDir, spec) {
1244
1250
  }
1245
1251
  if (manifest !== void 0 && manifest.exports) {
1246
1252
  const version = exactVersionOf(manifest.version);
1247
- const target = exportsTarget(manifest.exports, subpath);
1253
+ const target = exportsTarget(manifest.exports, subpath, conditions);
1248
1254
  if (target === "?") return { kind: "unknown" };
1249
1255
  if (target === void 0) {
1250
1256
  return version !== void 0 ? { kind: "not-exported", pkgDir, subpath, version } : { kind: "not-exported", pkgDir, subpath };
1251
1257
  }
1252
- const file = cssFileCandidates(path3.join(pkgDir, target)).find(isFile);
1258
+ const file = candidates(path3.join(pkgDir, target)).find(isFile);
1253
1259
  if (file !== void 0) return { kind: "resolved", pkgDir, file };
1254
1260
  return version !== void 0 ? { kind: "target-missing", pkgDir, subpath, target, version } : { kind: "target-missing", pkgDir, subpath, target };
1255
1261
  }
1256
- const bare = cssFileCandidates(path3.join(pkgDir, parsed.rest)).find(isFile);
1262
+ const bare = candidates(path3.join(pkgDir, parsed.rest)).find(isFile);
1257
1263
  if (bare !== void 0) return { kind: "resolved", pkgDir, file: bare };
1258
1264
  }
1259
1265
  const parent = path3.dirname(dir);
@@ -1304,6 +1310,25 @@ function cssPackageLineResolution(baseDir, lineDir, spec, otherDirs = []) {
1304
1310
  }
1305
1311
  return { kind: "ok" };
1306
1312
  }
1313
+ var JS_REQUIRE_CONDITIONS = /* @__PURE__ */ new Set(["require", "node", "module-sync", "default"]);
1314
+ var JS_IMPORT_CONDITIONS = /* @__PURE__ */ new Set(["import", "node", "module-sync", "default"]);
1315
+ function jsFileCandidates(p) {
1316
+ return [p, `${p}.js`, `${p}.json`, `${p}.node`, path3.join(p, "index.js"), path3.join(p, "index.json"), path3.join(p, "index.node")];
1317
+ }
1318
+ function tailwindConfigImportResolution(baseDir, spec, refs) {
1319
+ if (isPnpProject(baseDir)) return { kind: "ok" };
1320
+ const blocked = (conditions) => {
1321
+ const r = resolvePackageSubpath(baseDir, spec, conditions, jsFileCandidates);
1322
+ return r.kind === "not-exported" ? r : void 0;
1323
+ };
1324
+ const viaRequire = refs.require || refs.import ? blocked(JS_REQUIRE_CONDITIONS) : void 0;
1325
+ if (refs.require && viaRequire !== void 0) return viaRequire;
1326
+ if (refs.import && viaRequire !== void 0) {
1327
+ const viaImport = blocked(JS_IMPORT_CONDITIONS);
1328
+ if (viaImport !== void 0) return viaImport;
1329
+ }
1330
+ return { kind: "ok" };
1331
+ }
1307
1332
  function findPnpUnpluggedPackages(baseDirInput, name, range) {
1308
1333
  const root = pnpProjectRoot(baseDirInput);
1309
1334
  if (root === void 0) return [];
@@ -1328,6 +1353,17 @@ function findPnpUnpluggedPackages(baseDirInput, name, range) {
1328
1353
  }
1329
1354
  return found;
1330
1355
  }
1356
+ var PNP_REAL_DIR_RANGE = /^(?:workspace|portal|link):/;
1357
+ function pnpComponentSourceHidden(baseDirInput, name, range) {
1358
+ if (!isPnpProject(baseDirInput)) return false;
1359
+ const r = range.trim();
1360
+ if (PNP_REAL_DIR_RANGE.test(r)) return false;
1361
+ const probe = versionSatisfiesRange("0.0.0", r) === void 0 ? "*" : r;
1362
+ return findPnpUnpluggedPackages(baseDirInput, name, probe).length === 0;
1363
+ }
1364
+ function pnpUnplugSetupPhrase(name) {
1365
+ return `Plug'n'Play \uB8E8\uD2B8(.pnp.cjs \uAC00 \uC788\uB294 \uACF3) package.json \uC758 dependenciesMeta \uC5D0 "${name}": { "unplugged": true } \uB97C \uB450\uACE0 yarn install`;
1366
+ }
1331
1367
  function parsePartialVersion(token) {
1332
1368
  const m = /^v?(\d+|[xX*])(?:\.(\d+|[xX*]))?(?:\.(\d+|[xX*]))?(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/.exec(token.trim());
1333
1369
  if (!m) return void 0;
@@ -1440,9 +1476,6 @@ import { basename, dirname as dirname2, extname, isAbsolute, join as join2, rela
1440
1476
  function declaredRange(baseDir, pkg, name) {
1441
1477
  return declaredDependency(baseDir, pkg, name)?.range;
1442
1478
  }
1443
- function declaredRangeForCheck(baseDir, pkg, name) {
1444
- return declaredDependency(baseDir, pkg, name, void 0, { appOnlyInPnp: true })?.range;
1445
- }
1446
1479
  function isPlainObject2(value) {
1447
1480
  return typeof value === "object" && value !== null && !Array.isArray(value);
1448
1481
  }
@@ -1765,18 +1798,19 @@ function packageNameOfSpec(spec) {
1765
1798
  function displayRel(baseDir, p) {
1766
1799
  return relative(baseDir, p).split(sep).join("/");
1767
1800
  }
1768
- function packageLineShadowIssue(baseDir, expanded, origin, spec) {
1801
+ function packageLineShadowIssue(baseDir, expanded, origin, spec, opts = {}) {
1769
1802
  const name = packageNameOfSpec(spec);
1770
1803
  const lineDir = dirname2(origin.path);
1771
1804
  const others = () => [...new Set(expanded.files.map((f) => dirname2(f.path)))].filter((d) => d !== lineDir);
1772
1805
  const r = cssPackageLineResolution(baseDir, lineDir, spec, others);
1773
1806
  const head = `${spec} import \uAC00 \uC788\uC9C0\uB9CC \uADF8 \uC904\uC774 \uC788\uB294 \uD30C\uC77C \uC704\uCE58\uC5D0\uC11C`;
1774
1807
  const label = (pkgDir, version) => `${displayRel(baseDir, pkgDir)}(${version ?? "\uBC84\uC804 \uBAA8\uB984"})`;
1808
+ if (opts.tailwind3 === true && r.kind !== "shadow-not-exported") return void 0;
1775
1809
  switch (r.kind) {
1776
1810
  case "ok":
1777
1811
  return void 0;
1778
1812
  case "shadow-not-exported": {
1779
- const current = r.version !== void 0 && (compareExactVersions(r.version, TAILWIND4_MIN_AXIS_VERSION) ?? -1) >= 0;
1813
+ const current = opts.tailwind3 === true || r.version !== void 0 && (compareExactVersions(r.version, TAILWIND4_MIN_AXIS_VERSION) ?? -1) >= 0;
1780
1814
  const todo = current ? "\uB2E4\uC2DC \uC124\uCE58\uD558\uC138\uC694" : `${TAILWIND4_MIN_AXIS_VERSION} \uC774\uC0C1\uC73C\uB85C \uB9DE\uCD94\uC138\uC694`;
1781
1815
  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}`;
1782
1816
  }
@@ -1819,13 +1853,20 @@ function judgeGlobalsCss(baseDir, selection, candidate, expanded) {
1819
1853
  const origin = evidenceOrigin(expanded, (f) => findTokensCssImport(f) === imported);
1820
1854
  via = cssImportViaNote(viaFiles([origin]));
1821
1855
  const tailwind4 = (detectTailwind(baseDir, pkg).major ?? 0) >= 4;
1822
- const issue = tailwind4 && origin !== void 0 && !isOutsideEntry(origin) ? tokensCssUnresolvedIssue(
1856
+ const inside = origin !== void 0 && !isOutsideEntry(origin);
1857
+ const issue = tailwind4 && inside ? tokensCssUnresolvedIssue(
1823
1858
  baseDir,
1824
1859
  pkg,
1825
1860
  imported,
1826
1861
  void 0,
1827
1862
  () => packageLineShadowIssue(baseDir, expanded, origin, imported)
1828
- ) : tokensCssUnresolvedIssue(baseDir, pkg, imported, origin !== void 0 ? origin.cssDir : outsideCssDir(selection));
1863
+ ) : tokensCssUnresolvedIssue(
1864
+ baseDir,
1865
+ pkg,
1866
+ imported,
1867
+ origin !== void 0 ? origin.cssDir : outsideCssDir(selection),
1868
+ inside ? () => packageLineShadowIssue(baseDir, expanded, origin, imported, { tailwind3: true }) : void 0
1869
+ );
1829
1870
  if (issue !== void 0) unresolved = `${candidate}\uC5D0 ${issue}`;
1830
1871
  else pass = `${candidate}\uC5D0 AXIS CSS \uBCC0\uC218\uAC00 \uC788\uC2B5\uB2C8\uB2E4 (${imported} import)`;
1831
1872
  } else if (AXIS_VARIABLE_DEFINITION.test(stripCssComments(expanded.evidence))) {
@@ -2029,6 +2070,8 @@ function stripJsComments(src) {
2029
2070
  }
2030
2071
  var TOKENS_TAILWIND3_PRESET = "@axis-ds/tokens/tailwind";
2031
2072
  var PRESET_REFERENCE = /(?:\brequire\s*\(\s*|\bimport\s*\(\s*|\bfrom\s*|\bimport\s+)(["'])@axis-ds\/tokens\/tailwind\1/;
2073
+ var PRESET_REQUIRE_REFERENCE = /\brequire\s*\(\s*(["'])@axis-ds\/tokens\/tailwind\1/;
2074
+ var PRESET_IMPORT_REFERENCE = /(?:\bimport\s*\(\s*|\bfrom\s*|\bimport\s+)(["'])@axis-ds\/tokens\/tailwind\1/;
2032
2075
  function hasTokensPresetReference(source) {
2033
2076
  return PRESET_REFERENCE.test(stripJsComments(source));
2034
2077
  }
@@ -2056,7 +2099,7 @@ function hasBareCjsPresetRequire(code) {
2056
2099
  function isCommonJsConfig(file, source) {
2057
2100
  return extname(file) === ".cjs" || /\bmodule\.exports\b/.test(source);
2058
2101
  }
2059
- function presetTokensUnresolvedMessage(baseDir, pkg, file, bareCjs) {
2102
+ function presetTokensUnresolvedMessage(baseDir, pkg, file, bareCjs, code) {
2060
2103
  const r = tokensCssResolution(baseDir, pkg, TOKENS_PACKAGE_NAME);
2061
2104
  const head = `${file}\uC5D0 AXIS preset \uCC38\uC870\uAC00 \uC788\uC9C0\uB9CC ${TOKENS_PACKAGE_NAME} \uAC00`;
2062
2105
  if (r.kind === "not-installed") {
@@ -2065,6 +2108,14 @@ function presetTokensUnresolvedMessage(baseDir, pkg, file, bareCjs) {
2065
2108
  if (r.kind === "pnp-root-only" && !bareCjs) {
2066
2109
  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`;
2067
2110
  }
2111
+ const e = tailwindConfigImportResolution(baseDir, TOKENS_TAILWIND3_PRESET, {
2112
+ require: PRESET_REQUIRE_REFERENCE.test(code),
2113
+ import: PRESET_IMPORT_REFERENCE.test(code)
2114
+ });
2115
+ if (e.kind === "not-exported") {
2116
+ const label = `${displayRel(baseDir, e.pkgDir)}(${e.version ?? "\uBC84\uC804 \uBAA8\uB984"})`;
2117
+ 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`;
2118
+ }
2068
2119
  return void 0;
2069
2120
  }
2070
2121
  function packageVersionGate(baseDirInput, pkg, name, min, options = {}) {
@@ -2119,7 +2170,8 @@ function tailwind4Issues(input, pkg, versions, baseDir) {
2119
2170
  const r = resolutions.get(name);
2120
2171
  if (r.kind === "undeclared" || r.kind === "app-lockfile") continue;
2121
2172
  if (hasComponentTailwindImport(evidence, name) || hasComponentSource(evidence, name)) continue;
2122
- if (componentCssResolvable(r)) missing.push(name);
2173
+ if (r.kind === "app" && pnpComponentSourceHidden(baseDir, name, r.range)) unresolvedMissing.push(componentCssPnpMissingIssue(name));
2174
+ else if (componentCssResolvable(r)) missing.push(name);
2123
2175
  else unresolvedMissing.push(componentCssMissingIssue(baseDir, name, r));
2124
2176
  }
2125
2177
  if (missing.length > 0) {
@@ -2135,12 +2187,17 @@ function tailwind4Issues(input, pkg, versions, baseDir) {
2135
2187
  }
2136
2188
  for (const name of TAILWIND4_COMPONENT_PACKAGES) {
2137
2189
  if (!hasComponentTailwindImport(evidence, name)) continue;
2138
- const unresolved = componentCssPresentIssue(baseDir, name, resolutions.get(name));
2190
+ const r = resolutions.get(name);
2191
+ const unresolved = componentCssPresentIssue(baseDir, name, r);
2139
2192
  const spec = `${name}/tailwind.css`;
2140
2193
  if (unresolved !== void 0) {
2141
2194
  issues.push(unresolved);
2142
2195
  continue;
2143
2196
  }
2197
+ if (r.kind === "app" && pnpComponentSourceHidden(baseDir, name, r.range)) {
2198
+ issues.push(componentCssPnpPresentIssue(name));
2199
+ continue;
2200
+ }
2144
2201
  const shadow = input.lineIssue === void 0 ? false : input.lineIssue(spec);
2145
2202
  let lineProblem;
2146
2203
  if (shadow !== false) lineProblem = shadow;
@@ -2159,6 +2216,13 @@ function componentInstallPhrase(baseDir, name, range) {
2159
2216
  const g = dependencyInstallGuide(baseDir, name, range);
2160
2217
  return g.kind === "install-at-root" ? `\uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uB8E8\uD2B8\uC5D0\uC11C ${g.installCommand}` : g.installCommand;
2161
2218
  }
2219
+ 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`;
2220
+ function componentCssPnpMissingIssue(name) {
2221
+ return `${name} \uC758 tailwind.css \uB294 ${PNP_ZIP_SOURCE_NOTE} \u2192 ${pnpUnplugSetupPhrase(name)} \uB4A4 ${componentTailwindImportLine(name)}`;
2222
+ }
2223
+ function componentCssPnpPresentIssue(name) {
2224
+ return `${name}/tailwind.css import \uAC00 \uC788\uC9C0\uB9CC ${PNP_ZIP_SOURCE_NOTE} \u2192 ${pnpUnplugSetupPhrase(name)} \uD558\uC138\uC694`;
2225
+ }
2162
2226
  function componentCssMissingIssue(baseDir, name, r) {
2163
2227
  const line = componentTailwindImportLine(name);
2164
2228
  switch (r.kind) {
@@ -2254,13 +2318,13 @@ function checkTailwindSetup(baseDirInput) {
2254
2318
  };
2255
2319
  }
2256
2320
  for (const file of TAILWIND_CONFIG_FILES) {
2257
- const path11 = join2(baseDir, file);
2258
- if (!existsSync3(path11)) continue;
2259
- const content = readFileSync4(path11, "utf8");
2321
+ const path12 = join2(baseDir, file);
2322
+ if (!existsSync3(path12)) continue;
2323
+ const content = readFileSync4(path12, "utf8");
2260
2324
  if (hasTokensPresetReference(content)) {
2261
2325
  const code = stripJsComments(content);
2262
2326
  const bareCjs = isCommonJsConfig(file, code) && hasBareCjsPresetRequire(code);
2263
- const unresolved = presetTokensUnresolvedMessage(baseDir, pkg, file, bareCjs);
2327
+ const unresolved = presetTokensUnresolvedMessage(baseDir, pkg, file, bareCjs, code);
2264
2328
  if (unresolved !== void 0) return { name: "tailwind.config", severity: "warn", message: unresolved };
2265
2329
  if (bareCjs) {
2266
2330
  const gate = packageVersionGate(baseDir, pkg, "@axis-ds/tokens", TOKENS_CJS_PRESET_FIXED_VERSION, { appOnlyInPnp: true });
@@ -2677,6 +2741,33 @@ function componentsUseAnimation(baseDir, componentsDir) {
2677
2741
  }
2678
2742
  return false;
2679
2743
  }
2744
+ function animationPluginProblem(baseDir, pkg, name, pnp) {
2745
+ const declared = declaredDependency(baseDir, pkg, name, void 0, { appOnlyInPnp: true });
2746
+ if (declared === void 0) {
2747
+ 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` };
2748
+ }
2749
+ if (!pnp && findInstalledPackage(baseDir, name) === void 0) {
2750
+ return { name, kind: "notInstalled", why: `${name} \uBBF8\uC124\uCE58(\uC120\uC5B8\uB9CC \uC788\uC74C)`, root: declared.source === "root" };
2751
+ }
2752
+ return void 0;
2753
+ }
2754
+ function inspectTailwind4Animation(baseDirInput, pkgInput) {
2755
+ const baseDir = resolveBaseDir(baseDirInput);
2756
+ const pkg = pkgInput ?? readPackageJson(baseDir);
2757
+ const pnp = isPnpProject(baseDir);
2758
+ const selection = selectCheckGlobalCss(baseDir);
2759
+ const note = globalCssSelectionNote(selection);
2760
+ const expanded = selection.path !== void 0 && selection.rel !== void 0 ? expandGlobalCss(baseDir, selection.path, selection.rel, outsideCssDir(selection)) : void 0;
2761
+ const css = expanded !== void 0 ? stripCssComments(expanded.evidence) : "";
2762
+ const twAnimate = new RegExp(`@import\\s+(?:url\\(\\s*)?["']${ANIMATION_PLUGIN_TAILWIND4}["']`);
2763
+ const animatePlugin = new RegExp(`@plugin\\s+["']${ANIMATION_PLUGIN_TAILWIND3}["']`);
2764
+ const lines = [];
2765
+ if (twAnimate.test(css)) lines.push(ANIMATION_PLUGIN_TAILWIND4);
2766
+ if (animatePlugin.test(css)) lines.push(ANIMATION_PLUGIN_TAILWIND3);
2767
+ const via = expanded !== void 0 ? cssImportViaNote(viaFiles([evidenceOrigin(expanded, (f) => twAnimate.test(f)), evidenceOrigin(expanded, (f) => animatePlugin.test(f))])) : "";
2768
+ const problems = lines.map((name) => animationPluginProblem(baseDir, pkg, name, pnp)).filter((p) => p !== void 0);
2769
+ return { selection, file: selection.rel, note, via, lines, problems };
2770
+ }
2680
2771
  function checkAnimationPlugin(baseDirInput) {
2681
2772
  const baseDir = resolveBaseDir(baseDirInput);
2682
2773
  const pkg = readPackageJson(baseDir);
@@ -2687,25 +2778,8 @@ function checkAnimationPlugin(baseDirInput) {
2687
2778
  const by = declared ? "@axis-ds/ui-react \uC120\uC5B8" : "componentsDir \uC758 animate-in \uB958 \uD074\uB798\uC2A4";
2688
2779
  const tailwind = detectTailwind(baseDir, pkg);
2689
2780
  const pnp = isPnpProject(baseDir);
2690
- const pluginProblem = (name) => {
2691
- if (declaredRangeForCheck(baseDir, pkg, name) === void 0) {
2692
- return pnpRootOnlyDependency(baseDir, pkg, name) !== void 0 ? `${name} \uAC00 ${PNP_ROOT_ONLY_NOTE}` : `${name} \uC120\uC5B8 \uC5C6\uC74C`;
2693
- }
2694
- if (!pnp && findInstalledPackage(baseDir, name) === void 0) return `${name} \uBBF8\uC124\uCE58(\uC120\uC5B8\uB9CC \uC788\uC74C)`;
2695
- return void 0;
2696
- };
2697
2781
  if (tailwind.major !== void 0 && tailwind.major >= 4) {
2698
- const selection = selectCheckGlobalCss(baseDir);
2699
- const note = globalCssSelectionNote(selection);
2700
- const file = selection.rel;
2701
- const expanded = selection.path !== void 0 && selection.rel !== void 0 ? expandGlobalCss(baseDir, selection.path, selection.rel, outsideCssDir(selection)) : void 0;
2702
- const css = expanded !== void 0 ? stripCssComments(expanded.evidence) : "";
2703
- const twAnimate = new RegExp(`@import\\s+(?:url\\(\\s*)?["']${ANIMATION_PLUGIN_TAILWIND4}["']`);
2704
- const animatePlugin = new RegExp(`@plugin\\s+["']${ANIMATION_PLUGIN_TAILWIND3}["']`);
2705
- const lines = [];
2706
- if (twAnimate.test(css)) lines.push(ANIMATION_PLUGIN_TAILWIND4);
2707
- if (animatePlugin.test(css)) lines.push(ANIMATION_PLUGIN_TAILWIND3);
2708
- const via = expanded !== void 0 ? cssImportViaNote(viaFiles([evidenceOrigin(expanded, (f) => twAnimate.test(f)), evidenceOrigin(expanded, (f) => animatePlugin.test(f))])) : "";
2782
+ const { file, note, via, lines, problems } = inspectTailwind4Animation(baseDir, pkg);
2709
2783
  if (lines.length === 0) {
2710
2784
  return {
2711
2785
  name: "animation",
@@ -2713,7 +2787,6 @@ function checkAnimationPlugin(baseDirInput) {
2713
2787
  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}`
2714
2788
  };
2715
2789
  }
2716
- const problems = lines.map((name) => ({ name, why: pluginProblem(name) })).filter((x) => x.why !== void 0);
2717
2790
  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}` };
2718
2791
  return {
2719
2792
  name: "animation",
@@ -2724,7 +2797,7 @@ function checkAnimationPlugin(baseDirInput) {
2724
2797
  const configFile = TAILWIND_CONFIG_FILES.find((f) => existsSync3(join2(baseDir, f)));
2725
2798
  const source = configFile !== void 0 ? stripJsComments(readFileSync4(join2(baseDir, configFile), "utf8")) : "";
2726
2799
  const plugins = configFile !== void 0 ? readAnimationPluginUse(source) : "absent";
2727
- const pluginReason = pluginProblem(ANIMATION_PLUGIN_TAILWIND3);
2800
+ const pluginReason = animationPluginProblem(baseDir, pkg, ANIMATION_PLUGIN_TAILWIND3, pnp)?.why;
2728
2801
  if (plugins === "found" && pluginReason === void 0) {
2729
2802
  return { name: "animation", severity: "pass", message: `${configFile}\uC758 plugins \uC5D0 ${ANIMATION_PLUGIN_TAILWIND3} \uAC00 \uC788\uC2B5\uB2C8\uB2E4` };
2730
2803
  }
@@ -3238,7 +3311,7 @@ function missingDependencies(root, items) {
3238
3311
  for (const item of items) {
3239
3312
  for (const dep of item.dependencies) {
3240
3313
  const name = dependencyName(dep);
3241
- if (declaredDependency(root, pkg, name, rootPkg) !== void 0) continue;
3314
+ if (declaredDependency(root, pkg, name, rootPkg, { appOnlyInPnp: true }) !== void 0) continue;
3242
3315
  if (name in specs) continue;
3243
3316
  const explicit = dep.length > name.length ? dep.slice(name.length + 1) : void 0;
3244
3317
  specs[name] = explicit ?? ranges[name];
@@ -3690,11 +3763,11 @@ async function handleGetComponent(params, deps = {}) {
3690
3763
  return { component, source: describeOrigin(client, latest.version), notices };
3691
3764
  }
3692
3765
  function handleGetToken(params) {
3693
- const { path: path11 } = params;
3694
- if (!path11 || path11.trim() === "") {
3766
+ const { path: path12 } = params;
3767
+ if (!path12 || path12.trim() === "") {
3695
3768
  throw new Error("\uD1A0\uD070 \uACBD\uB85C(path)\uB294 \uD544\uC218\uC785\uB2C8\uB2E4.");
3696
3769
  }
3697
- const token = getToken(path11);
3770
+ const token = getToken(path12);
3698
3771
  if (!token) {
3699
3772
  return null;
3700
3773
  }
@@ -3775,9 +3848,9 @@ function cssUsage(token) {
3775
3848
  const shadcnColor = !token.cssVariable.startsWith("--axis-") && token.value.startsWith("hsl(");
3776
3849
  return shadcnColor ? `hsl(var(${token.cssVariable}))` : `var(${token.cssVariable})`;
3777
3850
  }
3778
- function formatTokenNotFound(path11) {
3851
+ function formatTokenNotFound(path12) {
3779
3852
  return [
3780
- `\uD1A0\uD070\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: \`${path11}\``,
3853
+ `\uD1A0\uD070\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: \`${path12}\``,
3781
3854
  "",
3782
3855
  "- \uACBD\uB85C\uB294 `axis.list_tokens` \uB85C \uD655\uC778\uD558\uC138\uC694. \uACBD\uB85C \xB7 tokens \uC774\uB984 \uAE30\uBC18 \uACBD\uB85C(\uC608: `control.h.md`) \xB7 CSS \uBCC0\uC218 \uC774\uB984(\uC608: `--axis-control-h-md`)\uC744 \uBC1B\uC2B5\uB2C8\uB2E4.",
3783
3856
  "- \uBE0C\uB79C\uB4DC \uAC12\uC740 `axis.list_brands` \xB7 `axis.get_brand` \uB85C \uC870\uD68C\uD558\uC138\uC694."
@@ -5475,7 +5548,7 @@ function formatSaveResult(result) {
5475
5548
  // src/tools/template.ts
5476
5549
  import fetch from "node-fetch";
5477
5550
  import fs6 from "fs-extra";
5478
- import path9 from "path";
5551
+ import path10 from "path";
5479
5552
 
5480
5553
  // src/tools/brand-core.ts
5481
5554
  import { createHash as createHash2 } from "crypto";
@@ -6035,11 +6108,15 @@ function checkDependencies(baseDirInput) {
6035
6108
  if (missingRecommended.length > 0) problems.push(`\uAD8C\uC7A5 \uC758\uC874\uC131 \uB204\uB77D: ${missingRecommended.join(", ")}`);
6036
6109
  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`);
6037
6110
  if (pnpRootAxis.length > 0) problems.push(`${pnpRootAxis.join(", ")} \uAC00 ${PNP_ROOT_ONLY_NOTE} \u2192 \uC571 package.json \uC5D0 \uC120\uC5B8\uD558\uC138\uC694`);
6111
+ const installCommand = detectInstallCommand(baseDir);
6038
6112
  if (notInstalledOther.length > 0) {
6039
- problems.push(`\uC120\uC5B8\uB410\uC9C0\uB9CC \uC124\uCE58\uB418\uC9C0 \uC54A\uC740 \uC758\uC874\uC131: ${notInstalledOther.join(", ")} \u2192 ${detectInstallCommand(baseDir)}`);
6113
+ const phrase = installCommandPhrase(installCommand, notInstalledOther.some((d) => fromRoot(d)));
6114
+ problems.push(`\uC120\uC5B8\uB410\uC9C0\uB9CC \uC124\uCE58\uB418\uC9C0 \uC54A\uC740 \uC758\uC874\uC131: ${notInstalledOther.join(", ")} \u2192 ${phrase}`);
6040
6115
  }
6041
6116
  if (notInstalledRoot.length > 0) {
6042
- 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)}`);
6117
+ problems.push(
6118
+ `\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)}`
6119
+ );
6043
6120
  }
6044
6121
  if (problems.length > 0) {
6045
6122
  return { name: "dependencies", severity: "warn", message: problems.join(" / ") + (rootNote ? ` (${rootNote})` : "") };
@@ -6052,6 +6129,192 @@ function checkDependencies(baseDirInput) {
6052
6129
  };
6053
6130
  }
6054
6131
 
6132
+ // ../axis-registry-core/src/template/apply-files.ts
6133
+ import { existsSync as existsSync9, lstatSync as lstatSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync10, readdirSync as readdirSync3, realpathSync as realpathSync4, rmdirSync, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
6134
+ import path9 from "path";
6135
+ var TemplatePathError = class extends Error {
6136
+ constructor(relPath, reason) {
6137
+ 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`);
6138
+ this.relPath = relPath;
6139
+ this.reason = reason;
6140
+ this.name = "TemplatePathError";
6141
+ }
6142
+ };
6143
+ function realpathOfExisting(p) {
6144
+ const rest = [];
6145
+ let cur = p;
6146
+ for (; ; ) {
6147
+ try {
6148
+ lstatSync3(cur);
6149
+ break;
6150
+ } catch {
6151
+ const parent = path9.dirname(cur);
6152
+ if (parent === cur) break;
6153
+ rest.unshift(path9.basename(cur));
6154
+ cur = parent;
6155
+ }
6156
+ }
6157
+ try {
6158
+ return path9.join(realpathSync4(cur), ...rest);
6159
+ } catch {
6160
+ return void 0;
6161
+ }
6162
+ }
6163
+ function isInside(root, target) {
6164
+ const rel2 = path9.relative(root, target);
6165
+ return rel2 !== "" && !rel2.startsWith("..") && !path9.isAbsolute(rel2);
6166
+ }
6167
+ function resolveTemplatePath(baseDir, relPath) {
6168
+ if (typeof relPath !== "string" || relPath === "" || relPath.includes("\0")) {
6169
+ throw new TemplatePathError(String(relPath), "\uBE48 \uACBD\uB85C \uB610\uB294 \uC798\uBABB\uB41C \uBB38\uC790");
6170
+ }
6171
+ if (path9.isAbsolute(relPath) || path9.win32.isAbsolute(relPath)) throw new TemplatePathError(relPath, "\uC808\uB300 \uACBD\uB85C");
6172
+ const base = path9.resolve(baseDir);
6173
+ const dest = path9.resolve(base, relPath);
6174
+ if (!isInside(base, dest)) throw new TemplatePathError(relPath, "\uC0C1\uC704 \uB514\uB809\uD130\uB9AC\uB85C \uB098\uAC10");
6175
+ const baseReal = realpathOfExisting(base);
6176
+ const destReal = realpathOfExisting(dest);
6177
+ if (!baseReal || !destReal || !isInside(baseReal, destReal)) {
6178
+ throw new TemplatePathError(relPath, "\uC2EC\uBCFC\uB9AD \uB9C1\uD06C\uAC00 \uB300\uC0C1 \uB514\uB809\uD130\uB9AC \uBC16\uC744 \uAC00\uB9AC\uD0B4");
6179
+ }
6180
+ return dest;
6181
+ }
6182
+ function assertTemplatePaths(baseDir, relPaths) {
6183
+ for (const p of relPaths) resolveTemplatePath(baseDir, p);
6184
+ }
6185
+ var PACKAGE_JSON_MERGED_MAPS = [
6186
+ "scripts",
6187
+ "dependencies",
6188
+ "devDependencies",
6189
+ "peerDependencies",
6190
+ "optionalDependencies"
6191
+ ];
6192
+ function isPlainObject3(v) {
6193
+ return typeof v === "object" && v !== null && !Array.isArray(v);
6194
+ }
6195
+ function parseObject(text) {
6196
+ try {
6197
+ const v = JSON.parse(text);
6198
+ return isPlainObject3(v) ? v : void 0;
6199
+ } catch {
6200
+ return void 0;
6201
+ }
6202
+ }
6203
+ function mergePackageJson(user, template) {
6204
+ const maps = new Set(PACKAGE_JSON_MERGED_MAPS);
6205
+ const out = {};
6206
+ for (const [key, value] of Object.entries(user)) {
6207
+ const tpl = template[key];
6208
+ if (maps.has(key) && isPlainObject3(tpl)) {
6209
+ out[key] = isPlainObject3(value) ? { ...value, ...tpl } : tpl;
6210
+ } else {
6211
+ out[key] = value;
6212
+ }
6213
+ }
6214
+ for (const [key, value] of Object.entries(template)) {
6215
+ if (!(key in out)) out[key] = value;
6216
+ }
6217
+ return out;
6218
+ }
6219
+ function mergeAxisConfigJson(user, template) {
6220
+ return { ...user, ...template };
6221
+ }
6222
+ function detectJsonIndent(text) {
6223
+ const m = /^([ \t]+)\S/m.exec(text);
6224
+ if (!m) return 2;
6225
+ return m[1].startsWith(" ") ? " " : m[1].length;
6226
+ }
6227
+ function serializeLike(before, value) {
6228
+ const crlf = before.includes("\r\n");
6229
+ const trailing = /\r?\n$/.test(before);
6230
+ let text = JSON.stringify(value, null, detectJsonIndent(before));
6231
+ if (trailing) text += "\n";
6232
+ return crlf ? text.replace(/\n/g, "\r\n") : text;
6233
+ }
6234
+ var MERGERS = {
6235
+ "package.json": mergePackageJson,
6236
+ "axis.config.json": mergeAxisConfigJson
6237
+ };
6238
+ function planTemplateFileContent(relPath, templateContent, before) {
6239
+ if (before === void 0) return { action: "created", content: templateContent };
6240
+ const merger = MERGERS[relPath.replace(/^\.\//, "")];
6241
+ if (!merger) return { action: "overwritten", content: templateContent };
6242
+ const user = parseObject(before);
6243
+ const template = parseObject(templateContent);
6244
+ if (!user || !template) {
6245
+ return {
6246
+ action: "overwritten",
6247
+ content: templateContent,
6248
+ 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`
6249
+ };
6250
+ }
6251
+ return { action: "merged", content: serializeLike(before, merger(user, template)) };
6252
+ }
6253
+ function planTemplateFiles(baseDir, files, extraPaths = []) {
6254
+ const dests = files.map((file) => resolveTemplatePath(baseDir, file.path));
6255
+ assertTemplatePaths(baseDir, extraPaths);
6256
+ return files.map((file, i) => {
6257
+ const dest = dests[i];
6258
+ const before = existsSync9(dest) ? readFileSync10(dest, "utf8") : void 0;
6259
+ return { path: file.path, dest, before, ...planTemplateFileContent(file.path, file.content, before) };
6260
+ });
6261
+ }
6262
+ var TemplateApplyError = class extends Error {
6263
+ constructor(message, restored, unrestored) {
6264
+ super(message);
6265
+ this.restored = restored;
6266
+ this.unrestored = unrestored;
6267
+ this.name = "TemplateApplyError";
6268
+ }
6269
+ };
6270
+ function writeTemplateFiles(plan) {
6271
+ const done = [];
6272
+ const madeDirs = [];
6273
+ try {
6274
+ for (const item of plan) {
6275
+ const dir = path9.dirname(item.dest);
6276
+ if (!existsSync9(dir)) {
6277
+ const fresh = [];
6278
+ for (let d = dir; !existsSync9(d); d = path9.dirname(d)) fresh.unshift(d);
6279
+ mkdirSync2(dir, { recursive: true });
6280
+ madeDirs.push(...fresh);
6281
+ }
6282
+ writeFileSync2(item.dest, item.content);
6283
+ done.push(item);
6284
+ }
6285
+ } catch (err) {
6286
+ const restored = [];
6287
+ const unrestored = [];
6288
+ const failed = plan[done.length];
6289
+ const targets = failed ? [...done, failed] : done;
6290
+ for (const item of targets.reverse()) {
6291
+ try {
6292
+ if (item.before === void 0) {
6293
+ if (existsSync9(item.dest)) unlinkSync(item.dest);
6294
+ } else {
6295
+ writeFileSync2(item.dest, item.before);
6296
+ }
6297
+ restored.push(item.path);
6298
+ } catch {
6299
+ unrestored.push(item.path);
6300
+ }
6301
+ }
6302
+ for (const d of madeDirs.reverse()) {
6303
+ try {
6304
+ if (existsSync9(d) && readdirSync3(d).length === 0) rmdirSync(d);
6305
+ } catch {
6306
+ }
6307
+ }
6308
+ const reason = err instanceof Error ? err.message : String(err);
6309
+ const tail = unrestored.length > 0 ? ` \uB418\uB3CC\uB9AC\uC9C0 \uBABB\uD55C \uD30C\uC77C: ${unrestored.join(", ")}` : "";
6310
+ throw new TemplateApplyError(
6311
+ `\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}`,
6312
+ restored.reverse(),
6313
+ unrestored
6314
+ );
6315
+ }
6316
+ }
6317
+
6055
6318
  // src/site.ts
6056
6319
  var AXIS_SITE_URL2 = "https://axis-design-system.pages.dev";
6057
6320
 
@@ -6105,24 +6368,18 @@ async function handleGetTemplate(params) {
6105
6368
  }
6106
6369
  async function handleApplyTemplate(params) {
6107
6370
  const detail = await fetchTemplateDetail(params.name);
6108
- const baseDir = path9.resolve(params.targetDir);
6371
+ const baseDir = path10.resolve(params.targetDir);
6109
6372
  const installCommand = detectInstallCommand(baseDir);
6110
- const files = [];
6111
- for (const file of detail.files) {
6112
- const dest = path9.join(baseDir, file.path);
6113
- const exists = await fs6.pathExists(dest);
6114
- if (!params.dryRun) {
6115
- await fs6.ensureDir(path9.dirname(dest));
6116
- await fs6.writeFile(dest, file.content);
6117
- }
6118
- files.push({
6119
- path: file.path,
6120
- action: exists ? "overwritten" : "created"
6121
- });
6122
- }
6373
+ const plan = planTemplateFiles(baseDir, detail.files, (detail.postInstall ?? []).map((p) => p.file));
6374
+ if (!params.dryRun) writeTemplateFiles(plan);
6375
+ const files = plan.map((item) => ({
6376
+ path: item.path,
6377
+ action: item.action,
6378
+ ...item.note ? { note: item.note } : {}
6379
+ }));
6123
6380
  if (!params.dryRun && detail.postInstall?.length) {
6124
6381
  for (const patch of detail.postInstall) {
6125
- const target = path9.join(baseDir, patch.file);
6382
+ const target = resolveTemplatePath(baseDir, patch.file);
6126
6383
  if (!await fs6.pathExists(target)) continue;
6127
6384
  if (patch.type === "replace" && patch.search && patch.value) {
6128
6385
  const content = await fs6.readFile(target, "utf-8");
@@ -6150,10 +6407,11 @@ async function handleApplyTemplate(params) {
6150
6407
  }
6151
6408
  async function handleDiffTemplate(params) {
6152
6409
  const detail = await fetchTemplateDetail(params.name);
6153
- const baseDir = path9.resolve(params.targetDir || ".");
6410
+ const baseDir = path10.resolve(params.targetDir || ".");
6154
6411
  const entries = [];
6155
- for (const file of detail.files) {
6156
- const localPath = path9.join(baseDir, file.path);
6412
+ const localPaths = detail.files.map((file) => resolveTemplatePath(baseDir, file.path));
6413
+ for (const [i, file] of detail.files.entries()) {
6414
+ const localPath = localPaths[i];
6157
6415
  if (!await fs6.pathExists(localPath)) {
6158
6416
  entries.push({ path: file.path, status: "added" });
6159
6417
  continue;
@@ -6241,9 +6499,9 @@ function brandActivationResult(check) {
6241
6499
  };
6242
6500
  }
6243
6501
  async function handleCheckProject(params) {
6244
- const baseDir = path9.resolve(params.targetDir || ".");
6502
+ const baseDir = path10.resolve(params.targetDir || ".");
6245
6503
  const results = [];
6246
- const configExists = await fs6.pathExists(path9.join(baseDir, "axis.config.json"));
6504
+ const configExists = await fs6.pathExists(path10.join(baseDir, "axis.config.json"));
6247
6505
  results.push({
6248
6506
  name: "axis.config.json",
6249
6507
  severity: configExists ? "pass" : "fail",
@@ -6260,7 +6518,7 @@ async function handleCheckProject(params) {
6260
6518
  ];
6261
6519
  let utilsFound = false;
6262
6520
  for (const candidate of utilsCandidates) {
6263
- const fullPath = path9.join(baseDir, candidate);
6521
+ const fullPath = path10.join(baseDir, candidate);
6264
6522
  if (await fs6.pathExists(fullPath)) {
6265
6523
  const content2 = await fs6.readFile(fullPath, "utf-8");
6266
6524
  const hasCn = content2.includes("function cn");
@@ -6351,9 +6609,15 @@ function formatApplyTemplateResult(result) {
6351
6609
  `);
6352
6610
  if (result.files.length > 0) {
6353
6611
  lines.push("### \uD30C\uC77C", "");
6612
+ const label = {
6613
+ created: "\uC0DD\uC131",
6614
+ overwritten: "\uB36E\uC5B4\uC4F0\uAE30",
6615
+ merged: "\uD569\uCE58\uAE30: \uAE30\uC874 \uD544\uB4DC\uB97C \uB450\uACE0 \uD15C\uD50C\uB9BF \uD0A4\uB97C \uD569\uCE68"
6616
+ };
6354
6617
  for (const f of result.files) {
6355
6618
  const icon = f.action === "created" ? "+" : "~";
6356
- lines.push(`- ${icon} ${f.path} (${f.action === "created" ? "\uC0DD\uC131" : "\uB36E\uC5B4\uC4F0\uAE30"})`);
6619
+ lines.push(`- ${icon} ${f.path} (${label[f.action]})`);
6620
+ if (f.note) lines.push(` - ! ${f.note}`);
6357
6621
  }
6358
6622
  }
6359
6623
  const deps = Object.entries(result.dependencies);
@@ -6405,10 +6669,10 @@ function formatCheckProjectResult(result) {
6405
6669
  }
6406
6670
 
6407
6671
  // src/tools/brand.ts
6408
- import path10 from "path";
6672
+ import path11 from "path";
6409
6673
  var TOKENS_INSTALL_COMMAND = addCommandFor("pnpm install", { [TOKENS_PACKAGE]: `^${TOKENS_DEPENDENCY_MIN_VERSION}` });
6410
6674
  function baseDirOf(targetDir) {
6411
- return path10.resolve(targetDir || process.cwd());
6675
+ return path11.resolve(targetDir || process.cwd());
6412
6676
  }
6413
6677
  function tokensInstallGuideFor(targetDir) {
6414
6678
  return dependencyInstallGuide(baseDirOf(targetDir), TOKENS_PACKAGE, `^${TOKENS_DEPENDENCY_MIN_VERSION}`);
@@ -6696,10 +6960,10 @@ server.tool(
6696
6960
  {
6697
6961
  path: z.string().describe("\uD1A0\uD070 \uACBD\uB85C (\uC608: colors.primary, spacing.4, control.h.md) \uB610\uB294 CSS \uBCC0\uC218 \uC774\uB984 (\uC608: --axis-control-h-md)")
6698
6962
  },
6699
- async ({ path: path11 }) => {
6963
+ async ({ path: path12 }) => {
6700
6964
  try {
6701
- const token = handleGetToken({ path: path11 });
6702
- const formatted = formatTokenDetail(token, path11);
6965
+ const token = handleGetToken({ path: path12 });
6966
+ const formatted = formatTokenDetail(token, path12);
6703
6967
  return {
6704
6968
  content: [
6705
6969
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axis-ds/mcp",
3
- "version": "1.4.7",
3
+ "version": "1.4.9",
4
4
  "type": "module",
5
5
  "description": "AXIS Design System - MCP Server for AI-assisted component discovery",
6
6
  "bin": {