@sberbusiness/triplex-next-mcp-server 0.24.0-beta1 → 0.24.0-beta2

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.
@@ -208,3 +208,288 @@ src/components/SliderExtended/
208
208
  | Дата | Изменение |
209
209
  |---|---|
210
210
  | 2026-04-18 | Создан документ |
211
+
212
+ ---
213
+
214
+ ## Примеры использования
215
+
216
+ ### Default
217
+
218
+ `stories/Slider/examples/SliderExtended/DefaultExample.tsx`
219
+
220
+ ```tsx
221
+ import React, { useState } from "react";
222
+ import { SliderExtended, EComponentSize } from "@sberbusiness/triplex-next";
223
+
224
+ export const DefaultExample: React.FC = () => {
225
+ const [value, setValue] = useState(35);
226
+
227
+ return (
228
+ <div style={{ maxWidth: "750px", padding: "30px" }}>
229
+ <div>value = {value}</div>
230
+ <br />
231
+ <SliderExtended min={0} max={100} size={EComponentSize.MD} step={1}>
232
+ <SliderExtended.Rail />
233
+ <SliderExtended.Dot value={value} onChange={setValue}>
234
+ <SliderExtended.Tooltip value={value}>{value}</SliderExtended.Tooltip>
235
+ </SliderExtended.Dot>
236
+ <SliderExtended.Track />
237
+ <SliderExtended.Marks>
238
+ <SliderExtended.Mark value={0}>0</SliderExtended.Mark>
239
+ <SliderExtended.Mark value={35}>35</SliderExtended.Mark>
240
+ <SliderExtended.Mark value={66}>66</SliderExtended.Mark>
241
+ <SliderExtended.Mark value={100}>100</SliderExtended.Mark>
242
+ </SliderExtended.Marks>
243
+ </SliderExtended>
244
+ </div>
245
+ );
246
+ };
247
+ ```
248
+
249
+ ### Range
250
+
251
+ `stories/Slider/examples/SliderExtended/RangeExample.tsx`
252
+
253
+ ```tsx
254
+ import React, { useState } from "react";
255
+ import { SliderExtended, EComponentSize } from "@sberbusiness/triplex-next";
256
+
257
+ export const RangeExample: React.FC = () => {
258
+ const [value1, setValue1] = useState(35);
259
+ const [value2, setValue2] = useState(60);
260
+
261
+ return (
262
+ <div style={{ maxWidth: "750px", padding: "30px" }}>
263
+ <div>values = {`[${value1}, ${value2}]`}</div>
264
+ <br />
265
+ <SliderExtended min={0} max={100} size={EComponentSize.MD} step={1}>
266
+ <SliderExtended.Rail />
267
+ <SliderExtended.Dot value={value1} onChange={setValue1} />
268
+ <SliderExtended.Track />
269
+ <SliderExtended.Dot value={value2} onChange={setValue2} />
270
+ <SliderExtended.Marks>
271
+ <SliderExtended.Mark value={0}>0</SliderExtended.Mark>
272
+ <SliderExtended.Mark value={35}>35</SliderExtended.Mark>
273
+ <SliderExtended.Mark value={66}>66</SliderExtended.Mark>
274
+ <SliderExtended.Mark value={100}>100</SliderExtended.Mark>
275
+ </SliderExtended.Marks>
276
+ </SliderExtended>
277
+ </div>
278
+ );
279
+ };
280
+ ```
281
+
282
+ ### RangeWithTooltip
283
+
284
+ `stories/Slider/examples/SliderExtended/RangeWithTooltipExample.tsx`
285
+
286
+ ```tsx
287
+ import React, { useState } from "react";
288
+ import { SliderExtended, EComponentSize } from "@sberbusiness/triplex-next";
289
+
290
+ export const RangeWithTooltipExample: React.FC = () => {
291
+ const [value1, setValue1] = useState(35);
292
+ const [value2, setValue2] = useState(60);
293
+
294
+ return (
295
+ <div style={{ maxWidth: "750px", padding: "30px" }}>
296
+ <div>values = {`[${value1}, ${value2}]`}</div>
297
+ <br />
298
+ <SliderExtended min={0} max={100} size={EComponentSize.MD} step={1}>
299
+ <SliderExtended.Rail />
300
+ <SliderExtended.Dot value={value1} onChange={setValue1}>
301
+ <SliderExtended.Tooltip value={value1}>{value1}</SliderExtended.Tooltip>
302
+ </SliderExtended.Dot>
303
+ <SliderExtended.Track />
304
+ <SliderExtended.Dot value={value2} onChange={setValue2}>
305
+ <SliderExtended.Tooltip value={value2}>{value2}</SliderExtended.Tooltip>
306
+ </SliderExtended.Dot>
307
+ <SliderExtended.Marks>
308
+ <SliderExtended.Mark value={0}>0</SliderExtended.Mark>
309
+ <SliderExtended.Mark value={35}>35</SliderExtended.Mark>
310
+ <SliderExtended.Mark value={66}>66</SliderExtended.Mark>
311
+ <SliderExtended.Mark value={100}>100</SliderExtended.Mark>
312
+ </SliderExtended.Marks>
313
+ </SliderExtended>
314
+ </div>
315
+ );
316
+ };
317
+ ```
318
+
319
+ ### WithCustomSteps
320
+
321
+ `stories/Slider/examples/SliderExtended/WithCustomStepsExample.tsx`
322
+
323
+ ```tsx
324
+ import React, { useState } from "react";
325
+ import { SliderExtended, EComponentSize } from "@sberbusiness/triplex-next";
326
+
327
+ export const WithCustomStepsExample: React.FC = () => {
328
+ const [value, setValue] = useState(50);
329
+
330
+ return (
331
+ <div style={{ maxWidth: "750px", padding: "30px" }}>
332
+ <div>value = {value}</div>
333
+ <br />
334
+ <SliderExtended min={0} max={100} size={EComponentSize.MD} step={[0, 25, 50, 75, 100]}>
335
+ <SliderExtended.Rail />
336
+ <SliderExtended.Dot value={value} onChange={setValue}>
337
+ <SliderExtended.Tooltip value={value}>{value}</SliderExtended.Tooltip>
338
+ </SliderExtended.Dot>
339
+ <SliderExtended.Track />
340
+ <SliderExtended.Marks>
341
+ <SliderExtended.Mark value={0}>0</SliderExtended.Mark>
342
+ <SliderExtended.Mark value={25}>25</SliderExtended.Mark>
343
+ <SliderExtended.Mark value={50}>50</SliderExtended.Mark>
344
+ <SliderExtended.Mark value={75}>75</SliderExtended.Mark>
345
+ <SliderExtended.Mark value={100}>100</SliderExtended.Mark>
346
+ </SliderExtended.Marks>
347
+ </SliderExtended>
348
+ </div>
349
+ );
350
+ };
351
+ ```
352
+
353
+ ### WithoutTooltip
354
+
355
+ `stories/Slider/examples/SliderExtended/WithoutTooltipExample.tsx`
356
+
357
+ ```tsx
358
+ import React, { useState } from "react";
359
+ import { SliderExtended, EComponentSize } from "@sberbusiness/triplex-next";
360
+
361
+ export const WithoutTooltipExample: React.FC = () => {
362
+ const [value, setValue] = useState(35);
363
+
364
+ return (
365
+ <div style={{ maxWidth: "750px", padding: "30px" }}>
366
+ <div>value = {value}</div>
367
+ <br />
368
+ <SliderExtended min={0} max={100} size={EComponentSize.MD} step={1}>
369
+ <SliderExtended.Rail />
370
+ <SliderExtended.Dot value={value} onChange={setValue} />
371
+ <SliderExtended.Track />
372
+ <SliderExtended.Marks>
373
+ <SliderExtended.Mark value={0}>0</SliderExtended.Mark>
374
+ <SliderExtended.Mark value={35}>35</SliderExtended.Mark>
375
+ <SliderExtended.Mark value={66}>66</SliderExtended.Mark>
376
+ <SliderExtended.Mark value={100}>100</SliderExtended.Mark>
377
+ </SliderExtended.Marks>
378
+ </SliderExtended>
379
+ </div>
380
+ );
381
+ };
382
+ ```
383
+
384
+ ### Disabled
385
+
386
+ `stories/Slider/examples/SliderExtended/DisabledExample.tsx`
387
+
388
+ ```tsx
389
+ import React from "react";
390
+ import { SliderExtended, EComponentSize } from "@sberbusiness/triplex-next";
391
+
392
+ export const DisabledExample: React.FC = () => (
393
+ <div style={{ maxWidth: "750px", padding: "30px" }}>
394
+ <SliderExtended min={0} max={100} size={EComponentSize.MD} step={1} disabled>
395
+ <SliderExtended.Rail />
396
+ <SliderExtended.Dot value={35} onChange={() => {}}>
397
+ <SliderExtended.Tooltip value={35}>35</SliderExtended.Tooltip>
398
+ </SliderExtended.Dot>
399
+ <SliderExtended.Track />
400
+ <SliderExtended.Marks>
401
+ <SliderExtended.Mark value={0}>0</SliderExtended.Mark>
402
+ <SliderExtended.Mark value={35}>35</SliderExtended.Mark>
403
+ <SliderExtended.Mark value={66}>66</SliderExtended.Mark>
404
+ <SliderExtended.Mark value={100}>100</SliderExtended.Mark>
405
+ </SliderExtended.Marks>
406
+ </SliderExtended>
407
+ </div>
408
+ );
409
+ ```
410
+
411
+ ### Reverse
412
+
413
+ `stories/Slider/examples/SliderExtended/ReverseExample.tsx`
414
+
415
+ ```tsx
416
+ import React, { useState } from "react";
417
+ import { SliderExtended, EComponentSize } from "@sberbusiness/triplex-next";
418
+
419
+ export const ReverseExample: React.FC = () => {
420
+ const [value, setValue] = useState(35);
421
+
422
+ return (
423
+ <div style={{ maxWidth: "750px", padding: "30px" }}>
424
+ <div>value = {value}</div>
425
+ <br />
426
+ <SliderExtended min={0} max={100} size={EComponentSize.MD} step={1} reverse>
427
+ <SliderExtended.Rail />
428
+ <SliderExtended.Dot value={value} onChange={setValue}>
429
+ <SliderExtended.Tooltip value={value}>{value}</SliderExtended.Tooltip>
430
+ </SliderExtended.Dot>
431
+ <SliderExtended.Track />
432
+ <SliderExtended.Marks>
433
+ <SliderExtended.Mark value={0}>0</SliderExtended.Mark>
434
+ <SliderExtended.Mark value={35}>35</SliderExtended.Mark>
435
+ <SliderExtended.Mark value={66}>66</SliderExtended.Mark>
436
+ <SliderExtended.Mark value={100}>100</SliderExtended.Mark>
437
+ </SliderExtended.Marks>
438
+ </SliderExtended>
439
+ </div>
440
+ );
441
+ };
442
+ ```
443
+
444
+ ### Amounts
445
+
446
+ `stories/Slider/examples/SliderExtended/AmountsExample.tsx`
447
+
448
+ ```tsx
449
+ import React, { useState } from "react";
450
+ import { range } from "lodash";
451
+ import { SliderExtended, EComponentSize } from "@sberbusiness/triplex-next";
452
+
453
+ export const AmountsExample: React.FC = () => {
454
+ const [value, setValue] = useState(1000000);
455
+
456
+ const amounts = [
457
+ 0,
458
+ 10000,
459
+ ...range(20000, 240000, 20000),
460
+ ...range(240000, 1000000, 40000),
461
+ ...range(1000000, 2150000, 50000),
462
+ ...range(2150000, 2600000, 75000),
463
+ ...range(2600000, 3000000, 100000),
464
+ ...range(3000000, 3800000, 200000),
465
+ ...range(3800000, 9000000, 400000),
466
+ ...range(9000000, 10000000, 500000),
467
+ ...range(10000000, 25000000, 2500000),
468
+ ...range(25000000, 40000000, 5000000),
469
+ ...range(40000000, 90000001, 10000000),
470
+ 100000000,
471
+ ];
472
+
473
+ return (
474
+ <div style={{ maxWidth: "750px", padding: "30px" }}>
475
+ <div>{new Intl.NumberFormat("ru-RU").format(value)}</div>
476
+ <br />
477
+ <SliderExtended min={0} max={99} size={EComponentSize.MD} step={1}>
478
+ <SliderExtended.Rail />
479
+ <SliderExtended.Dot
480
+ value={amounts.findIndex((v) => value === v)}
481
+ onChange={(idx) => setValue(amounts[idx])}
482
+ />
483
+ <SliderExtended.Track />
484
+ <SliderExtended.Marks>
485
+ <SliderExtended.Mark value={0}>0 млн</SliderExtended.Mark>
486
+ <SliderExtended.Mark value={32}>1 млн</SliderExtended.Mark>
487
+ <SliderExtended.Mark value={65}>3 млн</SliderExtended.Mark>
488
+ <SliderExtended.Mark value={99}>100 млн</SliderExtended.Mark>
489
+ </SliderExtended.Marks>
490
+ </SliderExtended>
491
+ </div>
492
+ );
493
+ };
494
+ ```
495
+
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "triplexVersion": "1.25.0",
4
- "generatedAt": "2026-04-19T08:22:25.060Z",
4
+ "generatedAt": "2026-04-28T11:24:56.787Z",
5
5
  "components": [
6
6
  {
7
7
  "name": "AbstractTree",
package/dist/index.js CHANGED
@@ -150,11 +150,13 @@ function loadBundle() {
150
150
  name: mc.name,
151
151
  path: mc.path,
152
152
  raw: readFileSync(resolve(BUNDLE_DIR, mc.file), "utf-8"),
153
+ examples: [],
153
154
  fallback: null
154
155
  } : {
155
156
  name: mc.name,
156
157
  path: mc.path,
157
158
  raw: null,
159
+ examples: [],
158
160
  fallback: {
159
161
  name: mc.name,
160
162
  storiesPath: mc.storiesPath ?? null
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/server.ts","../src/tools/index.ts","../src/parsers/loader.ts","../src/parsers/parseComponent.ts"],"sourcesContent":["import { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { createServer } from \"./server.js\";\n\nasync function main() {\n const server = createServer();\n const transport = new StdioServerTransport();\n await server.connect(transport);\n console.error(\"Triplex MCP Server started\");\n}\n\nmain().catch((error) => {\n console.error(\"Failed to start server:\", error);\n process.exit(1);\n});\n","import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { registerTools } from \"./tools/index.js\";\n\nexport function createServer(): McpServer {\n const server = new McpServer({\n name: \"triplex\",\n version: \"0.1.0\",\n });\n\n registerTools(server);\n\n return server;\n}\n","import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\nimport { loadBundle, loadIcons } from \"../parsers/loader.js\";\n\nexport function registerTools(server: McpServer): void {\n const bundle = loadBundle();\n const icons = loadIcons();\n const availableIconSizes = Array.from(new Set(icons.icons.map((i) => i.size))).sort(\n (a, b) => a - b,\n );\n\n server.tool(\n \"list_components\",\n \"Список всех компонентов дизайн-системы Triplex с кратким описанием и флагом ai_ready.\",\n {},\n async () => {\n const list = bundle.components.map((c) => ({\n name: c.name,\n description: c.description,\n category: c.category,\n ai_ready: c.ai_ready,\n }));\n\n return {\n content: [{ type: \"text\", text: JSON.stringify(list, null, 2) }],\n };\n },\n );\n\n server.tool(\n \"get_component\",\n \"Полная документация компонента: назначение, props, токены, инварианты, accessibility, секции AI.md.\",\n { name: z.string().describe(\"Имя компонента, например 'Button'\") },\n async ({ name }) => {\n const component = bundle.components.find((c) => c.name.toLowerCase() === name.toLowerCase());\n\n if (!component) {\n return {\n content: [\n {\n type: \"text\",\n text: `Компонент \"${name}\" не найден. Используйте list_components для списка доступных компонентов.`,\n },\n ],\n isError: true,\n };\n }\n\n return {\n content: [{ type: \"text\", text: JSON.stringify(component, null, 2) }],\n };\n },\n );\n\n server.tool(\n \"get_tokens\",\n \"Дизайн-токены: CSS-переменные компонента или список всех токенов ДС.\",\n {\n component: z\n .string()\n .optional()\n .describe(\"Имя компонента для фильтрации токенов. Если не указано — все токены.\"),\n },\n async ({ component }) => {\n if (component) {\n const comp = bundle.components.find(\n (c) => c.name.toLowerCase() === component.toLowerCase(),\n );\n\n if (!comp) {\n return {\n content: [\n {\n type: \"text\",\n text: `Компонент \"${component}\" не найден.`,\n },\n ],\n isError: true,\n };\n }\n\n return {\n content: [{ type: \"text\", text: JSON.stringify(comp.tokens, null, 2) }],\n };\n }\n\n const allTokens = bundle.components\n .filter((c) => c.tokens.length > 0)\n .map((c) => ({ component: c.name, tokens: c.tokens }));\n\n return {\n content: [{ type: \"text\", text: JSON.stringify(allTokens, null, 2) }],\n };\n },\n );\n\n server.tool(\n \"list_icons\",\n \"Список доступных иконок из @sberbusiness/icons-next. Используй перед тем как импортировать иконку, чтобы не придумать несуществующее имя. Фильтрация по подстроке в имени и по размеру.\",\n {\n query: z\n .string()\n .optional()\n .describe(\n \"Подстрока для поиска в имени иконки (регистронезависимая). Напр. 'plus' или 'arrow'.\",\n ),\n size: z\n .number()\n .int()\n .positive()\n .optional()\n .describe(\"Размер иконки в px (см. availableSizes в ответе для доступных значений).\"),\n limit: z\n .number()\n .int()\n .positive()\n .max(500)\n .optional()\n .describe(\"Максимум иконок в ответе. По умолчанию 100.\"),\n },\n async ({ query, size, limit }) => {\n if (icons.icons.length === 0) {\n return {\n content: [\n {\n type: \"text\",\n text: \"Список иконок пуст — сервер не смог загрузить bundle/icons.json. Проверь, что 'npm run fetch-icons' отработал на этапе сборки.\",\n },\n ],\n isError: true,\n };\n }\n\n const needle = query?.trim().toLowerCase() ?? \"\";\n const max = limit ?? 100;\n\n const matched = icons.icons.filter((ic) => {\n if (size !== undefined && ic.size !== size) return false;\n if (needle && !ic.name.toLowerCase().includes(needle)) return false;\n return true;\n });\n\n const truncated = matched.length > max;\n const page = truncated ? matched.slice(0, max) : matched;\n\n const payload = {\n package: `${icons.packageName}@${icons.packageVersion}`,\n totalInBundle: icons.icons.length,\n matched: matched.length,\n returned: page.length,\n truncated,\n availableSizes: availableIconSizes,\n icons: page,\n usage: \"import { IconName } from '@sberbusiness/icons-next'; <IconName />\",\n };\n\n return {\n content: [{ type: \"text\", text: JSON.stringify(payload, null, 2) }],\n };\n },\n );\n}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { dirname, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { IconsBundle, Manifest, ParsedBundle, RawComponent } from \"../types/index.js\";\nimport { parseComponent } from \"./parseComponent.js\";\n\nconst EMPTY_BUNDLE: ParsedBundle = {\n schemaVersion: 1,\n triplexVersion: \"0.0.0\",\n generatedAt: new Date(0).toISOString(),\n components: [],\n guides: [],\n releaseNotes: [],\n};\n\nconst EMPTY_ICONS: IconsBundle = {\n schemaVersion: 1,\n packageName: \"@sberbusiness/icons-next\",\n packageVersion: \"0.0.0\",\n generatedAt: new Date(0).toISOString(),\n icons: [],\n};\n\n/**\n * Tsup bundles всю source в `dist/index.js`, поэтому относительный путь\n * src/parsers/loader.ts → bundle/... не совпадает с runtime-путём.\n * Идём вверх до ближайшего `package.json` — так корень пакета находится\n * и в dev (tsx/vitest из src/), и в prod (bundled dist/), и после npm-install.\n */\nfunction findPackageRoot(startDir: string): string {\n let dir = startDir;\n while (dir !== dirname(dir)) {\n if (existsSync(resolve(dir, \"package.json\"))) {\n return dir;\n }\n dir = dirname(dir);\n }\n throw new Error(`package.json not found above ${startDir}`);\n}\n\nconst PACKAGE_ROOT = findPackageRoot(dirname(fileURLToPath(import.meta.url)));\nconst BUNDLE_DIR = resolve(PACKAGE_ROOT, \"bundle\");\nconst MANIFEST_PATH = resolve(BUNDLE_DIR, \"manifest.json\");\nconst ICONS_PATH = resolve(BUNDLE_DIR, \"icons.json\");\n\nexport function loadIcons(): IconsBundle {\n try {\n return JSON.parse(readFileSync(ICONS_PATH, \"utf-8\")) as IconsBundle;\n } catch {\n console.error(`Failed to load icons from ${ICONS_PATH}. Run 'npm run fetch-icons' first.`);\n return EMPTY_ICONS;\n }\n}\n\nexport function loadBundle(): ParsedBundle {\n let manifest: Manifest;\n try {\n manifest = JSON.parse(readFileSync(MANIFEST_PATH, \"utf-8\")) as Manifest;\n } catch {\n console.error(\n `Failed to load manifest from ${MANIFEST_PATH}. Run 'npm run fetch-bundle' first.`,\n );\n return EMPTY_BUNDLE;\n }\n\n return {\n schemaVersion: manifest.schemaVersion,\n triplexVersion: manifest.triplexVersion,\n generatedAt: manifest.generatedAt,\n components: manifest.components.map((mc) => {\n const raw: RawComponent =\n mc.file !== null\n ? {\n name: mc.name,\n path: mc.path,\n raw: readFileSync(resolve(BUNDLE_DIR, mc.file), \"utf-8\"),\n fallback: null,\n }\n : {\n name: mc.name,\n path: mc.path,\n raw: null,\n fallback: {\n name: mc.name,\n storiesPath: mc.storiesPath ?? null,\n },\n };\n return parseComponent(raw);\n }),\n guides: manifest.guides.map((g) => ({\n topic: g.topic,\n path: g.path,\n raw: readFileSync(resolve(BUNDLE_DIR, g.file), \"utf-8\"),\n })),\n releaseNotes: manifest.releaseNotes.map((n) => ({\n version: n.version,\n path: n.path,\n raw: readFileSync(resolve(BUNDLE_DIR, n.file), \"utf-8\"),\n })),\n };\n}\n","import matter from \"gray-matter\";\nimport type { ComponentFrontmatter, ParsedComponent, RawComponent } from \"../types/index.js\";\n\nconst SECTION_HEADING_RE = /^##\\s+(.+?)\\s*$/;\n\nexport function parseComponent(raw: RawComponent): ParsedComponent {\n if (raw.raw === null) {\n const fallback = raw.fallback ?? { name: raw.name, storiesPath: null };\n return {\n name: raw.name,\n path: raw.path,\n ai_ready: false,\n category: null,\n description: null,\n figma: { file: null, node: null },\n related: [],\n tokens: [],\n stories: fallback.storiesPath,\n sections: {},\n markdown: null,\n };\n }\n\n const parsed = matter(raw.raw);\n const fm = parsed.data as ComponentFrontmatter;\n const body = parsed.content;\n const sections = extractSections(body);\n\n return {\n name: raw.name,\n path: raw.path,\n ai_ready: true,\n category: fm.category ?? null,\n description: extractDescription(sections),\n figma: {\n file: nonEmpty(fm[\"figma-file\"]),\n node: nonEmpty(fm[\"figma-node\"]),\n },\n related: Array.isArray(fm.related) ? fm.related : [],\n tokens: Array.isArray(fm.tokens) ? fm.tokens : [],\n stories: fm.stories ?? null,\n sections,\n markdown: body,\n };\n}\n\nfunction extractSections(body: string): Record<string, string> {\n const sections: Record<string, string> = {};\n let currentTitle: string | null = null;\n let buffer: string[] = [];\n\n const flush = () => {\n if (currentTitle !== null) {\n sections[currentTitle] = buffer.join(\"\\n\").trim();\n }\n };\n\n for (const line of body.split(\"\\n\")) {\n const match = SECTION_HEADING_RE.exec(line);\n if (match) {\n flush();\n currentTitle = match[1];\n buffer = [];\n } else if (currentTitle !== null) {\n buffer.push(line);\n }\n }\n flush();\n return sections;\n}\n\nfunction extractDescription(sections: Record<string, string>): string | null {\n const purpose = sections[\"Назначение\"];\n if (!purpose) {\n return null;\n }\n const firstParagraph = purpose\n .split(/\\n\\s*\\n/)\n .map((p) => p.trim())\n .find((p) => p.length > 0);\n return firstParagraph ?? null;\n}\n\nfunction nonEmpty(value: string | undefined): string | null {\n if (typeof value !== \"string\") {\n return null;\n }\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : null;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/server.ts","../src/tools/index.ts","../src/parsers/loader.ts","../src/parsers/parseComponent.ts"],"sourcesContent":["import { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { createServer } from \"./server.js\";\n\nasync function main() {\n const server = createServer();\n const transport = new StdioServerTransport();\n await server.connect(transport);\n console.error(\"Triplex MCP Server started\");\n}\n\nmain().catch((error) => {\n console.error(\"Failed to start server:\", error);\n process.exit(1);\n});\n","import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { registerTools } from \"./tools/index.js\";\n\nexport function createServer(): McpServer {\n const server = new McpServer({\n name: \"triplex\",\n version: \"0.1.0\",\n });\n\n registerTools(server);\n\n return server;\n}\n","import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\nimport { loadBundle, loadIcons } from \"../parsers/loader.js\";\n\nexport function registerTools(server: McpServer): void {\n const bundle = loadBundle();\n const icons = loadIcons();\n const availableIconSizes = Array.from(new Set(icons.icons.map((i) => i.size))).sort(\n (a, b) => a - b,\n );\n\n server.tool(\n \"list_components\",\n \"Список всех компонентов дизайн-системы Triplex с кратким описанием и флагом ai_ready.\",\n {},\n async () => {\n const list = bundle.components.map((c) => ({\n name: c.name,\n description: c.description,\n category: c.category,\n ai_ready: c.ai_ready,\n }));\n\n return {\n content: [{ type: \"text\", text: JSON.stringify(list, null, 2) }],\n };\n },\n );\n\n server.tool(\n \"get_component\",\n \"Полная документация компонента: назначение, props, токены, инварианты, accessibility, секции AI.md.\",\n { name: z.string().describe(\"Имя компонента, например 'Button'\") },\n async ({ name }) => {\n const component = bundle.components.find((c) => c.name.toLowerCase() === name.toLowerCase());\n\n if (!component) {\n return {\n content: [\n {\n type: \"text\",\n text: `Компонент \"${name}\" не найден. Используйте list_components для списка доступных компонентов.`,\n },\n ],\n isError: true,\n };\n }\n\n return {\n content: [{ type: \"text\", text: JSON.stringify(component, null, 2) }],\n };\n },\n );\n\n server.tool(\n \"get_tokens\",\n \"Дизайн-токены: CSS-переменные компонента или список всех токенов ДС.\",\n {\n component: z\n .string()\n .optional()\n .describe(\"Имя компонента для фильтрации токенов. Если не указано — все токены.\"),\n },\n async ({ component }) => {\n if (component) {\n const comp = bundle.components.find(\n (c) => c.name.toLowerCase() === component.toLowerCase(),\n );\n\n if (!comp) {\n return {\n content: [\n {\n type: \"text\",\n text: `Компонент \"${component}\" не найден.`,\n },\n ],\n isError: true,\n };\n }\n\n return {\n content: [{ type: \"text\", text: JSON.stringify(comp.tokens, null, 2) }],\n };\n }\n\n const allTokens = bundle.components\n .filter((c) => c.tokens.length > 0)\n .map((c) => ({ component: c.name, tokens: c.tokens }));\n\n return {\n content: [{ type: \"text\", text: JSON.stringify(allTokens, null, 2) }],\n };\n },\n );\n\n server.tool(\n \"list_icons\",\n \"Список доступных иконок из @sberbusiness/icons-next. Используй перед тем как импортировать иконку, чтобы не придумать несуществующее имя. Фильтрация по подстроке в имени и по размеру.\",\n {\n query: z\n .string()\n .optional()\n .describe(\n \"Подстрока для поиска в имени иконки (регистронезависимая). Напр. 'plus' или 'arrow'.\",\n ),\n size: z\n .number()\n .int()\n .positive()\n .optional()\n .describe(\"Размер иконки в px (см. availableSizes в ответе для доступных значений).\"),\n limit: z\n .number()\n .int()\n .positive()\n .max(500)\n .optional()\n .describe(\"Максимум иконок в ответе. По умолчанию 100.\"),\n },\n async ({ query, size, limit }) => {\n if (icons.icons.length === 0) {\n return {\n content: [\n {\n type: \"text\",\n text: \"Список иконок пуст — сервер не смог загрузить bundle/icons.json. Проверь, что 'npm run fetch-icons' отработал на этапе сборки.\",\n },\n ],\n isError: true,\n };\n }\n\n const needle = query?.trim().toLowerCase() ?? \"\";\n const max = limit ?? 100;\n\n const matched = icons.icons.filter((ic) => {\n if (size !== undefined && ic.size !== size) return false;\n if (needle && !ic.name.toLowerCase().includes(needle)) return false;\n return true;\n });\n\n const truncated = matched.length > max;\n const page = truncated ? matched.slice(0, max) : matched;\n\n const payload = {\n package: `${icons.packageName}@${icons.packageVersion}`,\n totalInBundle: icons.icons.length,\n matched: matched.length,\n returned: page.length,\n truncated,\n availableSizes: availableIconSizes,\n icons: page,\n usage: \"import { IconName } from '@sberbusiness/icons-next'; <IconName />\",\n };\n\n return {\n content: [{ type: \"text\", text: JSON.stringify(payload, null, 2) }],\n };\n },\n );\n}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { dirname, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { IconsBundle, Manifest, ParsedBundle, RawComponent } from \"../types/index.js\";\nimport { parseComponent } from \"./parseComponent.js\";\n\nconst EMPTY_BUNDLE: ParsedBundle = {\n schemaVersion: 1,\n triplexVersion: \"0.0.0\",\n generatedAt: new Date(0).toISOString(),\n components: [],\n guides: [],\n releaseNotes: [],\n};\n\nconst EMPTY_ICONS: IconsBundle = {\n schemaVersion: 1,\n packageName: \"@sberbusiness/icons-next\",\n packageVersion: \"0.0.0\",\n generatedAt: new Date(0).toISOString(),\n icons: [],\n};\n\n/**\n * Tsup bundles всю source в `dist/index.js`, поэтому относительный путь\n * src/parsers/loader.ts → bundle/... не совпадает с runtime-путём.\n * Идём вверх до ближайшего `package.json` — так корень пакета находится\n * и в dev (tsx/vitest из src/), и в prod (bundled dist/), и после npm-install.\n */\nfunction findPackageRoot(startDir: string): string {\n let dir = startDir;\n while (dir !== dirname(dir)) {\n if (existsSync(resolve(dir, \"package.json\"))) {\n return dir;\n }\n dir = dirname(dir);\n }\n throw new Error(`package.json not found above ${startDir}`);\n}\n\nconst PACKAGE_ROOT = findPackageRoot(dirname(fileURLToPath(import.meta.url)));\nconst BUNDLE_DIR = resolve(PACKAGE_ROOT, \"bundle\");\nconst MANIFEST_PATH = resolve(BUNDLE_DIR, \"manifest.json\");\nconst ICONS_PATH = resolve(BUNDLE_DIR, \"icons.json\");\n\nexport function loadIcons(): IconsBundle {\n try {\n return JSON.parse(readFileSync(ICONS_PATH, \"utf-8\")) as IconsBundle;\n } catch {\n console.error(`Failed to load icons from ${ICONS_PATH}. Run 'npm run fetch-icons' first.`);\n return EMPTY_ICONS;\n }\n}\n\nexport function loadBundle(): ParsedBundle {\n let manifest: Manifest;\n try {\n manifest = JSON.parse(readFileSync(MANIFEST_PATH, \"utf-8\")) as Manifest;\n } catch {\n console.error(\n `Failed to load manifest from ${MANIFEST_PATH}. Run 'npm run fetch-bundle' first.`,\n );\n return EMPTY_BUNDLE;\n }\n\n return {\n schemaVersion: manifest.schemaVersion,\n triplexVersion: manifest.triplexVersion,\n generatedAt: manifest.generatedAt,\n components: manifest.components.map((mc) => {\n const raw: RawComponent =\n mc.file !== null\n ? {\n name: mc.name,\n path: mc.path,\n raw: readFileSync(resolve(BUNDLE_DIR, mc.file), \"utf-8\"),\n examples: [],\n fallback: null,\n }\n : {\n name: mc.name,\n path: mc.path,\n raw: null,\n examples: [],\n fallback: {\n name: mc.name,\n storiesPath: mc.storiesPath ?? null,\n },\n };\n return parseComponent(raw);\n }),\n guides: manifest.guides.map((g) => ({\n topic: g.topic,\n path: g.path,\n raw: readFileSync(resolve(BUNDLE_DIR, g.file), \"utf-8\"),\n })),\n releaseNotes: manifest.releaseNotes.map((n) => ({\n version: n.version,\n path: n.path,\n raw: readFileSync(resolve(BUNDLE_DIR, n.file), \"utf-8\"),\n })),\n };\n}\n","import matter from \"gray-matter\";\nimport type { ComponentFrontmatter, ParsedComponent, RawComponent } from \"../types/index.js\";\n\nconst SECTION_HEADING_RE = /^##\\s+(.+?)\\s*$/;\n\nexport function parseComponent(raw: RawComponent): ParsedComponent {\n if (raw.raw === null) {\n const fallback = raw.fallback ?? { name: raw.name, storiesPath: null };\n return {\n name: raw.name,\n path: raw.path,\n ai_ready: false,\n category: null,\n description: null,\n figma: { file: null, node: null },\n related: [],\n tokens: [],\n stories: fallback.storiesPath,\n sections: {},\n markdown: null,\n };\n }\n\n const parsed = matter(raw.raw);\n const fm = parsed.data as ComponentFrontmatter;\n const body = parsed.content;\n const sections = extractSections(body);\n\n return {\n name: raw.name,\n path: raw.path,\n ai_ready: true,\n category: fm.category ?? null,\n description: extractDescription(sections),\n figma: {\n file: nonEmpty(fm[\"figma-file\"]),\n node: nonEmpty(fm[\"figma-node\"]),\n },\n related: Array.isArray(fm.related) ? fm.related : [],\n tokens: Array.isArray(fm.tokens) ? fm.tokens : [],\n stories: fm.stories ?? null,\n sections,\n markdown: body,\n };\n}\n\nfunction extractSections(body: string): Record<string, string> {\n const sections: Record<string, string> = {};\n let currentTitle: string | null = null;\n let buffer: string[] = [];\n\n const flush = () => {\n if (currentTitle !== null) {\n sections[currentTitle] = buffer.join(\"\\n\").trim();\n }\n };\n\n for (const line of body.split(\"\\n\")) {\n const match = SECTION_HEADING_RE.exec(line);\n if (match) {\n flush();\n currentTitle = match[1];\n buffer = [];\n } else if (currentTitle !== null) {\n buffer.push(line);\n }\n }\n flush();\n return sections;\n}\n\nfunction extractDescription(sections: Record<string, string>): string | null {\n const purpose = sections[\"Назначение\"];\n if (!purpose) {\n return null;\n }\n const firstParagraph = purpose\n .split(/\\n\\s*\\n/)\n .map((p) => p.trim())\n .find((p) => p.length > 0);\n return firstParagraph ?? null;\n}\n\nfunction nonEmpty(value: string | undefined): string | null {\n if (typeof value !== \"string\") {\n return null;\n }\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : null;\n}\n"],"mappings":";;;AAAA,SAAS,4BAA4B;;;ACArC,SAAS,iBAAiB;;;ACC1B,SAAS,SAAS;;;ACDlB,SAAS,YAAY,oBAAoB;AACzC,SAAS,SAAS,eAAe;AACjC,SAAS,qBAAqB;;;ACF9B,OAAO,YAAY;AAGnB,IAAM,qBAAqB;AAEpB,SAAS,eAAe,KAAoC;AACjE,MAAI,IAAI,QAAQ,MAAM;AACpB,UAAM,WAAW,IAAI,YAAY,EAAE,MAAM,IAAI,MAAM,aAAa,KAAK;AACrE,WAAO;AAAA,MACL,MAAM,IAAI;AAAA,MACV,MAAM,IAAI;AAAA,MACV,UAAU;AAAA,MACV,UAAU;AAAA,MACV,aAAa;AAAA,MACb,OAAO,EAAE,MAAM,MAAM,MAAM,KAAK;AAAA,MAChC,SAAS,CAAC;AAAA,MACV,QAAQ,CAAC;AAAA,MACT,SAAS,SAAS;AAAA,MAClB,UAAU,CAAC;AAAA,MACX,UAAU;AAAA,IACZ;AAAA,EACF;AAEA,QAAM,SAAS,OAAO,IAAI,GAAG;AAC7B,QAAM,KAAK,OAAO;AAClB,QAAM,OAAO,OAAO;AACpB,QAAM,WAAW,gBAAgB,IAAI;AAErC,SAAO;AAAA,IACL,MAAM,IAAI;AAAA,IACV,MAAM,IAAI;AAAA,IACV,UAAU;AAAA,IACV,UAAU,GAAG,YAAY;AAAA,IACzB,aAAa,mBAAmB,QAAQ;AAAA,IACxC,OAAO;AAAA,MACL,MAAM,SAAS,GAAG,YAAY,CAAC;AAAA,MAC/B,MAAM,SAAS,GAAG,YAAY,CAAC;AAAA,IACjC;AAAA,IACA,SAAS,MAAM,QAAQ,GAAG,OAAO,IAAI,GAAG,UAAU,CAAC;AAAA,IACnD,QAAQ,MAAM,QAAQ,GAAG,MAAM,IAAI,GAAG,SAAS,CAAC;AAAA,IAChD,SAAS,GAAG,WAAW;AAAA,IACvB;AAAA,IACA,UAAU;AAAA,EACZ;AACF;AAEA,SAAS,gBAAgB,MAAsC;AAC7D,QAAM,WAAmC,CAAC;AAC1C,MAAI,eAA8B;AAClC,MAAI,SAAmB,CAAC;AAExB,QAAM,QAAQ,MAAM;AAClB,QAAI,iBAAiB,MAAM;AACzB,eAAS,YAAY,IAAI,OAAO,KAAK,IAAI,EAAE,KAAK;AAAA,IAClD;AAAA,EACF;AAEA,aAAW,QAAQ,KAAK,MAAM,IAAI,GAAG;AACnC,UAAM,QAAQ,mBAAmB,KAAK,IAAI;AAC1C,QAAI,OAAO;AACT,YAAM;AACN,qBAAe,MAAM,CAAC;AACtB,eAAS,CAAC;AAAA,IACZ,WAAW,iBAAiB,MAAM;AAChC,aAAO,KAAK,IAAI;AAAA,IAClB;AAAA,EACF;AACA,QAAM;AACN,SAAO;AACT;AAEA,SAAS,mBAAmB,UAAiD;AAC3E,QAAM,UAAU,SAAS,8DAAY;AACrC,MAAI,CAAC,SAAS;AACZ,WAAO;AAAA,EACT;AACA,QAAM,iBAAiB,QACpB,MAAM,SAAS,EACf,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,EACnB,KAAK,CAAC,MAAM,EAAE,SAAS,CAAC;AAC3B,SAAO,kBAAkB;AAC3B;AAEA,SAAS,SAAS,OAA0C;AAC1D,MAAI,OAAO,UAAU,UAAU;AAC7B,WAAO;AAAA,EACT;AACA,QAAM,UAAU,MAAM,KAAK;AAC3B,SAAO,QAAQ,SAAS,IAAI,UAAU;AACxC;;;ADnFA,IAAM,eAA6B;AAAA,EACjC,eAAe;AAAA,EACf,gBAAgB;AAAA,EAChB,cAAa,oBAAI,KAAK,CAAC,GAAE,YAAY;AAAA,EACrC,YAAY,CAAC;AAAA,EACb,QAAQ,CAAC;AAAA,EACT,cAAc,CAAC;AACjB;AAEA,IAAM,cAA2B;AAAA,EAC/B,eAAe;AAAA,EACf,aAAa;AAAA,EACb,gBAAgB;AAAA,EAChB,cAAa,oBAAI,KAAK,CAAC,GAAE,YAAY;AAAA,EACrC,OAAO,CAAC;AACV;AAQA,SAAS,gBAAgB,UAA0B;AACjD,MAAI,MAAM;AACV,SAAO,QAAQ,QAAQ,GAAG,GAAG;AAC3B,QAAI,WAAW,QAAQ,KAAK,cAAc,CAAC,GAAG;AAC5C,aAAO;AAAA,IACT;AACA,UAAM,QAAQ,GAAG;AAAA,EACnB;AACA,QAAM,IAAI,MAAM,gCAAgC,QAAQ,EAAE;AAC5D;AAEA,IAAM,eAAe,gBAAgB,QAAQ,cAAc,YAAY,GAAG,CAAC,CAAC;AAC5E,IAAM,aAAa,QAAQ,cAAc,QAAQ;AACjD,IAAM,gBAAgB,QAAQ,YAAY,eAAe;AACzD,IAAM,aAAa,QAAQ,YAAY,YAAY;AAE5C,SAAS,YAAyB;AACvC,MAAI;AACF,WAAO,KAAK,MAAM,aAAa,YAAY,OAAO,CAAC;AAAA,EACrD,QAAQ;AACN,YAAQ,MAAM,6BAA6B,UAAU,oCAAoC;AACzF,WAAO;AAAA,EACT;AACF;AAEO,SAAS,aAA2B;AACzC,MAAI;AACJ,MAAI;AACF,eAAW,KAAK,MAAM,aAAa,eAAe,OAAO,CAAC;AAAA,EAC5D,QAAQ;AACN,YAAQ;AAAA,MACN,gCAAgC,aAAa;AAAA,IAC/C;AACA,WAAO;AAAA,EACT;AAEA,SAAO;AAAA,IACL,eAAe,SAAS;AAAA,IACxB,gBAAgB,SAAS;AAAA,IACzB,aAAa,SAAS;AAAA,IACtB,YAAY,SAAS,WAAW,IAAI,CAAC,OAAO;AAC1C,YAAM,MACJ,GAAG,SAAS,OACR;AAAA,QACE,MAAM,GAAG;AAAA,QACT,MAAM,GAAG;AAAA,QACT,KAAK,aAAa,QAAQ,YAAY,GAAG,IAAI,GAAG,OAAO;AAAA,QACvD,UAAU,CAAC;AAAA,QACX,UAAU;AAAA,MACZ,IACA;AAAA,QACE,MAAM,GAAG;AAAA,QACT,MAAM,GAAG;AAAA,QACT,KAAK;AAAA,QACL,UAAU,CAAC;AAAA,QACX,UAAU;AAAA,UACR,MAAM,GAAG;AAAA,UACT,aAAa,GAAG,eAAe;AAAA,QACjC;AAAA,MACF;AACN,aAAO,eAAe,GAAG;AAAA,IAC3B,CAAC;AAAA,IACD,QAAQ,SAAS,OAAO,IAAI,CAAC,OAAO;AAAA,MAClC,OAAO,EAAE;AAAA,MACT,MAAM,EAAE;AAAA,MACR,KAAK,aAAa,QAAQ,YAAY,EAAE,IAAI,GAAG,OAAO;AAAA,IACxD,EAAE;AAAA,IACF,cAAc,SAAS,aAAa,IAAI,CAAC,OAAO;AAAA,MAC9C,SAAS,EAAE;AAAA,MACX,MAAM,EAAE;AAAA,MACR,KAAK,aAAa,QAAQ,YAAY,EAAE,IAAI,GAAG,OAAO;AAAA,IACxD,EAAE;AAAA,EACJ;AACF;;;ADlGO,SAAS,cAAc,QAAyB;AACrD,QAAM,SAAS,WAAW;AAC1B,QAAM,QAAQ,UAAU;AACxB,QAAM,qBAAqB,MAAM,KAAK,IAAI,IAAI,MAAM,MAAM,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,EAAE;AAAA,IAC7E,CAAC,GAAG,MAAM,IAAI;AAAA,EAChB;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,CAAC;AAAA,IACD,YAAY;AACV,YAAM,OAAO,OAAO,WAAW,IAAI,CAAC,OAAO;AAAA,QACzC,MAAM,EAAE;AAAA,QACR,aAAa,EAAE;AAAA,QACf,UAAU,EAAE;AAAA,QACZ,UAAU,EAAE;AAAA,MACd,EAAE;AAEF,aAAO;AAAA,QACL,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,KAAK,UAAU,MAAM,MAAM,CAAC,EAAE,CAAC;AAAA,MACjE;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,4IAAmC,EAAE;AAAA,IACjE,OAAO,EAAE,KAAK,MAAM;AAClB,YAAM,YAAY,OAAO,WAAW,KAAK,CAAC,MAAM,EAAE,KAAK,YAAY,MAAM,KAAK,YAAY,CAAC;AAE3F,UAAI,CAAC,WAAW;AACd,eAAO;AAAA,UACL,SAAS;AAAA,YACP;AAAA,cACE,MAAM;AAAA,cACN,MAAM,2DAAc,IAAI;AAAA,YAC1B;AAAA,UACF;AAAA,UACA,SAAS;AAAA,QACX;AAAA,MACF;AAEA,aAAO;AAAA,QACL,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,KAAK,UAAU,WAAW,MAAM,CAAC,EAAE,CAAC;AAAA,MACtE;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,MACE,WAAW,EACR,OAAO,EACP,SAAS,EACT,SAAS,8VAAsE;AAAA,IACpF;AAAA,IACA,OAAO,EAAE,UAAU,MAAM;AACvB,UAAI,WAAW;AACb,cAAM,OAAO,OAAO,WAAW;AAAA,UAC7B,CAAC,MAAM,EAAE,KAAK,YAAY,MAAM,UAAU,YAAY;AAAA,QACxD;AAEA,YAAI,CAAC,MAAM;AACT,iBAAO;AAAA,YACL,SAAS;AAAA,cACP;AAAA,gBACE,MAAM;AAAA,gBACN,MAAM,2DAAc,SAAS;AAAA,cAC/B;AAAA,YACF;AAAA,YACA,SAAS;AAAA,UACX;AAAA,QACF;AAEA,eAAO;AAAA,UACL,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,KAAK,UAAU,KAAK,QAAQ,MAAM,CAAC,EAAE,CAAC;AAAA,QACxE;AAAA,MACF;AAEA,YAAM,YAAY,OAAO,WACtB,OAAO,CAAC,MAAM,EAAE,OAAO,SAAS,CAAC,EACjC,IAAI,CAAC,OAAO,EAAE,WAAW,EAAE,MAAM,QAAQ,EAAE,OAAO,EAAE;AAEvD,aAAO;AAAA,QACL,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,KAAK,UAAU,WAAW,MAAM,CAAC,EAAE,CAAC;AAAA,MACtE;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,MACE,OAAO,EACJ,OAAO,EACP,SAAS,EACT;AAAA,QACC;AAAA,MACF;AAAA,MACF,MAAM,EACH,OAAO,EACP,IAAI,EACJ,SAAS,EACT,SAAS,EACT,SAAS,4RAA0E;AAAA,MACtF,OAAO,EACJ,OAAO,EACP,IAAI,EACJ,SAAS,EACT,IAAI,GAAG,EACP,SAAS,EACT,SAAS,6MAA6C;AAAA,IAC3D;AAAA,IACA,OAAO,EAAE,OAAO,MAAM,MAAM,MAAM;AAChC,UAAI,MAAM,MAAM,WAAW,GAAG;AAC5B,eAAO;AAAA,UACL,SAAS;AAAA,YACP;AAAA,cACE,MAAM;AAAA,cACN,MAAM;AAAA,YACR;AAAA,UACF;AAAA,UACA,SAAS;AAAA,QACX;AAAA,MACF;AAEA,YAAM,SAAS,OAAO,KAAK,EAAE,YAAY,KAAK;AAC9C,YAAM,MAAM,SAAS;AAErB,YAAM,UAAU,MAAM,MAAM,OAAO,CAAC,OAAO;AACzC,YAAI,SAAS,UAAa,GAAG,SAAS,KAAM,QAAO;AACnD,YAAI,UAAU,CAAC,GAAG,KAAK,YAAY,EAAE,SAAS,MAAM,EAAG,QAAO;AAC9D,eAAO;AAAA,MACT,CAAC;AAED,YAAM,YAAY,QAAQ,SAAS;AACnC,YAAM,OAAO,YAAY,QAAQ,MAAM,GAAG,GAAG,IAAI;AAEjD,YAAM,UAAU;AAAA,QACd,SAAS,GAAG,MAAM,WAAW,IAAI,MAAM,cAAc;AAAA,QACrD,eAAe,MAAM,MAAM;AAAA,QAC3B,SAAS,QAAQ;AAAA,QACjB,UAAU,KAAK;AAAA,QACf;AAAA,QACA,gBAAgB;AAAA,QAChB,OAAO;AAAA,QACP,OAAO;AAAA,MACT;AAEA,aAAO;AAAA,QACL,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,KAAK,UAAU,SAAS,MAAM,CAAC,EAAE,CAAC;AAAA,MACpE;AAAA,IACF;AAAA,EACF;AACF;;;AD9JO,SAAS,eAA0B;AACxC,QAAM,SAAS,IAAI,UAAU;AAAA,IAC3B,MAAM;AAAA,IACN,SAAS;AAAA,EACX,CAAC;AAED,gBAAc,MAAM;AAEpB,SAAO;AACT;;;ADTA,eAAe,OAAO;AACpB,QAAM,SAAS,aAAa;AAC5B,QAAM,YAAY,IAAI,qBAAqB;AAC3C,QAAM,OAAO,QAAQ,SAAS;AAC9B,UAAQ,MAAM,4BAA4B;AAC5C;AAEA,KAAK,EAAE,MAAM,CAAC,UAAU;AACtB,UAAQ,MAAM,2BAA2B,KAAK;AAC9C,UAAQ,KAAK,CAAC;AAChB,CAAC;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sberbusiness/triplex-next-mcp-server",
3
- "version": "0.24.0-beta1",
3
+ "version": "0.24.0-beta2",
4
4
  "description": "MCP-сервер для дизайн-системы Triplex. Предоставляет AI-агентам документацию компонентов, дизайн-токены и примеры использования.",
5
5
  "author": "СберБизнес",
6
6
  "license": "MIT",