@axis-ds/mcp 1.4.6 → 1.4.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +1 -0
  2. package/dist/index.js +756 -83
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -42,6 +42,7 @@ Claude Desktop 또는 기타 MCP 호환 클라이언트에서 설정:
42
42
  - `targetDir` 는 이미 있는 프로젝트 루트입니다(상대 경로는 서버의 현재 디렉터리 기준). `axis.config.json` 이 있으면 그 `componentsDir` · `agenticDir` 에, 없으면 `components/ui` · `components/agentic` 에 설치하고 그 사실을 알립니다. 프로젝트 밖으로 나가는 경로는 아무것도 쓰지 않고 실패합니다.
43
43
  - 내용이 다른 기존 파일은 덮어쓰지 않고 건너뛰며 응답 첫머리에 건너뛴 수를 적습니다. `overwrite: true` 일 때만 덮어씁니다.
44
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` 고정).
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
  );
@@ -237,8 +237,8 @@ function validateRegistryIndex(data, where = "index.json") {
237
237
  if (!isValidRegistryName(raw.name)) throw new Error(`${at}: name \uC774 slug \uADDC\uCE59\uC5D0 \uB9DE\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4`);
238
238
  if (seen.has(raw.name)) throw new Error(`${at}: name '${raw.name}' \uAC00 \uC911\uBCF5\uC785\uB2C8\uB2E4`);
239
239
  seen.add(raw.name);
240
- const sha256 = optionalString(raw, "sha256", at);
241
- if (sha256 !== void 0 && !/^[0-9a-f]{64}$/.test(sha256)) {
240
+ const sha2562 = optionalString(raw, "sha256", at);
241
+ if (sha2562 !== void 0 && !/^[0-9a-f]{64}$/.test(sha2562)) {
242
242
  throw new Error(`${at}: sha256 \uD615\uC2DD\uC774 \uC544\uB2D9\uB2C8\uB2E4`);
243
243
  }
244
244
  return {
@@ -246,7 +246,7 @@ function validateRegistryIndex(data, where = "index.json") {
246
246
  type: requireType(raw, at),
247
247
  title: optionalString(raw, "title", at),
248
248
  description: optionalString(raw, "description", at),
249
- ...sha256 !== void 0 ? { sha256 } : {}
249
+ ...sha2562 !== void 0 ? { sha256: sha2562 } : {}
250
250
  };
251
251
  });
252
252
  return {
@@ -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
  }
@@ -1062,6 +1065,13 @@ function isFile(file) {
1062
1065
  return false;
1063
1066
  }
1064
1067
  }
1068
+ function isDirectory(dir) {
1069
+ try {
1070
+ return statSync(dir).isDirectory();
1071
+ } catch {
1072
+ return false;
1073
+ }
1074
+ }
1065
1075
  function selectGlobalCss(baseDir, configured, candidates, options = {}) {
1066
1076
  const result = {};
1067
1077
  if (typeof configured === "string" && configured.trim() !== "") {
@@ -1181,6 +1191,144 @@ function outsideCssPackageResolution(baseDir, cssDir, name, file) {
1181
1191
  if (!usable(findInstalledPackage(baseDir, name))) return "unknown";
1182
1192
  return usable(findInstalledPackage(cssDir, name)) ? "resolved" : "unresolved";
1183
1193
  }
1194
+ var CSS_EXPORT_CONDITIONS = /* @__PURE__ */ new Set(["style", "default"]);
1195
+ function splitPackageSpec(spec) {
1196
+ const parts = spec.split("/");
1197
+ const n = spec.startsWith("@") ? 2 : 1;
1198
+ if (parts.length < n || parts.slice(0, n).some((p) => p === "" || p === "." || p === "..")) return void 0;
1199
+ return { name: parts.slice(0, n).join("/"), rest: parts.slice(n).join("/") };
1200
+ }
1201
+ function resolveExportTarget(value, conditions = CSS_EXPORT_CONDITIONS) {
1202
+ if (typeof value === "string") return value;
1203
+ if (Array.isArray(value)) {
1204
+ for (const v of value) {
1205
+ const r = resolveExportTarget(v, conditions);
1206
+ if (r !== void 0) return r;
1207
+ }
1208
+ return void 0;
1209
+ }
1210
+ if (isPlainObject(value)) {
1211
+ for (const [key, v] of Object.entries(value)) {
1212
+ if (!conditions.has(key)) continue;
1213
+ if (v === null) return void 0;
1214
+ const r = resolveExportTarget(v, conditions);
1215
+ if (r !== void 0) return r;
1216
+ }
1217
+ }
1218
+ return void 0;
1219
+ }
1220
+ function cssFileCandidates(p) {
1221
+ return [p, `${p}.css`, path3.join(p, "index.css")];
1222
+ }
1223
+ function exportsTarget(exportsField, subpath, conditions = CSS_EXPORT_CONDITIONS) {
1224
+ const map = isPlainObject(exportsField) && Object.keys(exportsField).some((k) => k.startsWith(".")) ? exportsField : { ".": exportsField };
1225
+ if (Object.prototype.hasOwnProperty.call(map, subpath)) {
1226
+ const t = resolveExportTarget(map[subpath], conditions);
1227
+ if (t === void 0) return void 0;
1228
+ return t.includes("*") || !t.startsWith("./") ? "?" : t;
1229
+ }
1230
+ if (Object.keys(map).some((k) => k.includes("*") || k.endsWith("/") && subpath.startsWith(k))) return "?";
1231
+ return void 0;
1232
+ }
1233
+ function resolveCssPackageImport(fromDir, spec) {
1234
+ return resolvePackageSubpath(fromDir, spec, CSS_EXPORT_CONDITIONS, cssFileCandidates);
1235
+ }
1236
+ function resolvePackageSubpath(fromDir, spec, conditions, candidates) {
1237
+ const parsed = splitPackageSpec(spec);
1238
+ if (parsed === void 0 || parsed.rest === "") return { kind: "unknown" };
1239
+ const subpath = `./${parsed.rest}`;
1240
+ let dir = resolveBaseDir(fromDir);
1241
+ for (; ; ) {
1242
+ const pkgDir = path3.join(dir, "node_modules", ...parsed.name.split("/"));
1243
+ if (isDirectory(pkgDir)) {
1244
+ let manifest;
1245
+ try {
1246
+ const raw = JSON.parse(readFileSync3(path3.join(pkgDir, "package.json"), "utf8"));
1247
+ manifest = isPlainObject(raw) ? raw : void 0;
1248
+ } catch {
1249
+ manifest = void 0;
1250
+ }
1251
+ if (manifest !== void 0 && manifest.exports) {
1252
+ const version = exactVersionOf(manifest.version);
1253
+ const target = exportsTarget(manifest.exports, subpath, conditions);
1254
+ if (target === "?") return { kind: "unknown" };
1255
+ if (target === void 0) {
1256
+ return version !== void 0 ? { kind: "not-exported", pkgDir, subpath, version } : { kind: "not-exported", pkgDir, subpath };
1257
+ }
1258
+ const file = candidates(path3.join(pkgDir, target)).find(isFile);
1259
+ if (file !== void 0) return { kind: "resolved", pkgDir, file };
1260
+ return version !== void 0 ? { kind: "target-missing", pkgDir, subpath, target, version } : { kind: "target-missing", pkgDir, subpath, target };
1261
+ }
1262
+ const bare = candidates(path3.join(pkgDir, parsed.rest)).find(isFile);
1263
+ if (bare !== void 0) return { kind: "resolved", pkgDir, file: bare };
1264
+ }
1265
+ const parent = path3.dirname(dir);
1266
+ if (parent === dir) return { kind: "not-found" };
1267
+ dir = parent;
1268
+ }
1269
+ }
1270
+ function installBase(pkgDir, name) {
1271
+ let base = pkgDir;
1272
+ for (let i = 0; i < name.split("/").length + 1; i++) base = path3.dirname(base);
1273
+ try {
1274
+ return realpathSync(base);
1275
+ } catch {
1276
+ return path3.resolve(base);
1277
+ }
1278
+ }
1279
+ function isAncestorInstall(hit, app, name) {
1280
+ const h = installBase(hit, name);
1281
+ const a = installBase(app, name);
1282
+ return a !== h && a.startsWith(h.endsWith(path3.sep) ? h : h + path3.sep);
1283
+ }
1284
+ function sameRealDir(a, b) {
1285
+ const real = (p) => {
1286
+ try {
1287
+ return realpathSync(p);
1288
+ } catch {
1289
+ return path3.resolve(p);
1290
+ }
1291
+ };
1292
+ return real(a) === real(b);
1293
+ }
1294
+ function cssPackageLineResolution(baseDir, lineDir, spec, otherDirs = []) {
1295
+ if (isPnpProject(baseDir)) return { kind: "ok" };
1296
+ const parsed = splitPackageSpec(spec);
1297
+ if (parsed === void 0) return { kind: "ok" };
1298
+ const r = resolveCssPackageImport(lineDir, spec);
1299
+ if (r.kind === "resolved" || r.kind === "unknown") return { kind: "ok" };
1300
+ const app = findInstalledPackage(baseDir, parsed.name);
1301
+ if (r.kind === "not-exported" || r.kind === "target-missing") {
1302
+ if (app !== void 0 && sameRealDir(app.dir, r.pkgDir)) return { kind: "ok" };
1303
+ if (app !== void 0 && isAncestorInstall(r.pkgDir, app.dir, parsed.name)) return { kind: "ok" };
1304
+ return r.kind === "not-exported" ? { ...r, kind: "shadow-not-exported" } : { ...r, kind: "shadow-target-missing" };
1305
+ }
1306
+ if (app !== void 0) return { kind: "ok" };
1307
+ for (const other of typeof otherDirs === "function" ? otherDirs() : otherDirs) {
1308
+ const o = resolveCssPackageImport(other, spec);
1309
+ if (o.kind === "resolved") return { kind: "not-visible", pkgDir: o.pkgDir, fromDir: resolveBaseDir(other) };
1310
+ }
1311
+ return { kind: "ok" };
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
+ }
1184
1332
  function findPnpUnpluggedPackages(baseDirInput, name, range) {
1185
1333
  const root = pnpProjectRoot(baseDirInput);
1186
1334
  if (root === void 0) return [];
@@ -1205,6 +1353,17 @@ function findPnpUnpluggedPackages(baseDirInput, name, range) {
1205
1353
  }
1206
1354
  return found;
1207
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
+ }
1208
1367
  function parsePartialVersion(token) {
1209
1368
  const m = /^v?(\d+|[xX*])(?:\.(\d+|[xX*]))?(?:\.(\d+|[xX*]))?(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/.exec(token.trim());
1210
1369
  if (!m) return void 0;
@@ -1618,12 +1777,12 @@ function outsideCssDir(selection) {
1618
1777
  function outsideCssUnresolvedIssue(spec, name) {
1619
1778
  return `${spec} import \uAC00 \uC788\uC9C0\uB9CC \uC774 \uD30C\uC77C \uC704\uCE58\uC5D0\uC11C ${name} \uB97C \uCC3E\uC9C0 \uBABB\uD574 \uD574\uC11D\uB418\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4(\uC124\uCE58\uBCF8\uC774 \uC571 \uCABD node_modules \uC5D0\uB9CC \uC788\uC74C) \u2192 \uC774 \uD30C\uC77C\uC758 \uC0C1\uC704 node_modules(\uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uB8E8\uD2B8 \uB4F1)\uC5D0 \uC124\uCE58\uD558\uAC70\uB098 globalCss \uB97C \uC571 \uC548 \uD30C\uC77C\uB85C \uBC14\uAFB8\uC138\uC694`;
1620
1779
  }
1621
- function tokensInstallPhrase(baseDir) {
1622
- const g = dependencyInstallGuide(baseDir, TOKENS_PACKAGE_NAME, `^${TAILWIND4_MIN_AXIS_VERSION}`);
1780
+ function tokensInstallPhrase(baseDir, range = `^${TAILWIND4_MIN_AXIS_VERSION}`) {
1781
+ const g = dependencyInstallGuide(baseDir, TOKENS_PACKAGE_NAME, range);
1623
1782
  if (g.kind === "install-at-root") return `\uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uB8E8\uD2B8\uC5D0\uC11C ${g.installCommand}`;
1624
1783
  return g.kind === "install" ? g.installCommand : g.addCommand;
1625
1784
  }
1626
- function tokensCssUnresolvedIssue(baseDir, pkg, spec, cssDir) {
1785
+ function tokensCssUnresolvedIssue(baseDir, pkg, spec, cssDir, lineIssue) {
1627
1786
  const r = tokensCssResolution(baseDir, pkg, TOKENS_PACKAGE_NAME);
1628
1787
  const head = `${spec} import \uAC00 \uC788\uC9C0\uB9CC`;
1629
1788
  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`;
@@ -1633,7 +1792,42 @@ function tokensCssUnresolvedIssue(baseDir, pkg, spec, cssDir) {
1633
1792
  if (cssDir !== void 0 && outsideCssPackageResolution(baseDir, cssDir, TOKENS_PACKAGE_NAME) === "unresolved") {
1634
1793
  return outsideCssUnresolvedIssue(spec, TOKENS_PACKAGE_NAME);
1635
1794
  }
1636
- return void 0;
1795
+ return lineIssue?.();
1796
+ }
1797
+ function packageNameOfSpec(spec) {
1798
+ const parts = spec.split("/");
1799
+ return parts.slice(0, spec.startsWith("@") ? 2 : 1).join("/");
1800
+ }
1801
+ function displayRel(baseDir, p) {
1802
+ return relative(baseDir, p).split(sep).join("/");
1803
+ }
1804
+ function packageLineShadowIssue(baseDir, expanded, origin, spec, opts = {}) {
1805
+ const name = packageNameOfSpec(spec);
1806
+ const lineDir = dirname2(origin.path);
1807
+ const others = () => [...new Set(expanded.files.map((f) => dirname2(f.path)))].filter((d) => d !== lineDir);
1808
+ const r = cssPackageLineResolution(baseDir, lineDir, spec, others);
1809
+ const head = `${spec} import \uAC00 \uC788\uC9C0\uB9CC \uADF8 \uC904\uC774 \uC788\uB294 \uD30C\uC77C \uC704\uCE58\uC5D0\uC11C`;
1810
+ const label = (pkgDir, version) => `${displayRel(baseDir, pkgDir)}(${version ?? "\uBC84\uC804 \uBAA8\uB984"})`;
1811
+ if (opts.tailwind3 === true && r.kind !== "shadow-not-exported") return void 0;
1812
+ switch (r.kind) {
1813
+ case "ok":
1814
+ return void 0;
1815
+ case "shadow-not-exported": {
1816
+ const current = opts.tailwind3 === true || r.version !== void 0 && (compareExactVersions(r.version, TAILWIND4_MIN_AXIS_VERSION) ?? -1) >= 0;
1817
+ const todo = current ? "\uB2E4\uC2DC \uC124\uCE58\uD558\uC138\uC694" : `${TAILWIND4_MIN_AXIS_VERSION} \uC774\uC0C1\uC73C\uB85C \uB9DE\uCD94\uC138\uC694`;
1818
+ 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}`;
1819
+ }
1820
+ case "shadow-target-missing":
1821
+ 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`;
1822
+ case "not-visible": {
1823
+ const there = expanded.files.find((f) => dirname2(f.path) === r.fromDir);
1824
+ 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`;
1825
+ 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}`;
1826
+ }
1827
+ }
1828
+ }
1829
+ function isOutsideEntry(origin) {
1830
+ return origin.depth === 0 && origin.cssDir !== void 0;
1637
1831
  }
1638
1832
  function checkGlobalsCss(baseDirInput) {
1639
1833
  const baseDir = resolveBaseDir(baseDirInput);
@@ -1661,7 +1855,21 @@ function judgeGlobalsCss(baseDir, selection, candidate, expanded) {
1661
1855
  if (imported !== void 0) {
1662
1856
  const origin = evidenceOrigin(expanded, (f) => findTokensCssImport(f) === imported);
1663
1857
  via = cssImportViaNote(viaFiles([origin]));
1664
- const issue = tokensCssUnresolvedIssue(baseDir, pkg, imported, origin !== void 0 ? origin.cssDir : outsideCssDir(selection));
1858
+ const tailwind4 = (detectTailwind(baseDir, pkg).major ?? 0) >= 4;
1859
+ const inside = origin !== void 0 && !isOutsideEntry(origin);
1860
+ const issue = tailwind4 && inside ? tokensCssUnresolvedIssue(
1861
+ baseDir,
1862
+ pkg,
1863
+ imported,
1864
+ void 0,
1865
+ () => packageLineShadowIssue(baseDir, expanded, origin, imported)
1866
+ ) : tokensCssUnresolvedIssue(
1867
+ baseDir,
1868
+ pkg,
1869
+ imported,
1870
+ origin !== void 0 ? origin.cssDir : outsideCssDir(selection),
1871
+ inside ? () => packageLineShadowIssue(baseDir, expanded, origin, imported, { tailwind3: true }) : void 0
1872
+ );
1665
1873
  if (issue !== void 0) unresolved = `${candidate}\uC5D0 ${issue}`;
1666
1874
  else pass = `${candidate}\uC5D0 AXIS CSS \uBCC0\uC218\uAC00 \uC788\uC2B5\uB2C8\uB2E4 (${imported} import)`;
1667
1875
  } else if (AXIS_VARIABLE_DEFINITION.test(stripCssComments(expanded.evidence))) {
@@ -1865,6 +2073,8 @@ function stripJsComments(src) {
1865
2073
  }
1866
2074
  var TOKENS_TAILWIND3_PRESET = "@axis-ds/tokens/tailwind";
1867
2075
  var PRESET_REFERENCE = /(?:\brequire\s*\(\s*|\bimport\s*\(\s*|\bfrom\s*|\bimport\s+)(["'])@axis-ds\/tokens\/tailwind\1/;
2076
+ var PRESET_REQUIRE_REFERENCE = /\brequire\s*\(\s*(["'])@axis-ds\/tokens\/tailwind\1/;
2077
+ var PRESET_IMPORT_REFERENCE = /(?:\bimport\s*\(\s*|\bfrom\s*|\bimport\s+)(["'])@axis-ds\/tokens\/tailwind\1/;
1868
2078
  function hasTokensPresetReference(source) {
1869
2079
  return PRESET_REFERENCE.test(stripJsComments(source));
1870
2080
  }
@@ -1892,6 +2102,25 @@ function hasBareCjsPresetRequire(code) {
1892
2102
  function isCommonJsConfig(file, source) {
1893
2103
  return extname(file) === ".cjs" || /\bmodule\.exports\b/.test(source);
1894
2104
  }
2105
+ function presetTokensUnresolvedMessage(baseDir, pkg, file, bareCjs, code) {
2106
+ const r = tokensCssResolution(baseDir, pkg, TOKENS_PACKAGE_NAME);
2107
+ const head = `${file}\uC5D0 AXIS preset \uCC38\uC870\uAC00 \uC788\uC9C0\uB9CC ${TOKENS_PACKAGE_NAME} \uAC00`;
2108
+ if (r.kind === "not-installed") {
2109
+ 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}`)})`;
2110
+ }
2111
+ if (r.kind === "pnp-root-only" && !bareCjs) {
2112
+ 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`;
2113
+ }
2114
+ const e = tailwindConfigImportResolution(baseDir, TOKENS_TAILWIND3_PRESET, {
2115
+ require: PRESET_REQUIRE_REFERENCE.test(code),
2116
+ import: PRESET_IMPORT_REFERENCE.test(code)
2117
+ });
2118
+ if (e.kind === "not-exported") {
2119
+ const label = `${displayRel(baseDir, e.pkgDir)}(${e.version ?? "\uBC84\uC804 \uBAA8\uB984"})`;
2120
+ 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`;
2121
+ }
2122
+ return void 0;
2123
+ }
1895
2124
  function packageVersionGate(baseDirInput, pkg, name, min, options = {}) {
1896
2125
  const baseDir = resolveBaseDir(baseDirInput);
1897
2126
  if (!isPnpProject(baseDir)) {
@@ -1944,7 +2173,8 @@ function tailwind4Issues(input, pkg, versions, baseDir) {
1944
2173
  const r = resolutions.get(name);
1945
2174
  if (r.kind === "undeclared" || r.kind === "app-lockfile") continue;
1946
2175
  if (hasComponentTailwindImport(evidence, name) || hasComponentSource(evidence, name)) continue;
1947
- if (componentCssResolvable(r)) missing.push(name);
2176
+ if (r.kind === "app" && pnpComponentSourceHidden(baseDir, name, r.range)) unresolvedMissing.push(componentCssPnpMissingIssue(name));
2177
+ else if (componentCssResolvable(r)) missing.push(name);
1948
2178
  else unresolvedMissing.push(componentCssMissingIssue(baseDir, name, r));
1949
2179
  }
1950
2180
  if (missing.length > 0) {
@@ -1960,12 +2190,28 @@ function tailwind4Issues(input, pkg, versions, baseDir) {
1960
2190
  }
1961
2191
  for (const name of TAILWIND4_COMPONENT_PACKAGES) {
1962
2192
  if (!hasComponentTailwindImport(evidence, name)) continue;
1963
- const unresolved = componentCssPresentIssue(baseDir, name, resolutions.get(name));
1964
- const componentDir = cssDirOf(`${name}/tailwind.css`);
1965
- if (unresolved !== void 0) issues.push(unresolved);
1966
- else if (componentDir !== void 0 && outsideCssPackageResolution(baseDir, componentDir, name, "tailwind.css") === "unresolved") {
1967
- issues.push(outsideCssUnresolvedIssue(`${name}/tailwind.css`, name));
1968
- } else if (versions.some((v) => v.name === name)) issues.push(`${name}/tailwind.css import \uAC00 \uC788\uC9C0\uB9CC ${name} \uBC84\uC804 \uD655\uC778\uC774 \uD544\uC694\uD569\uB2C8\uB2E4`);
2193
+ const r = resolutions.get(name);
2194
+ const unresolved = componentCssPresentIssue(baseDir, name, r);
2195
+ const spec = `${name}/tailwind.css`;
2196
+ if (unresolved !== void 0) {
2197
+ issues.push(unresolved);
2198
+ continue;
2199
+ }
2200
+ if (r.kind === "app" && pnpComponentSourceHidden(baseDir, name, r.range)) {
2201
+ issues.push(componentCssPnpPresentIssue(name));
2202
+ continue;
2203
+ }
2204
+ const shadow = input.lineIssue === void 0 ? false : input.lineIssue(spec);
2205
+ let lineProblem;
2206
+ if (shadow !== false) lineProblem = shadow;
2207
+ else {
2208
+ const componentDir = cssDirOf(spec);
2209
+ if (componentDir !== void 0 && outsideCssPackageResolution(baseDir, componentDir, name, "tailwind.css") === "unresolved") {
2210
+ lineProblem = outsideCssUnresolvedIssue(spec, name);
2211
+ }
2212
+ }
2213
+ if (lineProblem !== void 0) issues.push(lineProblem);
2214
+ 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`);
1969
2215
  }
1970
2216
  return issues;
1971
2217
  }
@@ -1973,6 +2219,13 @@ function componentInstallPhrase(baseDir, name, range) {
1973
2219
  const g = dependencyInstallGuide(baseDir, name, range);
1974
2220
  return g.kind === "install-at-root" ? `\uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uB8E8\uD2B8\uC5D0\uC11C ${g.installCommand}` : g.installCommand;
1975
2221
  }
2222
+ 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`;
2223
+ function componentCssPnpMissingIssue(name) {
2224
+ return `${name} \uC758 tailwind.css \uB294 ${PNP_ZIP_SOURCE_NOTE} \u2192 ${pnpUnplugSetupPhrase(name)} \uB4A4 ${componentTailwindImportLine(name)}`;
2225
+ }
2226
+ function componentCssPnpPresentIssue(name) {
2227
+ return `${name}/tailwind.css import \uAC00 \uC788\uC9C0\uB9CC ${PNP_ZIP_SOURCE_NOTE} \u2192 ${pnpUnplugSetupPhrase(name)} \uD558\uC138\uC694`;
2228
+ }
1976
2229
  function componentCssMissingIssue(baseDir, name, r) {
1977
2230
  const line = componentTailwindImportLine(name);
1978
2231
  switch (r.kind) {
@@ -2033,7 +2286,17 @@ function checkTailwindSetup(baseDirInput) {
2033
2286
  );
2034
2287
  const versions = axisPackagesBelowTailwind4(pkg, baseDir);
2035
2288
  const issues = tailwind4Issues(
2036
- { entry: expanded.entry, evidence: expanded.evidence, cssDirOf: (spec) => packageLineCssDir(expanded, spec) },
2289
+ {
2290
+ entry: expanded.entry,
2291
+ evidence: expanded.evidence,
2292
+ cssDirOf: (spec) => packageLineCssDir(expanded, spec),
2293
+ lineIssue: (spec) => {
2294
+ const line = expanded.packageLines.find((l) => l.spec === spec);
2295
+ const origin = line !== void 0 ? expanded.files.find((f) => f.rel === line.file) : void 0;
2296
+ if (origin === void 0 || isOutsideEntry(origin)) return false;
2297
+ return packageLineShadowIssue(baseDir, expanded, origin, spec);
2298
+ }
2299
+ },
2037
2300
  pkg,
2038
2301
  versions,
2039
2302
  baseDir
@@ -2058,12 +2321,15 @@ function checkTailwindSetup(baseDirInput) {
2058
2321
  };
2059
2322
  }
2060
2323
  for (const file of TAILWIND_CONFIG_FILES) {
2061
- const path11 = join2(baseDir, file);
2062
- if (!existsSync3(path11)) continue;
2063
- const content = readFileSync4(path11, "utf8");
2324
+ const path12 = join2(baseDir, file);
2325
+ if (!existsSync3(path12)) continue;
2326
+ const content = readFileSync4(path12, "utf8");
2064
2327
  if (hasTokensPresetReference(content)) {
2065
2328
  const code = stripJsComments(content);
2066
- if (isCommonJsConfig(file, code) && hasBareCjsPresetRequire(code)) {
2329
+ const bareCjs = isCommonJsConfig(file, code) && hasBareCjsPresetRequire(code);
2330
+ const unresolved = presetTokensUnresolvedMessage(baseDir, pkg, file, bareCjs, code);
2331
+ if (unresolved !== void 0) return { name: "tailwind.config", severity: "warn", message: unresolved };
2332
+ if (bareCjs) {
2067
2333
  const gate = packageVersionGate(baseDir, pkg, "@axis-ds/tokens", TOKENS_CJS_PRESET_FIXED_VERSION, { appOnlyInPnp: true });
2068
2334
  if (gate.status === "unresolved") {
2069
2335
  return {
@@ -3491,11 +3757,11 @@ async function handleGetComponent(params, deps = {}) {
3491
3757
  return { component, source: describeOrigin(client, latest.version), notices };
3492
3758
  }
3493
3759
  function handleGetToken(params) {
3494
- const { path: path11 } = params;
3495
- if (!path11 || path11.trim() === "") {
3760
+ const { path: path12 } = params;
3761
+ if (!path12 || path12.trim() === "") {
3496
3762
  throw new Error("\uD1A0\uD070 \uACBD\uB85C(path)\uB294 \uD544\uC218\uC785\uB2C8\uB2E4.");
3497
3763
  }
3498
- const token = getToken(path11);
3764
+ const token = getToken(path12);
3499
3765
  if (!token) {
3500
3766
  return null;
3501
3767
  }
@@ -3576,9 +3842,9 @@ function cssUsage(token) {
3576
3842
  const shadcnColor = !token.cssVariable.startsWith("--axis-") && token.value.startsWith("hsl(");
3577
3843
  return shadcnColor ? `hsl(var(${token.cssVariable}))` : `var(${token.cssVariable})`;
3578
3844
  }
3579
- function formatTokenNotFound(path11) {
3845
+ function formatTokenNotFound(path12) {
3580
3846
  return [
3581
- `\uD1A0\uD070\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: \`${path11}\``,
3847
+ `\uD1A0\uD070\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: \`${path12}\``,
3582
3848
  "",
3583
3849
  "- \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.",
3584
3850
  "- \uBE0C\uB79C\uB4DC \uAC12\uC740 `axis.list_brands` \xB7 `axis.get_brand` \uB85C \uC870\uD68C\uD558\uC138\uC694."
@@ -5276,12 +5542,14 @@ function formatSaveResult(result) {
5276
5542
  // src/tools/template.ts
5277
5543
  import fetch from "node-fetch";
5278
5544
  import fs6 from "fs-extra";
5279
- import path9 from "path";
5545
+ import path10 from "path";
5280
5546
 
5281
5547
  // src/tools/brand-core.ts
5548
+ import { createHash as createHash2 } from "crypto";
5282
5549
  import { existsSync as existsSync8, readFileSync as readFileSync8, statSync as statSync6 } from "fs";
5283
5550
  import { createRequire } from "module";
5284
5551
  import { dirname as dirname4, join as join4, relative as relative2, resolve as resolve3, sep as sep2 } from "path";
5552
+ import { MessageChannel, Worker, receiveMessageOnPort } from "worker_threads";
5285
5553
  var TOKENS_PACKAGE = "@axis-ds/tokens";
5286
5554
  var MIN_BRAND_TOKENS_VERSION = "1.3.0";
5287
5555
  var TOKENS_DEPENDENCY_MIN_VERSION = "1.6.0";
@@ -5306,13 +5574,15 @@ function readJsonFile(file) {
5306
5574
  function errorCode(err) {
5307
5575
  return typeof err === "object" && err !== null && "code" in err ? String(err.code) : void 0;
5308
5576
  }
5309
- function findTokensPackageJson(baseDir) {
5577
+ function tokensPackageJsonCandidates(baseDir) {
5578
+ const candidates = [];
5310
5579
  let dir = resolve3(baseDir);
5311
5580
  for (; ; ) {
5312
5581
  const candidate = join4(dir, "node_modules", TOKENS_PACKAGE, "package.json");
5313
- if (existsSync8(candidate)) return candidate;
5582
+ candidates.push(candidate);
5583
+ if (existsSync8(candidate)) return { found: candidate, candidates };
5314
5584
  const parent = dirname4(dir);
5315
- if (parent === dir) return void 0;
5585
+ if (parent === dir) return { candidates };
5316
5586
  dir = parent;
5317
5587
  }
5318
5588
  }
@@ -5322,18 +5592,195 @@ function projectRequire(baseDir) {
5322
5592
  function tokensSpecifier(subpath) {
5323
5593
  return `${TOKENS_PACKAGE}/${subpath.replace(/^\.\//, "")}`;
5324
5594
  }
5325
- function resolveTokens(baseDir) {
5326
- const pkgJson = findTokensPackageJson(baseDir);
5327
- if (!pkgJson) return { status: "not-installed" };
5328
- const pkg = readJsonFile(pkgJson);
5329
- const version = typeof pkg.version === "string" ? pkg.version : void 0;
5595
+ var nodeSeenStates = /* @__PURE__ */ new Map();
5596
+ var ABSENT = "absent";
5597
+ var UNKNOWN = "unknown";
5598
+ var isolationDisabled = false;
5599
+ var isolatedStats = { workers: 0, resolves: 0, fallbacks: 0 };
5600
+ var ISOLATED_RESOLVE_TIMEOUT_MS = 5e3;
5601
+ var ISOLATED_RESOLVE_SOURCE = `
5602
+ const { workerData } = require("node:worker_threads");
5603
+ const { createRequire } = require("node:module");
5604
+ const { port, signal, from } = workerData;
5605
+ const req = createRequire(from);
5606
+ port.on("message", (spec) => {
5607
+ let reply;
5330
5608
  try {
5331
- const indexPath = projectRequire(baseDir).resolve(tokensSpecifier("./brands"));
5332
- return { status: "ok", version, indexPath };
5609
+ reply = { path: req.resolve(spec) };
5610
+ } catch (err) {
5611
+ const code = err && typeof err === "object" && "code" in err ? String(err.code) : undefined;
5612
+ reply = { code, message: err && err.message ? String(err.message) : String(err) };
5613
+ }
5614
+ port.postMessage(reply);
5615
+ Atomics.store(signal, 0, 1);
5616
+ Atomics.notify(signal, 0);
5617
+ });
5618
+ `;
5619
+ var IsolationFailure = class extends Error {
5620
+ };
5621
+ function createWorkerResolveSession(from, source, timeoutMs) {
5622
+ const { port1, port2 } = new MessageChannel();
5623
+ const signal = new Int32Array(new SharedArrayBuffer(4));
5624
+ const worker = new Worker(source, {
5625
+ eval: true,
5626
+ workerData: { port: port2, signal, from },
5627
+ transferList: [port2]
5628
+ });
5629
+ worker.on("error", () => {
5630
+ });
5631
+ worker.unref();
5632
+ return {
5633
+ resolve(spec) {
5634
+ Atomics.store(signal, 0, 0);
5635
+ port1.postMessage(spec);
5636
+ const waited = Atomics.wait(signal, 0, 0, timeoutMs);
5637
+ const received = receiveMessageOnPort(port1);
5638
+ if (waited === "timed-out" || !received) throw new IsolationFailure("\uACA9\uB9AC \uD574\uC11D\uC774 \uC751\uB2F5\uD558\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4");
5639
+ const reply = received.message;
5640
+ if (typeof reply.path === "string") return reply.path;
5641
+ throw Object.assign(new Error(reply.message ?? spec), reply.code === void 0 ? {} : { code: reply.code });
5642
+ },
5643
+ close() {
5644
+ port1.close();
5645
+ void worker.terminate();
5646
+ }
5647
+ };
5648
+ }
5649
+ function workerResolveSession(from) {
5650
+ return createWorkerResolveSession(from, ISOLATED_RESOLVE_SOURCE, ISOLATED_RESOLVE_TIMEOUT_MS);
5651
+ }
5652
+ var isolatedFactory = workerResolveSession;
5653
+ function sha256(text) {
5654
+ return createHash2("sha256").update(text).digest("hex");
5655
+ }
5656
+ function openTokensResolver(baseDir, candidates, pkgJson, pkgText) {
5657
+ const nodeRequire = projectRequire(baseDir);
5658
+ const key = sha256(pkgText);
5659
+ const current = candidates.map((c) => c === pkgJson ? key : ABSENT);
5660
+ const changed = candidates.some((c, i) => {
5661
+ const seen = nodeSeenStates.get(c);
5662
+ return seen !== void 0 && seen !== current[i];
5663
+ });
5664
+ let mode = changed ? "isolated" : "node";
5665
+ if (mode === "node") {
5666
+ candidates.forEach((c, i) => {
5667
+ if (!nodeSeenStates.has(c)) nodeSeenStates.set(c, current[i]);
5668
+ });
5669
+ }
5670
+ let session = null;
5671
+ let stale = false;
5672
+ let raced = false;
5673
+ let postChecked = false;
5674
+ const markStale = () => {
5675
+ if (!stale) isolatedStats.fallbacks += 1;
5676
+ stale = true;
5677
+ };
5678
+ const fallBack = () => {
5679
+ markStale();
5680
+ isolationDisabled = true;
5681
+ session?.close();
5682
+ session = null;
5683
+ };
5684
+ const startIsolation = () => {
5685
+ if (isolationDisabled) {
5686
+ markStale();
5687
+ return;
5688
+ }
5689
+ try {
5690
+ session = isolatedFactory(join4(resolve3(baseDir), "package.json"));
5691
+ isolatedStats.workers += 1;
5692
+ } catch {
5693
+ fallBack();
5694
+ }
5695
+ };
5696
+ if (mode === "isolated") startIsolation();
5697
+ const isolatedResolve = (spec) => {
5698
+ if (session) {
5699
+ try {
5700
+ const resolved = session.resolve(spec);
5701
+ isolatedStats.resolves += 1;
5702
+ return resolved;
5703
+ } catch (err) {
5704
+ if (!(err instanceof IsolationFailure)) {
5705
+ isolatedStats.resolves += 1;
5706
+ throw err;
5707
+ }
5708
+ fallBack();
5709
+ }
5710
+ }
5711
+ return nodeRequire.resolve(spec);
5712
+ };
5713
+ return {
5714
+ resolve(spec) {
5715
+ if (mode === "isolated") return isolatedResolve(spec);
5716
+ let resolved;
5717
+ let failure;
5718
+ let failed = false;
5719
+ try {
5720
+ resolved = nodeRequire.resolve(spec);
5721
+ } catch (err) {
5722
+ failed = true;
5723
+ failure = err;
5724
+ }
5725
+ if (!postChecked) {
5726
+ postChecked = true;
5727
+ let after;
5728
+ try {
5729
+ after = sha256(readFileSync8(pkgJson, "utf8"));
5730
+ } catch {
5731
+ after = UNKNOWN;
5732
+ }
5733
+ if (after !== key) {
5734
+ nodeSeenStates.set(pkgJson, UNKNOWN);
5735
+ raced = true;
5736
+ mode = "isolated";
5737
+ startIsolation();
5738
+ return isolatedResolve(spec);
5739
+ }
5740
+ }
5741
+ if (failed) throw failure;
5742
+ return resolved;
5743
+ },
5744
+ get stale() {
5745
+ return stale;
5746
+ },
5747
+ get raced() {
5748
+ return raced;
5749
+ },
5750
+ close() {
5751
+ session?.close();
5752
+ session = null;
5753
+ }
5754
+ };
5755
+ }
5756
+ function readVersion(pkgText) {
5757
+ const pkg = JSON.parse(pkgText);
5758
+ return typeof pkg.version === "string" ? pkg.version : void 0;
5759
+ }
5760
+ function openTokens(baseDir) {
5761
+ const { found: pkgJson, candidates } = tokensPackageJsonCandidates(baseDir);
5762
+ if (!pkgJson) return { resolution: { status: "not-installed" } };
5763
+ const pkgText = readFileSync8(pkgJson, "utf8");
5764
+ let version = readVersion(pkgText);
5765
+ const resolver = openTokensResolver(baseDir, candidates, pkgJson, pkgText);
5766
+ const finish = (status, indexPath) => {
5767
+ if (resolver.raced) {
5768
+ try {
5769
+ version = readVersion(readFileSync8(pkgJson, "utf8"));
5770
+ } catch {
5771
+ }
5772
+ }
5773
+ const resolution = indexPath === void 0 ? { status, version } : { status, version, indexPath };
5774
+ return { resolution: resolver.stale ? { ...resolution, stale: true } : resolution, resolver };
5775
+ };
5776
+ try {
5777
+ const indexPath = resolver.resolve(tokensSpecifier("./brands"));
5778
+ return finish("ok", indexPath);
5333
5779
  } catch (err) {
5334
5780
  const code = errorCode(err);
5335
- if (code === "ERR_PACKAGE_PATH_NOT_EXPORTED") return { status: "unsupported", version };
5336
- if (code === "MODULE_NOT_FOUND") return { status: "not-built", version };
5781
+ if (code === "ERR_PACKAGE_PATH_NOT_EXPORTED") return finish("unsupported");
5782
+ if (code === "MODULE_NOT_FOUND") return finish("not-built");
5783
+ resolver.close();
5337
5784
  throw err;
5338
5785
  }
5339
5786
  }
@@ -5402,8 +5849,8 @@ function readBrandIndex(indexPath) {
5402
5849
  }
5403
5850
  return data.brands;
5404
5851
  }
5405
- function readSummary(baseDir, entry) {
5406
- const metaPath = projectRequire(baseDir).resolve(tokensSpecifier(entry.meta));
5852
+ function readSummary(resolver, entry) {
5853
+ const metaPath = resolver.resolve(tokensSpecifier(entry.meta));
5407
5854
  const meta = readJsonFile(metaPath);
5408
5855
  return {
5409
5856
  name: entry.name,
@@ -5414,20 +5861,33 @@ function readSummary(baseDir, entry) {
5414
5861
  };
5415
5862
  }
5416
5863
  function listBrands(baseDir) {
5417
- const tokens = resolveTokens(baseDir);
5418
- if (tokens.status !== "ok" || !tokens.indexPath) {
5864
+ const { resolution: tokens, resolver } = openTokens(baseDir);
5865
+ try {
5866
+ return withStaleOf(resolver, listBrandsWith(tokens, resolver));
5867
+ } finally {
5868
+ resolver?.close();
5869
+ }
5870
+ }
5871
+ function listBrandsWith(tokens, resolver) {
5872
+ if (tokens.status !== "ok" || !tokens.indexPath || !resolver) {
5419
5873
  return { status: tokens.status, version: tokens.version, brands: [] };
5420
5874
  }
5421
5875
  const entries = readBrandIndex(tokens.indexPath);
5422
- let brands;
5423
- try {
5424
- brands = entries.map((entry) => readSummary(baseDir, entry));
5425
- } catch (err) {
5426
- if (isMissingBuildFile(err)) return { status: "not-built", version: tokens.version, brands: [] };
5427
- throw err;
5876
+ const brands = [];
5877
+ for (const entry of entries) {
5878
+ try {
5879
+ brands.push(readSummary(resolver, entry));
5880
+ } catch (err) {
5881
+ if (isMissingBuildFile(err)) return { status: "not-built", version: tokens.version, brands: [] };
5882
+ if (resolver.stale && errorCode(err) === "ERR_PACKAGE_PATH_NOT_EXPORTED") continue;
5883
+ throw err;
5884
+ }
5428
5885
  }
5429
5886
  return { status: "ok", version: tokens.version, brands };
5430
5887
  }
5888
+ function withStaleOf(resolver, result) {
5889
+ return resolver?.stale ? { ...result, stale: true } : result;
5890
+ }
5431
5891
  function stripComments(css) {
5432
5892
  return css.replace(/\/\*[\s\S]*?\*\//g, "");
5433
5893
  }
@@ -5539,8 +5999,15 @@ function readProjectPackageJson(baseDir) {
5539
5999
  }
5540
6000
  }
5541
6001
  function getBrand(baseDir, name) {
5542
- const tokens = resolveTokens(baseDir);
5543
- if (tokens.status !== "ok" || !tokens.indexPath) {
6002
+ const { resolution: tokens, resolver } = openTokens(baseDir);
6003
+ try {
6004
+ return withStaleOf(resolver, getBrandWith(tokens, resolver, name));
6005
+ } finally {
6006
+ resolver?.close();
6007
+ }
6008
+ }
6009
+ function getBrandWith(tokens, resolver, name) {
6010
+ if (tokens.status !== "ok" || !tokens.indexPath || !resolver) {
5544
6011
  return { status: tokens.status, version: tokens.version, brand: null, available: [] };
5545
6012
  }
5546
6013
  const entries = readBrandIndex(tokens.indexPath);
@@ -5552,11 +6019,14 @@ function getBrand(baseDir, name) {
5552
6019
  let summary;
5553
6020
  let parsed;
5554
6021
  try {
5555
- summary = readSummary(baseDir, entry);
5556
- const cssPath = projectRequire(baseDir).resolve(summary.importPath);
6022
+ summary = readSummary(resolver, entry);
6023
+ const cssPath = resolver.resolve(summary.importPath);
5557
6024
  parsed = parseBrandCss(readFileSync8(cssPath, "utf8"), name);
5558
6025
  } catch (err) {
5559
6026
  if (isMissingBuildFile(err)) return { status: "not-built", version: tokens.version, brand: null, available: [] };
6027
+ if (resolver.stale && errorCode(err) === "ERR_PACKAGE_PATH_NOT_EXPORTED") {
6028
+ return { status: "ok", version: tokens.version, brand: null, available: available.filter((n) => n !== name) };
6029
+ }
5560
6030
  throw err;
5561
6031
  }
5562
6032
  return {
@@ -5632,11 +6102,15 @@ function checkDependencies(baseDirInput) {
5632
6102
  if (missingRecommended.length > 0) problems.push(`\uAD8C\uC7A5 \uC758\uC874\uC131 \uB204\uB77D: ${missingRecommended.join(", ")}`);
5633
6103
  if (pnpRootRecommended.length > 0) problems.push(`\uAD8C\uC7A5 \uC758\uC874\uC131 ${pnpRootRecommended.join(", ")} \uAC00 ${PNP_ROOT_ONLY_NOTE} \u2192 \uC571 package.json \uC5D0 \uC120\uC5B8\uD558\uC138\uC694`);
5634
6104
  if (pnpRootAxis.length > 0) problems.push(`${pnpRootAxis.join(", ")} \uAC00 ${PNP_ROOT_ONLY_NOTE} \u2192 \uC571 package.json \uC5D0 \uC120\uC5B8\uD558\uC138\uC694`);
6105
+ const installCommand = detectInstallCommand(baseDir);
5635
6106
  if (notInstalledOther.length > 0) {
5636
- problems.push(`\uC120\uC5B8\uB410\uC9C0\uB9CC \uC124\uCE58\uB418\uC9C0 \uC54A\uC740 \uC758\uC874\uC131: ${notInstalledOther.join(", ")} \u2192 ${detectInstallCommand(baseDir)}`);
6107
+ const phrase = installCommandPhrase(installCommand, notInstalledOther.some((d) => fromRoot(d)));
6108
+ problems.push(`\uC120\uC5B8\uB410\uC9C0\uB9CC \uC124\uCE58\uB418\uC9C0 \uC54A\uC740 \uC758\uC874\uC131: ${notInstalledOther.join(", ")} \u2192 ${phrase}`);
5637
6109
  }
5638
6110
  if (notInstalledRoot.length > 0) {
5639
- problems.push(`\uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uB8E8\uD2B8\uC5D0 \uC120\uC5B8\uB3FC \uC788\uC9C0\uB9CC \uC124\uCE58\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4: ${notInstalledRoot.join(", ")} \u2192 ${detectInstallCommand(baseDir)}`);
6111
+ problems.push(
6112
+ `\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)}`
6113
+ );
5640
6114
  }
5641
6115
  if (problems.length > 0) {
5642
6116
  return { name: "dependencies", severity: "warn", message: problems.join(" / ") + (rootNote ? ` (${rootNote})` : "") };
@@ -5649,6 +6123,192 @@ function checkDependencies(baseDirInput) {
5649
6123
  };
5650
6124
  }
5651
6125
 
6126
+ // ../axis-registry-core/src/template/apply-files.ts
6127
+ 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";
6128
+ import path9 from "path";
6129
+ var TemplatePathError = class extends Error {
6130
+ constructor(relPath, reason) {
6131
+ 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`);
6132
+ this.relPath = relPath;
6133
+ this.reason = reason;
6134
+ this.name = "TemplatePathError";
6135
+ }
6136
+ };
6137
+ function realpathOfExisting(p) {
6138
+ const rest = [];
6139
+ let cur = p;
6140
+ for (; ; ) {
6141
+ try {
6142
+ lstatSync3(cur);
6143
+ break;
6144
+ } catch {
6145
+ const parent = path9.dirname(cur);
6146
+ if (parent === cur) break;
6147
+ rest.unshift(path9.basename(cur));
6148
+ cur = parent;
6149
+ }
6150
+ }
6151
+ try {
6152
+ return path9.join(realpathSync4(cur), ...rest);
6153
+ } catch {
6154
+ return void 0;
6155
+ }
6156
+ }
6157
+ function isInside(root, target) {
6158
+ const rel2 = path9.relative(root, target);
6159
+ return rel2 !== "" && !rel2.startsWith("..") && !path9.isAbsolute(rel2);
6160
+ }
6161
+ function resolveTemplatePath(baseDir, relPath) {
6162
+ if (typeof relPath !== "string" || relPath === "" || relPath.includes("\0")) {
6163
+ throw new TemplatePathError(String(relPath), "\uBE48 \uACBD\uB85C \uB610\uB294 \uC798\uBABB\uB41C \uBB38\uC790");
6164
+ }
6165
+ if (path9.isAbsolute(relPath) || path9.win32.isAbsolute(relPath)) throw new TemplatePathError(relPath, "\uC808\uB300 \uACBD\uB85C");
6166
+ const base = path9.resolve(baseDir);
6167
+ const dest = path9.resolve(base, relPath);
6168
+ if (!isInside(base, dest)) throw new TemplatePathError(relPath, "\uC0C1\uC704 \uB514\uB809\uD130\uB9AC\uB85C \uB098\uAC10");
6169
+ const baseReal = realpathOfExisting(base);
6170
+ const destReal = realpathOfExisting(dest);
6171
+ if (!baseReal || !destReal || !isInside(baseReal, destReal)) {
6172
+ throw new TemplatePathError(relPath, "\uC2EC\uBCFC\uB9AD \uB9C1\uD06C\uAC00 \uB300\uC0C1 \uB514\uB809\uD130\uB9AC \uBC16\uC744 \uAC00\uB9AC\uD0B4");
6173
+ }
6174
+ return dest;
6175
+ }
6176
+ function assertTemplatePaths(baseDir, relPaths) {
6177
+ for (const p of relPaths) resolveTemplatePath(baseDir, p);
6178
+ }
6179
+ var PACKAGE_JSON_MERGED_MAPS = [
6180
+ "scripts",
6181
+ "dependencies",
6182
+ "devDependencies",
6183
+ "peerDependencies",
6184
+ "optionalDependencies"
6185
+ ];
6186
+ function isPlainObject3(v) {
6187
+ return typeof v === "object" && v !== null && !Array.isArray(v);
6188
+ }
6189
+ function parseObject(text) {
6190
+ try {
6191
+ const v = JSON.parse(text);
6192
+ return isPlainObject3(v) ? v : void 0;
6193
+ } catch {
6194
+ return void 0;
6195
+ }
6196
+ }
6197
+ function mergePackageJson(user, template) {
6198
+ const maps = new Set(PACKAGE_JSON_MERGED_MAPS);
6199
+ const out = {};
6200
+ for (const [key, value] of Object.entries(user)) {
6201
+ const tpl = template[key];
6202
+ if (maps.has(key) && isPlainObject3(tpl)) {
6203
+ out[key] = isPlainObject3(value) ? { ...value, ...tpl } : tpl;
6204
+ } else {
6205
+ out[key] = value;
6206
+ }
6207
+ }
6208
+ for (const [key, value] of Object.entries(template)) {
6209
+ if (!(key in out)) out[key] = value;
6210
+ }
6211
+ return out;
6212
+ }
6213
+ function mergeAxisConfigJson(user, template) {
6214
+ return { ...user, ...template };
6215
+ }
6216
+ function detectJsonIndent(text) {
6217
+ const m = /^([ \t]+)\S/m.exec(text);
6218
+ if (!m) return 2;
6219
+ return m[1].startsWith(" ") ? " " : m[1].length;
6220
+ }
6221
+ function serializeLike(before, value) {
6222
+ const crlf = before.includes("\r\n");
6223
+ const trailing = /\r?\n$/.test(before);
6224
+ let text = JSON.stringify(value, null, detectJsonIndent(before));
6225
+ if (trailing) text += "\n";
6226
+ return crlf ? text.replace(/\n/g, "\r\n") : text;
6227
+ }
6228
+ var MERGERS = {
6229
+ "package.json": mergePackageJson,
6230
+ "axis.config.json": mergeAxisConfigJson
6231
+ };
6232
+ function planTemplateFileContent(relPath, templateContent, before) {
6233
+ if (before === void 0) return { action: "created", content: templateContent };
6234
+ const merger = MERGERS[relPath.replace(/^\.\//, "")];
6235
+ if (!merger) return { action: "overwritten", content: templateContent };
6236
+ const user = parseObject(before);
6237
+ const template = parseObject(templateContent);
6238
+ if (!user || !template) {
6239
+ return {
6240
+ action: "overwritten",
6241
+ content: templateContent,
6242
+ 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`
6243
+ };
6244
+ }
6245
+ return { action: "merged", content: serializeLike(before, merger(user, template)) };
6246
+ }
6247
+ function planTemplateFiles(baseDir, files, extraPaths = []) {
6248
+ const dests = files.map((file) => resolveTemplatePath(baseDir, file.path));
6249
+ assertTemplatePaths(baseDir, extraPaths);
6250
+ return files.map((file, i) => {
6251
+ const dest = dests[i];
6252
+ const before = existsSync9(dest) ? readFileSync10(dest, "utf8") : void 0;
6253
+ return { path: file.path, dest, before, ...planTemplateFileContent(file.path, file.content, before) };
6254
+ });
6255
+ }
6256
+ var TemplateApplyError = class extends Error {
6257
+ constructor(message, restored, unrestored) {
6258
+ super(message);
6259
+ this.restored = restored;
6260
+ this.unrestored = unrestored;
6261
+ this.name = "TemplateApplyError";
6262
+ }
6263
+ };
6264
+ function writeTemplateFiles(plan) {
6265
+ const done = [];
6266
+ const madeDirs = [];
6267
+ try {
6268
+ for (const item of plan) {
6269
+ const dir = path9.dirname(item.dest);
6270
+ if (!existsSync9(dir)) {
6271
+ const fresh = [];
6272
+ for (let d = dir; !existsSync9(d); d = path9.dirname(d)) fresh.unshift(d);
6273
+ mkdirSync2(dir, { recursive: true });
6274
+ madeDirs.push(...fresh);
6275
+ }
6276
+ writeFileSync2(item.dest, item.content);
6277
+ done.push(item);
6278
+ }
6279
+ } catch (err) {
6280
+ const restored = [];
6281
+ const unrestored = [];
6282
+ const failed = plan[done.length];
6283
+ const targets = failed ? [...done, failed] : done;
6284
+ for (const item of targets.reverse()) {
6285
+ try {
6286
+ if (item.before === void 0) {
6287
+ if (existsSync9(item.dest)) unlinkSync(item.dest);
6288
+ } else {
6289
+ writeFileSync2(item.dest, item.before);
6290
+ }
6291
+ restored.push(item.path);
6292
+ } catch {
6293
+ unrestored.push(item.path);
6294
+ }
6295
+ }
6296
+ for (const d of madeDirs.reverse()) {
6297
+ try {
6298
+ if (existsSync9(d) && readdirSync3(d).length === 0) rmdirSync(d);
6299
+ } catch {
6300
+ }
6301
+ }
6302
+ const reason = err instanceof Error ? err.message : String(err);
6303
+ const tail = unrestored.length > 0 ? ` \uB418\uB3CC\uB9AC\uC9C0 \uBABB\uD55C \uD30C\uC77C: ${unrestored.join(", ")}` : "";
6304
+ throw new TemplateApplyError(
6305
+ `\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}`,
6306
+ restored.reverse(),
6307
+ unrestored
6308
+ );
6309
+ }
6310
+ }
6311
+
5652
6312
  // src/site.ts
5653
6313
  var AXIS_SITE_URL2 = "https://axis-design-system.pages.dev";
5654
6314
 
@@ -5702,24 +6362,18 @@ async function handleGetTemplate(params) {
5702
6362
  }
5703
6363
  async function handleApplyTemplate(params) {
5704
6364
  const detail = await fetchTemplateDetail(params.name);
5705
- const baseDir = path9.resolve(params.targetDir);
6365
+ const baseDir = path10.resolve(params.targetDir);
5706
6366
  const installCommand = detectInstallCommand(baseDir);
5707
- const files = [];
5708
- for (const file of detail.files) {
5709
- const dest = path9.join(baseDir, file.path);
5710
- const exists = await fs6.pathExists(dest);
5711
- if (!params.dryRun) {
5712
- await fs6.ensureDir(path9.dirname(dest));
5713
- await fs6.writeFile(dest, file.content);
5714
- }
5715
- files.push({
5716
- path: file.path,
5717
- action: exists ? "overwritten" : "created"
5718
- });
5719
- }
6367
+ const plan = planTemplateFiles(baseDir, detail.files, (detail.postInstall ?? []).map((p) => p.file));
6368
+ if (!params.dryRun) writeTemplateFiles(plan);
6369
+ const files = plan.map((item) => ({
6370
+ path: item.path,
6371
+ action: item.action,
6372
+ ...item.note ? { note: item.note } : {}
6373
+ }));
5720
6374
  if (!params.dryRun && detail.postInstall?.length) {
5721
6375
  for (const patch of detail.postInstall) {
5722
- const target = path9.join(baseDir, patch.file);
6376
+ const target = resolveTemplatePath(baseDir, patch.file);
5723
6377
  if (!await fs6.pathExists(target)) continue;
5724
6378
  if (patch.type === "replace" && patch.search && patch.value) {
5725
6379
  const content = await fs6.readFile(target, "utf-8");
@@ -5747,10 +6401,11 @@ async function handleApplyTemplate(params) {
5747
6401
  }
5748
6402
  async function handleDiffTemplate(params) {
5749
6403
  const detail = await fetchTemplateDetail(params.name);
5750
- const baseDir = path9.resolve(params.targetDir || ".");
6404
+ const baseDir = path10.resolve(params.targetDir || ".");
5751
6405
  const entries = [];
5752
- for (const file of detail.files) {
5753
- const localPath = path9.join(baseDir, file.path);
6406
+ const localPaths = detail.files.map((file) => resolveTemplatePath(baseDir, file.path));
6407
+ for (const [i, file] of detail.files.entries()) {
6408
+ const localPath = localPaths[i];
5754
6409
  if (!await fs6.pathExists(localPath)) {
5755
6410
  entries.push({ path: file.path, status: "added" });
5756
6411
  continue;
@@ -5838,9 +6493,9 @@ function brandActivationResult(check) {
5838
6493
  };
5839
6494
  }
5840
6495
  async function handleCheckProject(params) {
5841
- const baseDir = path9.resolve(params.targetDir || ".");
6496
+ const baseDir = path10.resolve(params.targetDir || ".");
5842
6497
  const results = [];
5843
- const configExists = await fs6.pathExists(path9.join(baseDir, "axis.config.json"));
6498
+ const configExists = await fs6.pathExists(path10.join(baseDir, "axis.config.json"));
5844
6499
  results.push({
5845
6500
  name: "axis.config.json",
5846
6501
  severity: configExists ? "pass" : "fail",
@@ -5857,7 +6512,7 @@ async function handleCheckProject(params) {
5857
6512
  ];
5858
6513
  let utilsFound = false;
5859
6514
  for (const candidate of utilsCandidates) {
5860
- const fullPath = path9.join(baseDir, candidate);
6515
+ const fullPath = path10.join(baseDir, candidate);
5861
6516
  if (await fs6.pathExists(fullPath)) {
5862
6517
  const content2 = await fs6.readFile(fullPath, "utf-8");
5863
6518
  const hasCn = content2.includes("function cn");
@@ -5948,9 +6603,15 @@ function formatApplyTemplateResult(result) {
5948
6603
  `);
5949
6604
  if (result.files.length > 0) {
5950
6605
  lines.push("### \uD30C\uC77C", "");
6606
+ const label = {
6607
+ created: "\uC0DD\uC131",
6608
+ overwritten: "\uB36E\uC5B4\uC4F0\uAE30",
6609
+ merged: "\uD569\uCE58\uAE30: \uAE30\uC874 \uD544\uB4DC\uB97C \uB450\uACE0 \uD15C\uD50C\uB9BF \uD0A4\uB97C \uD569\uCE68"
6610
+ };
5951
6611
  for (const f of result.files) {
5952
6612
  const icon = f.action === "created" ? "+" : "~";
5953
- lines.push(`- ${icon} ${f.path} (${f.action === "created" ? "\uC0DD\uC131" : "\uB36E\uC5B4\uC4F0\uAE30"})`);
6613
+ lines.push(`- ${icon} ${f.path} (${label[f.action]})`);
6614
+ if (f.note) lines.push(` - ! ${f.note}`);
5954
6615
  }
5955
6616
  }
5956
6617
  const deps = Object.entries(result.dependencies);
@@ -6002,10 +6663,10 @@ function formatCheckProjectResult(result) {
6002
6663
  }
6003
6664
 
6004
6665
  // src/tools/brand.ts
6005
- import path10 from "path";
6666
+ import path11 from "path";
6006
6667
  var TOKENS_INSTALL_COMMAND = addCommandFor("pnpm install", { [TOKENS_PACKAGE]: `^${TOKENS_DEPENDENCY_MIN_VERSION}` });
6007
6668
  function baseDirOf(targetDir) {
6008
- return path10.resolve(targetDir || process.cwd());
6669
+ return path11.resolve(targetDir || process.cwd());
6009
6670
  }
6010
6671
  function tokensInstallGuideFor(targetDir) {
6011
6672
  return dependencyInstallGuide(baseDirOf(targetDir), TOKENS_PACKAGE, `^${TOKENS_DEPENDENCY_MIN_VERSION}`);
@@ -6043,7 +6704,16 @@ function formatTokensStatusGuide(status, version, installCommand = TOKENS_INSTAL
6043
6704
  ].join("\n");
6044
6705
  }
6045
6706
  }
6707
+ var STALE_TOKENS_NOTE = `- \uC8FC\uC758: \uC774 MCP \uC11C\uBC84\uAC00 ${TOKENS_PACKAGE} \uB97C \uCC98\uC74C \uC77D\uC740 \uB4A4 \uB0B4\uC6A9\uC774 \uBC14\uB00C\uC5C8\uB294\uB370 \uC0C8 \uC0C1\uD0DC\uB97C \uB2E4\uC2DC \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4. \uC704 \uACB0\uACFC\uB294 \uC774\uC804 \uC124\uCE58 \uAE30\uC900\uC77C \uC218 \uC788\uC73C\uB2C8 MCP \uC11C\uBC84\uB97C \uB2E4\uC2DC \uC2DC\uC791\uD558\uC138\uC694.`;
6708
+ function withStaleNote(text, result) {
6709
+ return result.stale ? `${text}
6710
+
6711
+ ${STALE_TOKENS_NOTE}` : text;
6712
+ }
6046
6713
  function formatListBrandsResult(result, installCommand) {
6714
+ return withStaleNote(listBrandsText(result, installCommand), result);
6715
+ }
6716
+ function listBrandsText(result, installCommand) {
6047
6717
  const lines = ["## AXIS \uBE0C\uB79C\uB4DC\n"];
6048
6718
  if (result.status !== "ok") {
6049
6719
  lines.push(formatTokensStatusGuide(result.status, result.version, installCommand));
@@ -6081,6 +6751,9 @@ function tokenTable(brand) {
6081
6751
  return lines;
6082
6752
  }
6083
6753
  function formatGetBrandResult(result, name, installCommand) {
6754
+ return withStaleNote(getBrandText(result, name, installCommand), result);
6755
+ }
6756
+ function getBrandText(result, name, installCommand) {
6084
6757
  if (result.status !== "ok") {
6085
6758
  return [`## \uBE0C\uB79C\uB4DC: ${name}
6086
6759
  `, formatTokensStatusGuide(result.status, result.version, installCommand)].join("\n");
@@ -6281,10 +6954,10 @@ server.tool(
6281
6954
  {
6282
6955
  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)")
6283
6956
  },
6284
- async ({ path: path11 }) => {
6957
+ async ({ path: path12 }) => {
6285
6958
  try {
6286
- const token = handleGetToken({ path: path11 });
6287
- const formatted = formatTokenDetail(token, path11);
6959
+ const token = handleGetToken({ path: path12 });
6960
+ const formatted = formatTokenDetail(token, path12);
6288
6961
  return {
6289
6962
  content: [
6290
6963
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axis-ds/mcp",
3
- "version": "1.4.6",
3
+ "version": "1.4.8",
4
4
  "type": "module",
5
5
  "description": "AXIS Design System - MCP Server for AI-assisted component discovery",
6
6
  "bin": {