@sberbusiness/triplex-next-mcp-server 1.44.0-beta → 1.45.0-beta
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -6
- package/bundle/components/AlertContext.md +11 -8
- package/bundle/components/AlertProcess.md +13 -10
- package/bundle/components/Badge.md +6 -3
- package/bundle/components/Button.md +46 -43
- package/bundle/components/ButtonDropdownExtended.md +3 -2
- package/bundle/components/ButtonIcon.md +7 -4
- package/bundle/components/Calendar.md +62 -59
- package/bundle/components/Caption.md +26 -23
- package/bundle/components/Checkbox.md +32 -29
- package/bundle/components/CheckboxTreeExtended.md +9 -5
- package/bundle/components/Chip.md +44 -41
- package/bundle/components/CodeText.md +26 -23
- package/bundle/components/Col.md +1 -2
- package/bundle/components/CollapsibleTree.md +8 -5
- package/bundle/components/Dropdown.md +33 -28
- package/bundle/components/EmptyView.md +12 -5
- package/bundle/components/FooterPage.md +6 -2
- package/bundle/components/FormField.md +44 -41
- package/bundle/components/FormGroup.md +192 -52
- package/bundle/components/Header.md +491 -211
- package/bundle/components/HeaderPage.md +6 -2
- package/bundle/components/ImageGallery.md +33 -34
- package/bundle/components/ImageGalleryExtended.md +33 -34
- package/bundle/components/Island.md +16 -13
- package/bundle/components/LightBox.md +14 -12
- package/bundle/components/Link.md +211 -96
- package/bundle/components/ListActionItem.md +7 -4
- package/bundle/components/ListItem.md +11 -8
- package/bundle/components/ListItemControlsButton.md +16 -13
- package/bundle/components/ListItemControlsButtonDropdown.md +9 -6
- package/bundle/components/ListItemSelectable.md +7 -4
- package/bundle/components/ListMasterFooter.md +8 -5
- package/bundle/components/ListMasterHeader.md +8 -5
- package/bundle/components/ListSortableItem.md +11 -8
- package/bundle/components/ListTableItem.md +7 -4
- package/bundle/components/LoaderMiddle.md +7 -4
- package/bundle/components/LoaderScreen.md +11 -8
- package/bundle/components/LoaderSmall.md +7 -4
- package/bundle/components/Marker.md +184 -69
- package/bundle/components/MarkerStatus.md +206 -88
- package/bundle/components/MaskedField.md +2 -4
- package/bundle/components/MasterTable.md +602 -0
- package/bundle/components/ModalWindow.md +7 -4
- package/bundle/components/MultiselectField.md +2183 -132
- package/bundle/components/Notification.md +12 -9
- package/bundle/components/Overlay.md +9 -4
- package/bundle/components/Page.md +2 -2
- package/bundle/components/Pagination.md +15 -8
- package/bundle/components/Row.md +1 -1
- package/bundle/components/SelectExtendedField.md +3 -3
- package/bundle/components/SelectField.md +466 -148
- package/bundle/components/SliderExtended.md +39 -36
- package/bundle/components/SmallInput.md +194 -51
- package/bundle/components/Suggest.md +535 -99
- package/bundle/components/SwipeableArea.md +428 -79
- package/bundle/components/TableBasic.md +19 -11
- package/bundle/components/TabsExtended.md +24 -21
- package/bundle/components/Tag.md +6 -2
- package/bundle/components/Text.md +28 -25
- package/bundle/components/TextField.md +3 -4
- package/bundle/components/ThemeProvider.md +50 -1
- package/bundle/components/Title.md +26 -23
- package/bundle/components/Tooltip.md +24 -21
- package/bundle/components/TopOverlay.md +7 -4
- package/bundle/guides/codestyle.md +3 -0
- package/bundle/guides/context.md +84 -12
- package/bundle/guides/guidelines.md +321 -0
- package/bundle/guides/template.md +22 -12
- package/bundle/manifest.json +31 -14
- package/bundle/release-notes/1.45.0.mdx +117 -0
- package/bundle/release-notes/1.46.0.mdx +7 -0
- package/bundle/tokens.json +6362 -0
- package/dist/index.js +177 -28
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -100,7 +100,8 @@ var EMPTY_BUNDLE = {
|
|
|
100
100
|
generatedAt: (/* @__PURE__ */ new Date(0)).toISOString(),
|
|
101
101
|
components: [],
|
|
102
102
|
guides: [],
|
|
103
|
-
releaseNotes: []
|
|
103
|
+
releaseNotes: [],
|
|
104
|
+
tokens: null
|
|
104
105
|
};
|
|
105
106
|
var EMPTY_ICONS = {
|
|
106
107
|
schemaVersion: 1,
|
|
@@ -131,6 +132,19 @@ function loadIcons() {
|
|
|
131
132
|
return EMPTY_ICONS;
|
|
132
133
|
}
|
|
133
134
|
}
|
|
135
|
+
function loadTokens(manifest) {
|
|
136
|
+
if (!manifest.tokens) {
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
try {
|
|
140
|
+
return JSON.parse(readFileSync(resolve(BUNDLE_DIR, manifest.tokens), "utf-8"));
|
|
141
|
+
} catch {
|
|
142
|
+
console.error(
|
|
143
|
+
`Failed to load tokens from ${manifest.tokens}. Run 'npm run fetch-bundle' first.`
|
|
144
|
+
);
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
134
148
|
function loadBundle() {
|
|
135
149
|
let manifest;
|
|
136
150
|
try {
|
|
@@ -173,7 +187,153 @@ function loadBundle() {
|
|
|
173
187
|
version: n.version,
|
|
174
188
|
path: n.path,
|
|
175
189
|
raw: readFileSync(resolve(BUNDLE_DIR, n.file), "utf-8")
|
|
176
|
-
}))
|
|
190
|
+
})),
|
|
191
|
+
tokens: loadTokens(manifest)
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// src/tools/guidelines.ts
|
|
196
|
+
var GUIDELINES_TOPIC = "guidelines";
|
|
197
|
+
function buildGuidelinesResponse(bundle) {
|
|
198
|
+
const guide = bundle.guides.find((g) => g.topic === GUIDELINES_TOPIC);
|
|
199
|
+
if (!guide) {
|
|
200
|
+
return {
|
|
201
|
+
ok: false,
|
|
202
|
+
text: `Bundle \u0441\u043E\u0431\u0440\u0430\u043D \u0438\u0437 triplex-next ${bundle.triplexVersion} \u0438 \u0433\u0430\u0439\u0434\u043B\u0430\u0439\u043D\u043E\u0432 \u043D\u0435 \u0441\u043E\u0434\u0435\u0440\u0436\u0438\u0442 \u2014 \u043E\u043D\u0438 \u043F\u043E\u0441\u0442\u0430\u0432\u043B\u044F\u044E\u0442\u0441\u044F \u043D\u0430\u0447\u0438\u043D\u0430\u044F \u0441 1.45.0. \u041E\u0431\u043D\u043E\u0432\u0438\u0442\u0435 bundle: npm run fetch-bundle.`
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
return { ok: true, text: guide.raw };
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// src/tools/tokens.ts
|
|
209
|
+
var LEGACY_NOTE = "Bundle \u0441\u043E\u0431\u0440\u0430\u043D \u0434\u043E schemaVersion 2 \u0438 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0439 \u0442\u043E\u043A\u0435\u043D\u043E\u0432 \u043D\u0435 \u0441\u043E\u0434\u0435\u0440\u0436\u0438\u0442 \u2014 \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u044B \u0442\u043E\u043B\u044C\u043A\u043E \u043F\u0443\u0442\u0438. \u041E\u0431\u043D\u043E\u0432\u0438\u0442\u0435 bundle: npm run fetch-bundle.";
|
|
210
|
+
function howToOverride(group) {
|
|
211
|
+
return {
|
|
212
|
+
api: "<ThemeProvider tokens={...}> \u0438\u0437 @sberbusiness/triplex-next",
|
|
213
|
+
example: [
|
|
214
|
+
"const TOKENS = {",
|
|
215
|
+
` ${group}: {`,
|
|
216
|
+
' <\u0422\u043E\u043A\u0435\u043D>: {value: "#FFFFFF"}, // \u0441\u0432\u043E\u0451 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435',
|
|
217
|
+
' <\u0414\u0440\u0443\u0433\u043E\u0439>: {ref: "ColorBrand.50"}, // \u0441\u0441\u044B\u043B\u043A\u0430 \u043D\u0430 core-\u0442\u043E\u043A\u0435\u043D',
|
|
218
|
+
" },",
|
|
219
|
+
"};",
|
|
220
|
+
"",
|
|
221
|
+
"<ThemeProvider tokens={TOKENS} scopeRef={scopeRef}>\u2026</ThemeProvider>"
|
|
222
|
+
].join("\n"),
|
|
223
|
+
notes: [
|
|
224
|
+
"\u041E\u0431\u044A\u0435\u043A\u0442 tokens \u043F\u043B\u043E\u0441\u043A\u0438\u0439: \u0433\u0440\u0443\u043F\u043F\u044B \u043B\u0435\u0436\u0430\u0442 \u043D\u0430 \u0432\u0435\u0440\u0445\u043D\u0435\u043C \u0443\u0440\u043E\u0432\u043D\u0435, \u0432\u043B\u043E\u0436\u0435\u043D\u043D\u043E\u0441\u0442\u0438 core/components \u043D\u0435\u0442.",
|
|
225
|
+
"\u041E\u0434\u043D\u0438\u043C \u043E\u0431\u044A\u0435\u043A\u0442\u043E\u043C \u043C\u043E\u0436\u043D\u043E \u043F\u0435\u0440\u0435\u043E\u043F\u0440\u0435\u0434\u0435\u043B\u0438\u0442\u044C \u043D\u0435\u0441\u043A\u043E\u043B\u044C\u043A\u043E \u0433\u0440\u0443\u043F\u043F \u0441\u0440\u0430\u0437\u0443 \u2014 \u0438 core, \u0438 \u043A\u043E\u043C\u043F\u043E\u043D\u0435\u043D\u0442\u043D\u044B\u0435.",
|
|
226
|
+
"ref \u0443\u043A\u0430\u0437\u044B\u0432\u0430\u0435\u0442 \u0442\u043E\u043B\u044C\u043A\u043E \u043D\u0430 core-\u0442\u043E\u043A\u0435\u043D\u044B (refable: true).",
|
|
227
|
+
"tokens \u0441\u0440\u0430\u0432\u043D\u0438\u0432\u0430\u0435\u0442\u0441\u044F \u043F\u043E \u0441\u0441\u044B\u043B\u043A\u0435 \u2014 \u0432\u044B\u043D\u043E\u0441\u0438\u0442\u0435 \u043E\u0431\u044A\u0435\u043A\u0442 \u0438\u0437 \u0440\u0435\u043D\u0434\u0435\u0440\u0430.",
|
|
228
|
+
"\u041F\u0435\u0440\u0435\u043E\u043F\u0440\u0435\u0434\u0435\u043B\u0435\u043D\u0438\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0443\u0435\u0442 \u0432\u043D\u0443\u0442\u0440\u0438 \u044D\u043B\u0435\u043C\u0435\u043D\u0442\u0430 \u0438\u0437 scopeRef."
|
|
229
|
+
]
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
function internalNote(section) {
|
|
233
|
+
return {
|
|
234
|
+
cssVarPattern: section.internal.cssVarPattern,
|
|
235
|
+
note: "\u0412\u043D\u0443\u0442\u0440\u0435\u043D\u043D\u044F\u044F \u0440\u0435\u0430\u043B\u0438\u0437\u0430\u0446\u0438\u044F: \u0432 \u0441\u043E\u0431\u0440\u0430\u043D\u043D\u043E\u043C \u043F\u0430\u043A\u0435\u0442\u0435 \u043A \u0438\u043C\u0435\u043D\u0438 \u043F\u0435\u0440\u0435\u043C\u0435\u043D\u043D\u043E\u0439 \u0434\u043E\u0431\u0430\u0432\u043B\u044F\u0435\u0442\u0441\u044F \u0432\u0435\u0440\u0441\u0438\u044F, \u043F\u043E\u044D\u0442\u043E\u043C\u0443 \u0432 \u043A\u043E\u0434\u0435 \u043F\u043E\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043B\u044F \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u044C \u0435\u0451 \u043D\u0435\u043B\u044C\u0437\u044F."
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
function coreTokensUsed(tokens) {
|
|
239
|
+
const refs = tokens.flatMap(
|
|
240
|
+
(token) => [token.light.ref, token.dark.ref].filter((ref) => ref !== void 0)
|
|
241
|
+
);
|
|
242
|
+
return [...new Set(refs)].sort();
|
|
243
|
+
}
|
|
244
|
+
function groupIndex(section, kind) {
|
|
245
|
+
return Object.fromEntries(
|
|
246
|
+
Object.entries(section.groups).filter(([, group]) => group.kind === kind).map(([name, group]) => [name, Object.keys(group.tokens).length])
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
function byGroup(section, group) {
|
|
250
|
+
const name = Object.keys(section.groups).find((key) => key.toLowerCase() === group.toLowerCase());
|
|
251
|
+
if (name === void 0) {
|
|
252
|
+
return {
|
|
253
|
+
ok: false,
|
|
254
|
+
text: `\u0413\u0440\u0443\u043F\u043F\u0430 \u0442\u043E\u043A\u0435\u043D\u043E\u0432 "${group}" \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D\u0430. \u0421\u043F\u0438\u0441\u043E\u043A \u0433\u0440\u0443\u043F\u043F: get_tokens() \u0431\u0435\u0437 \u0430\u0440\u0433\u0443\u043C\u0435\u043D\u0442\u043E\u0432.`
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
const entry = section.groups[name];
|
|
258
|
+
return {
|
|
259
|
+
ok: true,
|
|
260
|
+
payload: {
|
|
261
|
+
group: name,
|
|
262
|
+
kind: entry.kind,
|
|
263
|
+
refable: entry.refable,
|
|
264
|
+
tokenCount: Object.keys(entry.tokens).length,
|
|
265
|
+
howToOverride: howToOverride(name),
|
|
266
|
+
tokens: Object.values(entry.tokens),
|
|
267
|
+
internal: internalNote(section)
|
|
268
|
+
}
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
function byComponent(bundle, section, component) {
|
|
272
|
+
const found = bundle.components.find((c) => c.name.toLowerCase() === component.toLowerCase());
|
|
273
|
+
if (!found) {
|
|
274
|
+
return {
|
|
275
|
+
ok: false,
|
|
276
|
+
text: `\u041A\u043E\u043C\u043F\u043E\u043D\u0435\u043D\u0442 "${component}" \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D. \u0418\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0439\u0442\u0435 list_components \u0434\u043B\u044F \u0441\u043F\u0438\u0441\u043A\u0430 \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u044B\u0445 \u043A\u043E\u043C\u043F\u043E\u043D\u0435\u043D\u0442\u043E\u0432.`
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
if (section === null) {
|
|
280
|
+
return {
|
|
281
|
+
ok: true,
|
|
282
|
+
payload: { component: found.name, tokens: found.tokens, note: LEGACY_NOTE }
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
const resolved = found.tokens.map((path) => {
|
|
286
|
+
const [group, token] = path.split(".");
|
|
287
|
+
return { path, entry: section.groups[group]?.tokens[token] };
|
|
288
|
+
});
|
|
289
|
+
const known = resolved.map(({ entry }) => entry).filter((entry) => entry !== void 0);
|
|
290
|
+
const unknown = resolved.filter(({ entry }) => entry === void 0).map(({ path }) => path);
|
|
291
|
+
const groups = [...new Set(known.map((token) => token.path.split(".")[0]))];
|
|
292
|
+
return {
|
|
293
|
+
ok: true,
|
|
294
|
+
payload: {
|
|
295
|
+
component: found.name,
|
|
296
|
+
groups,
|
|
297
|
+
tokenCount: known.length,
|
|
298
|
+
howToOverride: howToOverride(groups[0] ?? "\u0413\u0440\u0443\u043F\u043F\u0430"),
|
|
299
|
+
tokens: known,
|
|
300
|
+
// Палитра, на которую ссылаются токены компонента: перекрасив core-токен,
|
|
301
|
+
// потребитель меняет вид всех компонентов, которые на него ссылаются.
|
|
302
|
+
coreTokensUsed: coreTokensUsed(known),
|
|
303
|
+
...unknown.length ? { unknownTokens: unknown } : {},
|
|
304
|
+
internal: internalNote(section)
|
|
305
|
+
}
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
function buildTokensResponse(bundle, query) {
|
|
309
|
+
const section = bundle.tokens;
|
|
310
|
+
if (query.group !== void 0) {
|
|
311
|
+
return section === null ? { ok: false, text: LEGACY_NOTE } : byGroup(section, query.group);
|
|
312
|
+
}
|
|
313
|
+
if (query.component !== void 0) {
|
|
314
|
+
return byComponent(bundle, section, query.component);
|
|
315
|
+
}
|
|
316
|
+
if (section === null) {
|
|
317
|
+
return {
|
|
318
|
+
ok: true,
|
|
319
|
+
payload: {
|
|
320
|
+
note: LEGACY_NOTE,
|
|
321
|
+
components: bundle.components.filter((c) => c.tokens.length > 0).map((c) => ({ component: c.name, tokens: c.tokens }))
|
|
322
|
+
}
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
return {
|
|
326
|
+
ok: true,
|
|
327
|
+
payload: {
|
|
328
|
+
triplexVersion: bundle.triplexVersion,
|
|
329
|
+
overridePath: section.overridePath,
|
|
330
|
+
core: {
|
|
331
|
+
description: '\u041F\u0430\u043B\u0438\u0442\u0440\u0430 \u0438 \u043F\u0440\u0438\u043C\u0438\u0442\u0438\u0432\u044B. \u0421\u0441\u044B\u043B\u043A\u0438 { ref: "ColorBrand.50" } \u0440\u0435\u0437\u043E\u043B\u0432\u044F\u0442\u0441\u044F \u0441\u044E\u0434\u0430.',
|
|
332
|
+
groups: groupIndex(section, "core")
|
|
333
|
+
},
|
|
334
|
+
components: { groups: groupIndex(section, "component") },
|
|
335
|
+
hint: '\u041F\u043E\u043B\u043D\u044B\u0435 \u0434\u0430\u043D\u043D\u044B\u0435: get_tokens({ component: "Calendar" }) \u0438\u043B\u0438 get_tokens({ group: "ColorBrand" }).'
|
|
336
|
+
}
|
|
177
337
|
};
|
|
178
338
|
}
|
|
179
339
|
|
|
@@ -224,34 +384,23 @@ function registerTools(server) {
|
|
|
224
384
|
);
|
|
225
385
|
server.tool(
|
|
226
386
|
"get_tokens",
|
|
227
|
-
"\u0414\u0438\u0437\u0430\u0439\u043D-\u0442\u043E\u043A\u0435\u043D\u044B:
|
|
387
|
+
"\u0414\u0438\u0437\u0430\u0439\u043D-\u0442\u043E\u043A\u0435\u043D\u044B Triplex: \u043F\u0443\u0442\u0438 `\u0413\u0440\u0443\u043F\u043F\u0430.\u0422\u043E\u043A\u0435\u043D` \u0434\u043B\u044F ThemeProvider, \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u044F \u0441\u0432\u0435\u0442\u043B\u043E\u0439 \u0438 \u0442\u0451\u043C\u043D\u043E\u0439 \u0442\u0435\u043C\u044B, \u0441\u0441\u044B\u043B\u043A\u0438 \u043D\u0430 \u043F\u0430\u043B\u0438\u0442\u0440\u0443. \u0411\u0435\u0437 \u0430\u0440\u0433\u0443\u043C\u0435\u043D\u0442\u043E\u0432 \u2014 \u0438\u043D\u0434\u0435\u043A\u0441 \u0433\u0440\u0443\u043F\u043F.",
|
|
228
388
|
{
|
|
229
|
-
component: z.string().optional().describe("\u0418\u043C\u044F \u043A\u043E\u043C\u043F\u043E\u043D\u0435\u043D\u0442\u0430 \
|
|
389
|
+
component: z.string().optional().describe("\u0418\u043C\u044F \u043A\u043E\u043C\u043F\u043E\u043D\u0435\u043D\u0442\u0430: \u0432\u0435\u0440\u043D\u0443\u0442\u044C \u0442\u043E\u043A\u0435\u043D\u044B, \u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u043E\u043D \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0435\u0442. \u041D\u0430\u043F\u0440. 'Calendar'."),
|
|
390
|
+
group: z.string().optional().describe("\u0418\u043C\u044F \u0433\u0440\u0443\u043F\u043F\u044B \u0442\u043E\u043A\u0435\u043D\u043E\u0432: \u0432\u0435\u0440\u043D\u0443\u0442\u044C \u0432\u0441\u044E \u0433\u0440\u0443\u043F\u043F\u0443 \u0446\u0435\u043B\u0438\u043A\u043E\u043C. \u041D\u0430\u043F\u0440. 'ColorBrand'.")
|
|
230
391
|
},
|
|
231
|
-
async ({ component }) => {
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
],
|
|
244
|
-
isError: true
|
|
245
|
-
};
|
|
246
|
-
}
|
|
247
|
-
return {
|
|
248
|
-
content: [{ type: "text", text: JSON.stringify(comp.tokens, null, 2) }]
|
|
249
|
-
};
|
|
250
|
-
}
|
|
251
|
-
const allTokens = bundle.components.filter((c) => c.tokens.length > 0).map((c) => ({ component: c.name, tokens: c.tokens }));
|
|
252
|
-
return {
|
|
253
|
-
content: [{ type: "text", text: JSON.stringify(allTokens, null, 2) }]
|
|
254
|
-
};
|
|
392
|
+
async ({ component, group }) => {
|
|
393
|
+
const result = buildTokensResponse(bundle, { component, group });
|
|
394
|
+
return result.ok ? { content: [{ type: "text", text: JSON.stringify(result.payload, null, 2) }] } : { content: [{ type: "text", text: result.text }], isError: true };
|
|
395
|
+
}
|
|
396
|
+
);
|
|
397
|
+
server.tool(
|
|
398
|
+
"get_guidelines",
|
|
399
|
+
"\u0413\u0430\u0439\u0434\u043B\u0430\u0439\u043D\u044B \u043A\u043E\u0434\u043E\u0433\u0435\u043D\u0435\u0440\u0430\u0446\u0438\u0438 \u043D\u0430 Triplex \u0434\u043B\u044F \u0418\u0418-\u0430\u0433\u0435\u043D\u0442\u043E\u0432: \u043F\u0440\u0430\u0432\u0438\u043B\u0430 TPX-G-NN \u2014 \u043A\u0430\u043A\u0438\u0435 \u043A\u043E\u043C\u043F\u043E\u043D\u0435\u043D\u0442\u044B \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u044C \u0434\u043B\u044F \u0442\u0435\u043A\u0441\u0442\u043E\u0432, \u0441\u0435\u0442\u043A\u0438, \u043E\u0442\u0441\u0442\u0443\u043F\u043E\u0432, \u0438\u043A\u043E\u043D\u043E\u043A, \u043E\u0431\u0432\u044F\u0437\u043A\u0430 \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u044F. \u041F\u0440\u043E\u0447\u0438\u0442\u0430\u0439 \u043F\u0435\u0440\u0435\u0434 \u0433\u0435\u043D\u0435\u0440\u0430\u0446\u0438\u0435\u0439 \u043A\u043E\u0434\u0430 \u043F\u043E \u043C\u0430\u043A\u0435\u0442\u0443.",
|
|
400
|
+
{},
|
|
401
|
+
async () => {
|
|
402
|
+
const result = buildGuidelinesResponse(bundle);
|
|
403
|
+
return result.ok ? { content: [{ type: "text", text: result.text }] } : { content: [{ type: "text", text: result.text }], isError: true };
|
|
255
404
|
}
|
|
256
405
|
);
|
|
257
406
|
server.tool(
|
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 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":"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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","../src/tools/guidelines.ts","../src/tools/tokens.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\";\nimport { buildGuidelinesResponse } from \"./guidelines.js\";\nimport { buildTokensResponse } from \"./tokens.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 \"Дизайн-токены Triplex: пути `Группа.Токен` для ThemeProvider, значения светлой и тёмной темы, ссылки на палитру. Без аргументов — индекс групп.\",\n {\n component: z\n .string()\n .optional()\n .describe(\"Имя компонента: вернуть токены, которые он использует. Напр. 'Calendar'.\"),\n group: z\n .string()\n .optional()\n .describe(\"Имя группы токенов: вернуть всю группу целиком. Напр. 'ColorBrand'.\"),\n },\n async ({ component, group }) => {\n const result = buildTokensResponse(bundle, { component, group });\n\n return result.ok\n ? { content: [{ type: \"text\", text: JSON.stringify(result.payload, null, 2) }] }\n : { content: [{ type: \"text\", text: result.text }], isError: true };\n },\n );\n\n server.tool(\n \"get_guidelines\",\n \"Гайдлайны кодогенерации на Triplex для ИИ-агентов: правила TPX-G-NN — какие компоненты использовать для текстов, сетки, отступов, иконок, обвязка приложения. Прочитай перед генерацией кода по макету.\",\n {},\n async () => {\n const result = buildGuidelinesResponse(bundle);\n\n return result.ok\n ? { content: [{ type: \"text\", text: result.text }] }\n : { content: [{ type: \"text\", text: result.text }], isError: true };\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 {\n IconsBundle,\n Manifest,\n ParsedBundle,\n RawComponent,\n TokensSection,\n} 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 tokens: null,\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\n/**\n * Читает дерево дизайн-токенов. null — bundle собран до schemaVersion 2\n * (или файл не разложен): tools в этом случае работают без значений токенов.\n */\nfunction loadTokens(manifest: Manifest): TokensSection | null {\n if (!manifest.tokens) {\n return null;\n }\n\n try {\n return JSON.parse(readFileSync(resolve(BUNDLE_DIR, manifest.tokens), \"utf-8\")) as TokensSection;\n } catch {\n console.error(\n `Failed to load tokens from ${manifest.tokens}. Run 'npm run fetch-bundle' first.`,\n );\n return null;\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 tokens: loadTokens(manifest),\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","/**\n * Сборка ответа tool `get_guidelines`.\n *\n * Гайдлайны кодогенерации (`docs/mcp/guidelines.md` в triplex-next, правила\n * `TPX-G-NN`) приезжают через bundle как guide с топиком `guidelines` —\n * начиная с triplex-next 1.45.0. На более старом bundle топика нет: сервер\n * обязан работать и в этом случае, отвечая внятной ошибкой, а не падая.\n */\nimport type { ParsedBundle } from \"../types/index.js\";\n\nexport const GUIDELINES_TOPIC = \"guidelines\";\n\nexport type GuidelinesResult = { ok: true; text: string } | { ok: false; text: string };\n\nexport function buildGuidelinesResponse(bundle: ParsedBundle): GuidelinesResult {\n const guide = bundle.guides.find((g) => g.topic === GUIDELINES_TOPIC);\n\n if (!guide) {\n return {\n ok: false,\n text:\n `Bundle собран из triplex-next ${bundle.triplexVersion} и гайдлайнов не содержит — ` +\n \"они поставляются начиная с 1.45.0. Обновите bundle: npm run fetch-bundle.\",\n };\n }\n\n return { ok: true, text: guide.raw };\n}\n","/**\n * Сборка ответа tool `get_tokens`.\n *\n * Токены Triplex адресуются путём `Группа.Токен` — ровно в этом виде они\n * передаются в `ThemeProvider` через prop `tokens`. CSS-переменные\n * `--triplex-next-*` публичным API не являются: на сборке библиотеки к имени\n * дописывается версия пакета.\n *\n * Дерево токенов приходит в bundle начиная с `schemaVersion: 2`. Для более\n * старых bundle доступны только пути из frontmatter AI.md — ответ в этом случае\n * помечается `note`, а сервер продолжает работать.\n */\nimport type { ParsedBundle, TokenEntry, TokensSection } from \"../types/index.js\";\n\n/** Фильтры tool `get_tokens`. Оба необязательны, `group` имеет приоритет. */\nexport interface TokensQuery {\n component?: string;\n group?: string;\n}\n\nexport type TokensResult = { ok: true; payload: unknown } | { ok: false; text: string };\n\nexport const LEGACY_NOTE =\n \"Bundle собран до schemaVersion 2 и значений токенов не содержит — доступны только пути. Обновите bundle: npm run fetch-bundle.\";\n\n/** Как потребитель переопределяет токен: единственный публичный способ. */\nfunction howToOverride(group: string) {\n return {\n api: \"<ThemeProvider tokens={...}> из @sberbusiness/triplex-next\",\n example: [\n \"const TOKENS = {\",\n ` ${group}: {`,\n ' <Токен>: {value: \"#FFFFFF\"}, // своё значение',\n ' <Другой>: {ref: \"ColorBrand.50\"}, // ссылка на core-токен',\n \" },\",\n \"};\",\n \"\",\n \"<ThemeProvider tokens={TOKENS} scopeRef={scopeRef}>…</ThemeProvider>\",\n ].join(\"\\n\"),\n notes: [\n \"Объект tokens плоский: группы лежат на верхнем уровне, вложенности core/components нет.\",\n \"Одним объектом можно переопределить несколько групп сразу — и core, и компонентные.\",\n \"ref указывает только на core-токены (refable: true).\",\n \"tokens сравнивается по ссылке — выносите объект из рендера.\",\n \"Переопределение действует внутри элемента из scopeRef.\",\n ],\n };\n}\n\n/** Внутренний слой: css-переменные с версией пакета в имени. */\nfunction internalNote(section: TokensSection) {\n return {\n cssVarPattern: section.internal.cssVarPattern,\n note: \"Внутренняя реализация: в собранном пакете к имени переменной добавляется версия, поэтому в коде потребителя использовать её нельзя.\",\n };\n}\n\n/** Core-токены, на которые ссылаются переданные токены. */\nfunction coreTokensUsed(tokens: TokenEntry[]): string[] {\n const refs = tokens.flatMap((token) =>\n [token.light.ref, token.dark.ref].filter((ref): ref is string => ref !== undefined),\n );\n\n return [...new Set(refs)].sort();\n}\n\n/** Индекс групп: имя → число токенов. Полное дерево слишком велико для одного ответа. */\nfunction groupIndex(section: TokensSection, kind: \"core\" | \"component\"): Record<string, number> {\n return Object.fromEntries(\n Object.entries(section.groups)\n .filter(([, group]) => group.kind === kind)\n .map(([name, group]) => [name, Object.keys(group.tokens).length]),\n );\n}\n\nfunction byGroup(section: TokensSection, group: string): TokensResult {\n const name = Object.keys(section.groups).find((key) => key.toLowerCase() === group.toLowerCase());\n\n if (name === undefined) {\n return {\n ok: false,\n text: `Группа токенов \"${group}\" не найдена. Список групп: get_tokens() без аргументов.`,\n };\n }\n\n const entry = section.groups[name];\n\n return {\n ok: true,\n payload: {\n group: name,\n kind: entry.kind,\n refable: entry.refable,\n tokenCount: Object.keys(entry.tokens).length,\n howToOverride: howToOverride(name),\n tokens: Object.values(entry.tokens),\n internal: internalNote(section),\n },\n };\n}\n\nfunction byComponent(\n bundle: ParsedBundle,\n section: TokensSection | null,\n component: string,\n): TokensResult {\n const found = bundle.components.find((c) => c.name.toLowerCase() === component.toLowerCase());\n\n if (!found) {\n return {\n ok: false,\n text: `Компонент \"${component}\" не найден. Используйте list_components для списка доступных компонентов.`,\n };\n }\n\n if (section === null) {\n return {\n ok: true,\n payload: { component: found.name, tokens: found.tokens, note: LEGACY_NOTE },\n };\n }\n\n // Компонент может использовать токены нескольких групп: например, поле выбора\n // красится токенами FormField, Dropdown и DropdownList сразу.\n const resolved = found.tokens.map((path) => {\n const [group, token] = path.split(\".\");\n\n return { path, entry: section.groups[group]?.tokens[token] };\n });\n const known = resolved\n .map(({ entry }) => entry)\n .filter((entry): entry is TokenEntry => entry !== undefined);\n const unknown = resolved.filter(({ entry }) => entry === undefined).map(({ path }) => path);\n const groups = [...new Set(known.map((token) => token.path.split(\".\")[0]))];\n\n return {\n ok: true,\n payload: {\n component: found.name,\n groups,\n tokenCount: known.length,\n howToOverride: howToOverride(groups[0] ?? \"Группа\"),\n tokens: known,\n // Палитра, на которую ссылаются токены компонента: перекрасив core-токен,\n // потребитель меняет вид всех компонентов, которые на него ссылаются.\n coreTokensUsed: coreTokensUsed(known),\n ...(unknown.length ? { unknownTokens: unknown } : {}),\n internal: internalNote(section),\n },\n };\n}\n\n/** Собирает ответ `get_tokens` по фильтрам. Без фильтров возвращает индекс групп. */\nexport function buildTokensResponse(bundle: ParsedBundle, query: TokensQuery): TokensResult {\n const section = bundle.tokens;\n\n if (query.group !== undefined) {\n return section === null ? { ok: false, text: LEGACY_NOTE } : byGroup(section, query.group);\n }\n\n if (query.component !== undefined) {\n return byComponent(bundle, section, query.component);\n }\n\n if (section === null) {\n return {\n ok: true,\n payload: {\n note: LEGACY_NOTE,\n components: bundle.components\n .filter((c) => c.tokens.length > 0)\n .map((c) => ({ component: c.name, tokens: c.tokens })),\n },\n };\n }\n\n return {\n ok: true,\n payload: {\n triplexVersion: bundle.triplexVersion,\n overridePath: section.overridePath,\n core: {\n description: 'Палитра и примитивы. Ссылки { ref: \"ColorBrand.50\" } резолвятся сюда.',\n groups: groupIndex(section, \"core\"),\n },\n components: { groups: groupIndex(section, \"component\") },\n hint: 'Полные данные: get_tokens({ component: \"Calendar\" }) или get_tokens({ group: \"ColorBrand\" }).',\n },\n };\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sberbusiness/triplex-next-mcp-server",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.45.0-beta",
|
|
4
4
|
"description": "MCP-сервер для дизайн-системы Triplex. Предоставляет AI-агентам документацию компонентов, дизайн-токены и примеры использования.",
|
|
5
5
|
"author": "СберБизнес",
|
|
6
6
|
"license": "MIT",
|