@aleph-alpha/lib-mcp 2.2.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -3222,8 +3222,8 @@ var require_utils = __commonJS({
3222
3222
  }
3223
3223
  return ind;
3224
3224
  }
3225
- function removeDotSegments(path12) {
3226
- let input = path12;
3225
+ function removeDotSegments(path13) {
3226
+ let input = path13;
3227
3227
  const output = [];
3228
3228
  let nextSlash = -1;
3229
3229
  let len = 0;
@@ -3422,8 +3422,8 @@ var require_schemes = __commonJS({
3422
3422
  wsComponent.secure = void 0;
3423
3423
  }
3424
3424
  if (wsComponent.resourceName) {
3425
- const [path12, query] = wsComponent.resourceName.split("?");
3426
- wsComponent.path = path12 && path12 !== "/" ? path12 : void 0;
3425
+ const [path13, query] = wsComponent.resourceName.split("?");
3426
+ wsComponent.path = path13 && path13 !== "/" ? path13 : void 0;
3427
3427
  wsComponent.query = query;
3428
3428
  wsComponent.resourceName = void 0;
3429
3429
  }
@@ -7429,8 +7429,8 @@ function getErrorMap() {
7429
7429
 
7430
7430
  // ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/parseUtil.js
7431
7431
  var makeIssue = (params) => {
7432
- const { data, path: path12, errorMaps, issueData } = params;
7433
- const fullPath = [...path12, ...issueData.path || []];
7432
+ const { data, path: path13, errorMaps, issueData } = params;
7433
+ const fullPath = [...path13, ...issueData.path || []];
7434
7434
  const fullIssue = {
7435
7435
  ...issueData,
7436
7436
  path: fullPath
@@ -7546,11 +7546,11 @@ var errorUtil;
7546
7546
 
7547
7547
  // ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/types.js
7548
7548
  var ParseInputLazyPath = class {
7549
- constructor(parent, value, path12, key) {
7549
+ constructor(parent, value, path13, key) {
7550
7550
  this._cachedPath = [];
7551
7551
  this.parent = parent;
7552
7552
  this.data = value;
7553
- this._path = path12;
7553
+ this._path = path13;
7554
7554
  this._key = key;
7555
7555
  }
7556
7556
  get path() {
@@ -11188,10 +11188,10 @@ function assignProp(target, prop, value) {
11188
11188
  configurable: true
11189
11189
  });
11190
11190
  }
11191
- function getElementAtPath(obj, path12) {
11192
- if (!path12)
11191
+ function getElementAtPath(obj, path13) {
11192
+ if (!path13)
11193
11193
  return obj;
11194
- return path12.reduce((acc, key) => acc?.[key], obj);
11194
+ return path13.reduce((acc, key) => acc?.[key], obj);
11195
11195
  }
11196
11196
  function promiseAllObject(promisesObj) {
11197
11197
  const keys = Object.keys(promisesObj);
@@ -11511,11 +11511,11 @@ function aborted(x, startIndex = 0) {
11511
11511
  }
11512
11512
  return false;
11513
11513
  }
11514
- function prefixIssues(path12, issues) {
11514
+ function prefixIssues(path13, issues) {
11515
11515
  return issues.map((iss) => {
11516
11516
  var _a;
11517
11517
  (_a = iss).path ?? (_a.path = []);
11518
- iss.path.unshift(path12);
11518
+ iss.path.unshift(path13);
11519
11519
  return iss;
11520
11520
  });
11521
11521
  }
@@ -21143,10 +21143,267 @@ var StdioServerTransport = class {
21143
21143
 
21144
21144
  // src/tools/list-components.ts
21145
21145
  import * as fs5 from "node:fs";
21146
- import * as path5 from "node:path";
21146
+ import * as path6 from "node:path";
21147
21147
 
21148
- // src/readers/types-reader.ts
21148
+ // src/readers/stories-reader.ts
21149
21149
  import * as path2 from "node:path";
21150
+ function extractStoryJSDoc(content, storyName) {
21151
+ const exportRegex = new RegExp(`export\\s+const\\s+${storyName}\\s*:`);
21152
+ const exportMatch = content.match(exportRegex);
21153
+ if (!exportMatch || exportMatch.index === void 0) return "";
21154
+ const beforeExport = content.substring(0, exportMatch.index);
21155
+ const lastJsDocEnd = beforeExport.lastIndexOf("*/");
21156
+ if (lastJsDocEnd === -1) return "";
21157
+ const between = beforeExport.substring(lastJsDocEnd + 2);
21158
+ if (between.trim() !== "") return "";
21159
+ const lastJsDocStart = beforeExport.lastIndexOf("/**");
21160
+ if (lastJsDocStart === -1 || lastJsDocStart > lastJsDocEnd) return "";
21161
+ const jsdoc = beforeExport.substring(lastJsDocStart + 3, lastJsDocEnd);
21162
+ return jsdoc.split("\n").map((line) => line.replace(/^\s*\*\s?/, "").trim()).filter((line) => line && !line.startsWith("@")).join(" ").trim();
21163
+ }
21164
+ function extractTemplateSource(content) {
21165
+ const templates = /* @__PURE__ */ new Map();
21166
+ const templateRegex = /const\s+(\w+TemplateSource)\s*=\s*`([\s\S]*?)`;/g;
21167
+ let match;
21168
+ while ((match = templateRegex.exec(content)) !== null) {
21169
+ const varName = match[1];
21170
+ const code = match[2].trim();
21171
+ templates.set(varName, code);
21172
+ }
21173
+ return templates;
21174
+ }
21175
+ function extractStories(content) {
21176
+ const stories = /* @__PURE__ */ new Map();
21177
+ const storyExportRegex = /export\s+const\s+(\w+):\s*Story\s*=/g;
21178
+ let match;
21179
+ while ((match = storyExportRegex.exec(content)) !== null) {
21180
+ const storyName = match[1];
21181
+ if (storyName === "default") continue;
21182
+ const storyStart = match.index;
21183
+ const remainingContent = content.substring(storyStart);
21184
+ const templateRefMatch = remainingContent.match(
21185
+ /code:\s*(\w+TemplateSource)/
21186
+ );
21187
+ if (templateRefMatch) {
21188
+ stories.set(storyName, templateRefMatch[1]);
21189
+ }
21190
+ }
21191
+ return stories;
21192
+ }
21193
+ function extractInlineRenderTemplates(content) {
21194
+ const examples = [];
21195
+ const storyExportRegex = /export\s+const\s+(\w+):\s*Story\s*=/g;
21196
+ let match;
21197
+ while ((match = storyExportRegex.exec(content)) !== null) {
21198
+ const storyName = match[1];
21199
+ if (storyName === "default") continue;
21200
+ const afterEquals = content.indexOf("{", match.index + match[0].length);
21201
+ if (afterEquals === -1) continue;
21202
+ const closingBrace = findMatchingBrace(content, afterEquals);
21203
+ if (closingBrace === -1) continue;
21204
+ const storyBlock = content.slice(afterEquals, closingBrace + 1);
21205
+ if (!storyBlock.includes("template:")) continue;
21206
+ if (/sourceState:\s*['"]none['"]/.test(storyBlock)) continue;
21207
+ const templateMatch = storyBlock.match(/template:\s*`([\s\S]*?)`/);
21208
+ if (!templateMatch) continue;
21209
+ const template = templateMatch[1].trim();
21210
+ if (!template) continue;
21211
+ const componentsMatch = storyBlock.match(/components:\s*\{([^}]+)\}/);
21212
+ const componentNames = componentsMatch ? componentsMatch[1].split(",").map((c) => c.trim()).filter(Boolean) : [];
21213
+ const imports = componentNames.length > 0 ? `<script setup>
21214
+ // Components: ${componentNames.join(", ")}
21215
+ </script>
21216
+
21217
+ ` : "";
21218
+ examples.push({
21219
+ name: storyName,
21220
+ description: "",
21221
+ code: `${imports}<template>
21222
+ ${template}
21223
+ </template>`
21224
+ });
21225
+ }
21226
+ return examples;
21227
+ }
21228
+ function extractArgTypes(content) {
21229
+ const argTypes = [];
21230
+ const argTypesKeyIndex = content.indexOf("argTypes");
21231
+ if (argTypesKeyIndex === -1) {
21232
+ return argTypes;
21233
+ }
21234
+ const colonIndex = content.indexOf(":", argTypesKeyIndex);
21235
+ if (colonIndex === -1) {
21236
+ return argTypes;
21237
+ }
21238
+ const openingBraceIndex = content.indexOf("{", colonIndex);
21239
+ if (openingBraceIndex === -1) {
21240
+ return argTypes;
21241
+ }
21242
+ const closingBraceIndex = findMatchingBrace(content, openingBraceIndex);
21243
+ if (closingBraceIndex === -1) {
21244
+ return argTypes;
21245
+ }
21246
+ const argTypesBlock = content.slice(openingBraceIndex + 1, closingBraceIndex);
21247
+ let index = 0;
21248
+ while (index < argTypesBlock.length) {
21249
+ const propNameMatch = argTypesBlock.slice(index).match(/^\s*(\w+)\s*:\s*\{/);
21250
+ if (!propNameMatch) {
21251
+ const nextComma = argTypesBlock.indexOf(",", index);
21252
+ if (nextComma === -1) break;
21253
+ index = nextComma + 1;
21254
+ continue;
21255
+ }
21256
+ const propName = propNameMatch[1];
21257
+ const propStartIndex = index + propNameMatch[0].length - 1;
21258
+ const propEndIndex = findMatchingBrace(argTypesBlock, propStartIndex);
21259
+ if (propEndIndex === -1) break;
21260
+ const propBlock = argTypesBlock.slice(propStartIndex + 1, propEndIndex);
21261
+ const descMatch = propBlock.match(/description:\s*['"](.+?)['"]\s*[,}]/s);
21262
+ const description = descMatch ? descMatch[1].replace(/\\(['"])/g, "$1") : "";
21263
+ const controlMatch = propBlock.match(/control:\s*['"]?(\w+)['"]?/);
21264
+ const control = controlMatch ? controlMatch[1] : void 0;
21265
+ const optionsMatch = propBlock.match(/options:\s*\[([\s\S]*?)\]/);
21266
+ let options;
21267
+ if (optionsMatch) {
21268
+ options = optionsMatch[1].split(",").map((opt) => opt.trim().replace(/['"]/g, "")).filter(Boolean);
21269
+ }
21270
+ argTypes.push({
21271
+ name: propName,
21272
+ description,
21273
+ control,
21274
+ options
21275
+ });
21276
+ index = propEndIndex + 1;
21277
+ }
21278
+ return argTypes;
21279
+ }
21280
+ function extractTitle(content) {
21281
+ const titleMatch = content.match(/title:\s*['"]([^'"]+)['"]/);
21282
+ return titleMatch ? titleMatch[1] : "";
21283
+ }
21284
+ function extractLabels(content) {
21285
+ const tagsKeyIndex = content.indexOf("tags:");
21286
+ if (tagsKeyIndex === -1) return [];
21287
+ const openingBracketIndex = content.indexOf("[", tagsKeyIndex);
21288
+ if (openingBracketIndex === -1) return [];
21289
+ const closingBracketIndex = content.indexOf("]", openingBracketIndex);
21290
+ if (closingBracketIndex === -1) return [];
21291
+ const tagsBlock = content.slice(openingBracketIndex + 1, closingBracketIndex);
21292
+ const labels = /* @__PURE__ */ new Set();
21293
+ const tagRegex = /['"`]([^'"`]+)['"`]/g;
21294
+ let match;
21295
+ while ((match = tagRegex.exec(tagsBlock)) !== null) {
21296
+ const label = match[1].trim();
21297
+ if (label) labels.add(label);
21298
+ }
21299
+ return Array.from(labels);
21300
+ }
21301
+ function extractMetaArgs(content) {
21302
+ const metaDefaultIndex = content.indexOf("export default");
21303
+ if (metaDefaultIndex === -1) return void 0;
21304
+ const metaSection = content.slice(0, metaDefaultIndex);
21305
+ const argsKeyIndex = metaSection.lastIndexOf("args:");
21306
+ if (argsKeyIndex !== -1) {
21307
+ return extractArgsFromPosition(content, argsKeyIndex);
21308
+ }
21309
+ const afterExport = content.slice(metaDefaultIndex + "export default".length);
21310
+ const trimmed = afterExport.trimStart();
21311
+ if (!trimmed.startsWith("{")) return void 0;
21312
+ const blockStart = content.indexOf("{", metaDefaultIndex);
21313
+ const blockEnd = findMatchingBrace(content, blockStart);
21314
+ if (blockEnd === -1) return void 0;
21315
+ const metaBlock = content.slice(blockStart + 1, blockEnd);
21316
+ const inlineArgsIndex = metaBlock.indexOf("args:");
21317
+ if (inlineArgsIndex === -1) return void 0;
21318
+ return extractArgsFromPosition(content, blockStart + 1 + inlineArgsIndex);
21319
+ }
21320
+ function extractArgsFromPosition(content, argsKeyIndex) {
21321
+ const colonIndex = content.indexOf(":", argsKeyIndex + 4);
21322
+ if (colonIndex === -1) {
21323
+ return void 0;
21324
+ }
21325
+ const openingBraceIndex = content.indexOf("{", colonIndex);
21326
+ if (openingBraceIndex === -1) {
21327
+ return void 0;
21328
+ }
21329
+ const closingBraceIndex = findMatchingBrace(content, openingBraceIndex);
21330
+ if (closingBraceIndex === -1) {
21331
+ return void 0;
21332
+ }
21333
+ const argsBlock = content.slice(openingBraceIndex + 1, closingBraceIndex);
21334
+ const args = {};
21335
+ const kvRegex = /(\w+)\s*:\s*(?:'([^']*)'|"([^"]*)"|(\d+(?:\.\d+)?)|(\btrue\b|\bfalse\b))/g;
21336
+ let match;
21337
+ while ((match = kvRegex.exec(argsBlock)) !== null) {
21338
+ const key = match[1];
21339
+ if (match[2] !== void 0) {
21340
+ args[key] = match[2];
21341
+ } else if (match[3] !== void 0) {
21342
+ args[key] = match[3];
21343
+ } else if (match[4] !== void 0) {
21344
+ args[key] = Number(match[4]);
21345
+ } else if (match[5] !== void 0) {
21346
+ args[key] = match[5] === "true";
21347
+ }
21348
+ }
21349
+ return Object.keys(args).length > 0 ? args : void 0;
21350
+ }
21351
+ function readStoriesFile(filePath) {
21352
+ const content = readTextFile(filePath);
21353
+ if (!content) {
21354
+ return null;
21355
+ }
21356
+ const title = extractTitle(content);
21357
+ const labels = extractLabels(content);
21358
+ const argTypes = extractArgTypes(content);
21359
+ const templateSources = extractTemplateSource(content);
21360
+ const storyTemplateMap = extractStories(content);
21361
+ const examples = [];
21362
+ const usageGuidance = [];
21363
+ const coveredStories = /* @__PURE__ */ new Set();
21364
+ for (const [storyName, templateVar] of storyTemplateMap) {
21365
+ const code = templateSources.get(templateVar);
21366
+ const description = extractStoryJSDoc(content, storyName);
21367
+ if (code) {
21368
+ examples.push({
21369
+ name: storyName,
21370
+ description,
21371
+ code
21372
+ });
21373
+ coveredStories.add(storyName);
21374
+ }
21375
+ if (description) {
21376
+ usageGuidance.push(description);
21377
+ }
21378
+ }
21379
+ const inlineExamples = extractInlineRenderTemplates(content);
21380
+ for (const example of inlineExamples) {
21381
+ if (!coveredStories.has(example.name)) {
21382
+ const description = extractStoryJSDoc(content, example.name);
21383
+ examples.push({ ...example, description });
21384
+ if (description) {
21385
+ usageGuidance.push(description);
21386
+ }
21387
+ }
21388
+ }
21389
+ const defaultArgs = extractMetaArgs(content);
21390
+ return {
21391
+ title,
21392
+ labels,
21393
+ examples,
21394
+ argTypes,
21395
+ usageGuidance,
21396
+ defaultArgs
21397
+ };
21398
+ }
21399
+ function readComponentStories(componentDir) {
21400
+ const componentName = path2.basename(componentDir);
21401
+ const storiesPath = path2.join(componentDir, `${componentName}.stories.ts`);
21402
+ return readStoriesFile(storiesPath);
21403
+ }
21404
+
21405
+ // src/readers/types-reader.ts
21406
+ import * as path3 from "node:path";
21150
21407
  var TYPE_OR_INTERFACE = "(?:interface|type)";
21151
21408
  function parseJSDoc(comment) {
21152
21409
  const lines = comment.replace(/\/\*\*|\*\/|\*/g, "").split("\n").map((line) => line.trim()).filter(Boolean);
@@ -21280,7 +21537,7 @@ function readTypesFile(filePath, componentName) {
21280
21537
  if (!content) {
21281
21538
  return null;
21282
21539
  }
21283
- const resolvedName = componentName || path2.basename(path2.dirname(filePath));
21540
+ const resolvedName = componentName || path3.basename(path3.dirname(filePath));
21284
21541
  const exactRegex = new RegExp(
21285
21542
  `export\\s+${TYPE_OR_INTERFACE}\\s+(${resolvedName}Props)\\b`
21286
21543
  );
@@ -21313,28 +21570,28 @@ function readTypesFile(filePath, componentName) {
21313
21570
  };
21314
21571
  }
21315
21572
  function readComponentTypes(componentDir) {
21316
- const typesPath = path2.join(componentDir, "types.ts");
21317
- return readTypesFile(typesPath, path2.basename(componentDir));
21573
+ const typesPath = path3.join(componentDir, "types.ts");
21574
+ return readTypesFile(typesPath, path3.basename(componentDir));
21318
21575
  }
21319
21576
 
21320
21577
  // src/constants.ts
21321
21578
  import * as fs4 from "node:fs";
21322
- import * as path4 from "node:path";
21579
+ import * as path5 from "node:path";
21323
21580
 
21324
21581
  // src/utils/paths.ts
21325
21582
  import * as fs3 from "node:fs";
21326
- import * as path3 from "node:path";
21583
+ import * as path4 from "node:path";
21327
21584
  import { fileURLToPath as fileURLToPath2 } from "node:url";
21328
21585
  var __filename2 = fileURLToPath2(import.meta.url);
21329
- var __dirname2 = path3.dirname(__filename2);
21586
+ var __dirname2 = path4.dirname(__filename2);
21330
21587
  function findInMonorepo(startDir, packageName) {
21331
21588
  let current = startDir;
21332
21589
  for (let i = 0; i < 10; i++) {
21333
- const candidate = path3.join(current, "packages", packageName);
21334
- if (fs3.existsSync(path3.join(candidate, "package.json"))) {
21590
+ const candidate = path4.join(current, "packages", packageName);
21591
+ if (fs3.existsSync(path4.join(candidate, "package.json"))) {
21335
21592
  return candidate;
21336
21593
  }
21337
- const parent = path3.dirname(current);
21594
+ const parent = path4.dirname(current);
21338
21595
  if (parent === current) break;
21339
21596
  current = parent;
21340
21597
  }
@@ -21346,12 +21603,12 @@ function resolveWorkspacePackage(packageName, scope = "@aleph-alpha") {
21346
21603
  const fromCwd = findInMonorepo(process.cwd(), packageName);
21347
21604
  if (fromCwd) return fromCwd;
21348
21605
  const nodeModulesCandidates = [
21349
- path3.resolve(__dirname2, `../../${scope}/${packageName}`),
21350
- path3.resolve(__dirname2, `../../../${scope}/${packageName}`),
21351
- path3.join(process.cwd(), `node_modules/${scope}/${packageName}`)
21606
+ path4.resolve(__dirname2, `../../${scope}/${packageName}`),
21607
+ path4.resolve(__dirname2, `../../../${scope}/${packageName}`),
21608
+ path4.join(process.cwd(), `node_modules/${scope}/${packageName}`)
21352
21609
  ];
21353
21610
  for (const pkgPath of nodeModulesCandidates) {
21354
- if (fs3.existsSync(path3.join(pkgPath, "package.json"))) {
21611
+ if (fs3.existsSync(path4.join(pkgPath, "package.json"))) {
21355
21612
  return pkgPath;
21356
21613
  }
21357
21614
  }
@@ -21367,7 +21624,7 @@ function getLibraryRootPath() {
21367
21624
  }
21368
21625
  function getLibrarySourcePath() {
21369
21626
  const uiLibraryRoot = findUiLibraryRoot();
21370
- const srcPath = path3.join(uiLibraryRoot, "src");
21627
+ const srcPath = path4.join(uiLibraryRoot, "src");
21371
21628
  if (fs3.existsSync(srcPath)) {
21372
21629
  return srcPath;
21373
21630
  }
@@ -21382,7 +21639,7 @@ function findChatKitRoot() {
21382
21639
  }
21383
21640
  function getChatKitSourcePath() {
21384
21641
  const chatKitRoot = findChatKitRoot();
21385
- const srcPath = path3.join(chatKitRoot, "src");
21642
+ const srcPath = path4.join(chatKitRoot, "src");
21386
21643
  if (fs3.existsSync(srcPath)) {
21387
21644
  return srcPath;
21388
21645
  }
@@ -21393,20 +21650,20 @@ function getChatKitSourcePath() {
21393
21650
  function getMcpDirPath() {
21394
21651
  const possiblePaths = [
21395
21652
  // Bundled: from dist/utils -> package root
21396
- path3.resolve(__dirname2, "../.."),
21653
+ path4.resolve(__dirname2, "../.."),
21397
21654
  // Fallback: current directory
21398
21655
  __dirname2
21399
21656
  ];
21400
21657
  for (const mcpPath of possiblePaths) {
21401
- if (fs3.existsSync(path3.join(mcpPath, "components-meta.json"))) {
21658
+ if (fs3.existsSync(path4.join(mcpPath, "components-meta.json"))) {
21402
21659
  return mcpPath;
21403
21660
  }
21404
21661
  }
21405
- return path3.resolve(__dirname2, "../..");
21662
+ return path4.resolve(__dirname2, "../..");
21406
21663
  }
21407
21664
  function getPackageRoot() {
21408
- const pkgRoot = path3.resolve(__dirname2, "../..");
21409
- if (fs3.existsSync(path3.join(pkgRoot, "package.json"))) {
21665
+ const pkgRoot = path4.resolve(__dirname2, "../..");
21666
+ if (fs3.existsSync(path4.join(pkgRoot, "package.json"))) {
21410
21667
  return pkgRoot;
21411
21668
  }
21412
21669
  return process.cwd();
@@ -21429,7 +21686,7 @@ function detectCategoryDirs() {
21429
21686
  (entry) => !entry.name.startsWith(".") && entry.name !== "node_modules"
21430
21687
  ).filter((entry) => {
21431
21688
  try {
21432
- const dirPath = path4.join(srcPath, entry.name);
21689
+ const dirPath = path5.join(srcPath, entry.name);
21433
21690
  const subEntries = fs4.readdirSync(dirPath, { withFileTypes: true });
21434
21691
  return subEntries.some(
21435
21692
  (sub) => sub.isDirectory() && sub.name.startsWith(COMPONENT_PREFIX)
@@ -21471,8 +21728,8 @@ function detectChatKitCategoryDirs() {
21471
21728
  if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
21472
21729
  if (entry.name.startsWith(CHAT_KIT_PREFIX)) continue;
21473
21730
  walk(
21474
- path4.join(dir, entry.name),
21475
- relative ? path4.join(relative, entry.name) : entry.name,
21731
+ path5.join(dir, entry.name),
21732
+ relative ? path5.join(relative, entry.name) : entry.name,
21476
21733
  depth + 1
21477
21734
  );
21478
21735
  }
@@ -21504,7 +21761,7 @@ var cachedMeta = null;
21504
21761
  function loadComponentsMeta() {
21505
21762
  if (cachedMeta) return cachedMeta;
21506
21763
  const mcpDir = getMcpDirPath();
21507
- const metaPath = path4.join(mcpDir, "components-meta.json");
21764
+ const metaPath = path5.join(mcpDir, "components-meta.json");
21508
21765
  cachedMeta = readJsonFile(metaPath) ?? {};
21509
21766
  return cachedMeta;
21510
21767
  }
@@ -21512,13 +21769,13 @@ var cachedChatKitMeta = null;
21512
21769
  function loadChatKitComponentsMeta() {
21513
21770
  if (cachedChatKitMeta) return cachedChatKitMeta;
21514
21771
  const mcpDir = getMcpDirPath();
21515
- const metaPath = path4.join(mcpDir, "chat-kit-components-meta.json");
21772
+ const metaPath = path5.join(mcpDir, "chat-kit-components-meta.json");
21516
21773
  cachedChatKitMeta = readJsonFile(metaPath) ?? {};
21517
21774
  return cachedChatKitMeta;
21518
21775
  }
21519
21776
  function getPackageVersion() {
21520
21777
  const pkgRoot = getPackageRoot();
21521
- const pkgPath = path4.join(pkgRoot, "package.json");
21778
+ const pkgPath = path5.join(pkgRoot, "package.json");
21522
21779
  const pkg = readJsonFile(pkgPath);
21523
21780
  return pkg?.version ?? "0.0.0";
21524
21781
  }
@@ -21554,7 +21811,7 @@ function scanCategoryDirectory(categoryDir) {
21554
21811
  return entries.filter((entry) => entry.isDirectory()).filter((entry) => isComponentDirectory(entry.name)).filter((entry) => !INTERNAL_DIRS.includes(entry.name)).map((entry) => {
21555
21812
  const componentName = entry.name;
21556
21813
  const componentMeta = meta[componentName];
21557
- const componentDir = path5.join(categoryDir, componentName);
21814
+ const componentDir = path6.join(categoryDir, componentName);
21558
21815
  return {
21559
21816
  name: componentName,
21560
21817
  category: componentMeta?.category ?? "Uncategorized",
@@ -21562,18 +21819,19 @@ function scanCategoryDirectory(categoryDir) {
21562
21819
  componentName,
21563
21820
  componentMeta,
21564
21821
  componentDir
21565
- )
21822
+ ),
21823
+ labels: readComponentStories(componentDir)?.labels || []
21566
21824
  };
21567
21825
  });
21568
21826
  }
21569
21827
  function matchesFilter(component, filter) {
21570
21828
  const filterLower = filter.toLowerCase();
21571
- return component.name.toLowerCase().includes(filterLower) || component.category.toLowerCase().includes(filterLower) || component.description.toLowerCase().includes(filterLower);
21829
+ return component.name.toLowerCase().includes(filterLower) || component.category.toLowerCase().includes(filterLower) || component.description.toLowerCase().includes(filterLower) || component.labels.some((label) => label.toLowerCase().includes(filterLower));
21572
21830
  }
21573
21831
  function listComponents(filter) {
21574
21832
  const srcPath = getLibrarySourcePath();
21575
21833
  const allComponents = getCategoryDirs().flatMap((category) => {
21576
- const categoryPath = path5.join(srcPath, category);
21834
+ const categoryPath = path6.join(srcPath, category);
21577
21835
  return scanCategoryDirectory(categoryPath);
21578
21836
  });
21579
21837
  allComponents.sort((a, b) => a.name.localeCompare(b.name));
@@ -21581,250 +21839,21 @@ function listComponents(filter) {
21581
21839
  }
21582
21840
 
21583
21841
  // src/tools/get-docs.ts
21584
- import * as path7 from "node:path";
21585
-
21586
- // src/readers/stories-reader.ts
21587
- import * as path6 from "node:path";
21588
- function extractStoryJSDoc(content, storyName) {
21589
- const exportRegex = new RegExp(`export\\s+const\\s+${storyName}\\s*:`);
21590
- const exportMatch = content.match(exportRegex);
21591
- if (!exportMatch || exportMatch.index === void 0) return "";
21592
- const beforeExport = content.substring(0, exportMatch.index);
21593
- const lastJsDocEnd = beforeExport.lastIndexOf("*/");
21594
- if (lastJsDocEnd === -1) return "";
21595
- const between = beforeExport.substring(lastJsDocEnd + 2);
21596
- if (between.trim() !== "") return "";
21597
- const lastJsDocStart = beforeExport.lastIndexOf("/**");
21598
- if (lastJsDocStart === -1 || lastJsDocStart > lastJsDocEnd) return "";
21599
- const jsdoc = beforeExport.substring(lastJsDocStart + 3, lastJsDocEnd);
21600
- return jsdoc.split("\n").map((line) => line.replace(/^\s*\*\s?/, "").trim()).filter((line) => line && !line.startsWith("@")).join(" ").trim();
21601
- }
21602
- function extractTemplateSource(content) {
21603
- const templates = /* @__PURE__ */ new Map();
21604
- const templateRegex = /const\s+(\w+TemplateSource)\s*=\s*`([\s\S]*?)`;/g;
21605
- let match;
21606
- while ((match = templateRegex.exec(content)) !== null) {
21607
- const varName = match[1];
21608
- const code = match[2].trim();
21609
- templates.set(varName, code);
21610
- }
21611
- return templates;
21612
- }
21613
- function extractStories(content) {
21614
- const stories = /* @__PURE__ */ new Map();
21615
- const storyExportRegex = /export\s+const\s+(\w+):\s*Story\s*=/g;
21616
- let match;
21617
- while ((match = storyExportRegex.exec(content)) !== null) {
21618
- const storyName = match[1];
21619
- if (storyName === "default") continue;
21620
- const storyStart = match.index;
21621
- const remainingContent = content.substring(storyStart);
21622
- const templateRefMatch = remainingContent.match(
21623
- /code:\s*(\w+TemplateSource)/
21624
- );
21625
- if (templateRefMatch) {
21626
- stories.set(storyName, templateRefMatch[1]);
21627
- }
21628
- }
21629
- return stories;
21630
- }
21631
- function extractInlineRenderTemplates(content) {
21632
- const examples = [];
21633
- const storyExportRegex = /export\s+const\s+(\w+):\s*Story\s*=/g;
21634
- let match;
21635
- while ((match = storyExportRegex.exec(content)) !== null) {
21636
- const storyName = match[1];
21637
- if (storyName === "default") continue;
21638
- const afterEquals = content.indexOf("{", match.index + match[0].length);
21639
- if (afterEquals === -1) continue;
21640
- const closingBrace = findMatchingBrace(content, afterEquals);
21641
- if (closingBrace === -1) continue;
21642
- const storyBlock = content.slice(afterEquals, closingBrace + 1);
21643
- if (!storyBlock.includes("template:")) continue;
21644
- const templateMatch = storyBlock.match(/template:\s*`([\s\S]*?)`/);
21645
- if (!templateMatch) continue;
21646
- const template = templateMatch[1].trim();
21647
- if (!template) continue;
21648
- const componentsMatch = storyBlock.match(/components:\s*\{([^}]+)\}/);
21649
- const componentNames = componentsMatch ? componentsMatch[1].split(",").map((c) => c.trim()).filter(Boolean) : [];
21650
- const imports = componentNames.length > 0 ? `<script setup>
21651
- // Components: ${componentNames.join(", ")}
21652
- </script>
21842
+ import * as path8 from "node:path";
21653
21843
 
21654
- ` : "";
21655
- examples.push({
21656
- name: storyName,
21657
- description: "",
21658
- code: `${imports}<template>
21659
- ${template}
21660
- </template>`
21661
- });
21662
- }
21663
- return examples;
21664
- }
21665
- function extractArgTypes(content) {
21666
- const argTypes = [];
21667
- const argTypesKeyIndex = content.indexOf("argTypes");
21668
- if (argTypesKeyIndex === -1) {
21669
- return argTypes;
21670
- }
21671
- const colonIndex = content.indexOf(":", argTypesKeyIndex);
21672
- if (colonIndex === -1) {
21673
- return argTypes;
21674
- }
21675
- const openingBraceIndex = content.indexOf("{", colonIndex);
21676
- if (openingBraceIndex === -1) {
21677
- return argTypes;
21678
- }
21679
- const closingBraceIndex = findMatchingBrace(content, openingBraceIndex);
21680
- if (closingBraceIndex === -1) {
21681
- return argTypes;
21682
- }
21683
- const argTypesBlock = content.slice(openingBraceIndex + 1, closingBraceIndex);
21684
- let index = 0;
21685
- while (index < argTypesBlock.length) {
21686
- const propNameMatch = argTypesBlock.slice(index).match(/^\s*(\w+)\s*:\s*\{/);
21687
- if (!propNameMatch) {
21688
- const nextComma = argTypesBlock.indexOf(",", index);
21689
- if (nextComma === -1) break;
21690
- index = nextComma + 1;
21691
- continue;
21692
- }
21693
- const propName = propNameMatch[1];
21694
- const propStartIndex = index + propNameMatch[0].length - 1;
21695
- const propEndIndex = findMatchingBrace(argTypesBlock, propStartIndex);
21696
- if (propEndIndex === -1) break;
21697
- const propBlock = argTypesBlock.slice(propStartIndex + 1, propEndIndex);
21698
- const descMatch = propBlock.match(/description:\s*['"](.+?)['"]\s*[,}]/s);
21699
- const description = descMatch ? descMatch[1].replace(/\\(['"])/g, "$1") : "";
21700
- const controlMatch = propBlock.match(/control:\s*['"]?(\w+)['"]?/);
21701
- const control = controlMatch ? controlMatch[1] : void 0;
21702
- const optionsMatch = propBlock.match(/options:\s*\[([\s\S]*?)\]/);
21703
- let options;
21704
- if (optionsMatch) {
21705
- options = optionsMatch[1].split(",").map((opt) => opt.trim().replace(/['"]/g, "")).filter(Boolean);
21706
- }
21707
- argTypes.push({
21708
- name: propName,
21709
- description,
21710
- control,
21711
- options
21712
- });
21713
- index = propEndIndex + 1;
21714
- }
21715
- return argTypes;
21716
- }
21717
- function extractTitle(content) {
21718
- const titleMatch = content.match(/title:\s*['"]([^'"]+)['"]/);
21719
- return titleMatch ? titleMatch[1] : "";
21720
- }
21721
- function extractMetaArgs(content) {
21722
- const metaDefaultIndex = content.indexOf("export default");
21723
- if (metaDefaultIndex === -1) return void 0;
21724
- const metaSection = content.slice(0, metaDefaultIndex);
21725
- const argsKeyIndex = metaSection.lastIndexOf("args:");
21726
- if (argsKeyIndex !== -1) {
21727
- return extractArgsFromPosition(content, argsKeyIndex);
21728
- }
21729
- const afterExport = content.slice(metaDefaultIndex + "export default".length);
21730
- const trimmed = afterExport.trimStart();
21731
- if (!trimmed.startsWith("{")) return void 0;
21732
- const blockStart = content.indexOf("{", metaDefaultIndex);
21733
- const blockEnd = findMatchingBrace(content, blockStart);
21734
- if (blockEnd === -1) return void 0;
21735
- const metaBlock = content.slice(blockStart + 1, blockEnd);
21736
- const inlineArgsIndex = metaBlock.indexOf("args:");
21737
- if (inlineArgsIndex === -1) return void 0;
21738
- return extractArgsFromPosition(content, blockStart + 1 + inlineArgsIndex);
21739
- }
21740
- function extractArgsFromPosition(content, argsKeyIndex) {
21741
- const colonIndex = content.indexOf(":", argsKeyIndex + 4);
21742
- if (colonIndex === -1) {
21743
- return void 0;
21744
- }
21745
- const openingBraceIndex = content.indexOf("{", colonIndex);
21746
- if (openingBraceIndex === -1) {
21747
- return void 0;
21748
- }
21749
- const closingBraceIndex = findMatchingBrace(content, openingBraceIndex);
21750
- if (closingBraceIndex === -1) {
21751
- return void 0;
21752
- }
21753
- const argsBlock = content.slice(openingBraceIndex + 1, closingBraceIndex);
21754
- const args = {};
21755
- const kvRegex = /(\w+)\s*:\s*(?:'([^']*)'|"([^"]*)"|(\d+(?:\.\d+)?)|(\btrue\b|\bfalse\b))/g;
21756
- let match;
21757
- while ((match = kvRegex.exec(argsBlock)) !== null) {
21758
- const key = match[1];
21759
- if (match[2] !== void 0) {
21760
- args[key] = match[2];
21761
- } else if (match[3] !== void 0) {
21762
- args[key] = match[3];
21763
- } else if (match[4] !== void 0) {
21764
- args[key] = Number(match[4]);
21765
- } else if (match[5] !== void 0) {
21766
- args[key] = match[5] === "true";
21767
- }
21768
- }
21769
- return Object.keys(args).length > 0 ? args : void 0;
21770
- }
21771
- function readStoriesFile(filePath) {
21772
- const content = readTextFile(filePath);
21773
- if (!content) {
21774
- return null;
21775
- }
21776
- const title = extractTitle(content);
21777
- const argTypes = extractArgTypes(content);
21778
- const templateSources = extractTemplateSource(content);
21779
- const storyTemplateMap = extractStories(content);
21780
- const examples = [];
21781
- const usageGuidance = [];
21782
- const coveredStories = /* @__PURE__ */ new Set();
21783
- for (const [storyName, templateVar] of storyTemplateMap) {
21784
- const code = templateSources.get(templateVar);
21785
- const description = extractStoryJSDoc(content, storyName);
21786
- if (code) {
21787
- examples.push({
21788
- name: storyName,
21789
- description,
21790
- code
21791
- });
21792
- coveredStories.add(storyName);
21793
- }
21794
- if (description) {
21795
- usageGuidance.push(description);
21796
- }
21797
- }
21798
- const inlineExamples = extractInlineRenderTemplates(content);
21799
- for (const example of inlineExamples) {
21800
- if (!coveredStories.has(example.name)) {
21801
- const description = extractStoryJSDoc(content, example.name);
21802
- examples.push({ ...example, description });
21803
- if (description) {
21804
- usageGuidance.push(description);
21805
- }
21806
- }
21807
- }
21808
- const defaultArgs = extractMetaArgs(content);
21809
- return {
21810
- title,
21811
- examples,
21812
- argTypes,
21813
- usageGuidance,
21814
- defaultArgs
21815
- };
21816
- }
21817
- function readComponentStories(componentDir) {
21818
- const componentName = path6.basename(componentDir);
21819
- const storiesPath = path6.join(componentDir, `${componentName}.stories.ts`);
21820
- return readStoriesFile(storiesPath);
21844
+ // src/readers/component-docs-reader.ts
21845
+ import * as path7 from "node:path";
21846
+ function readComponentSupplementalDocs(componentDir) {
21847
+ return readJsonFile(
21848
+ path7.join(componentDir, "mcp-docs.json")
21849
+ );
21821
21850
  }
21822
21851
 
21823
21852
  // src/tools/get-docs.ts
21824
21853
  function findComponentDirectory(componentName) {
21825
21854
  const srcPath = getLibrarySourcePath();
21826
21855
  for (const category of getCategoryDirs()) {
21827
- const componentDir = path7.join(srcPath, category, componentName);
21856
+ const componentDir = path8.join(srcPath, category, componentName);
21828
21857
  if (isDirectory(componentDir)) {
21829
21858
  return componentDir;
21830
21859
  }
@@ -21860,15 +21889,17 @@ function getComponentDocs(componentName) {
21860
21889
  const props = typeInfo?.props || [];
21861
21890
  let description = typeInfo?.description || "";
21862
21891
  const storiesInfo = readComponentStories(componentDir);
21892
+ const labels = storiesInfo?.labels || [];
21863
21893
  const examples = storiesInfo?.examples || [];
21864
21894
  const usageGuidance = storiesInfo?.usageGuidance || [];
21895
+ const supplementalDocs = readComponentSupplementalDocs(componentDir);
21865
21896
  if (!description && usageGuidance.length > 0) {
21866
21897
  description = usageGuidance[0];
21867
21898
  }
21868
21899
  if (!description) {
21869
21900
  description = `${normalizedName} component from @aleph-alpha/ui-library`;
21870
21901
  }
21871
- const indexPath = path7.join(componentDir, "index.ts");
21902
+ const indexPath = path8.join(componentDir, "index.ts");
21872
21903
  const subComponents = readTextFile(indexPath) ? extractSubComponents(indexPath, normalizedName) : void 0;
21873
21904
  if (storiesInfo?.argTypes) {
21874
21905
  for (const argType of storiesInfo.argTypes) {
@@ -21881,20 +21912,22 @@ function getComponentDocs(componentName) {
21881
21912
  return {
21882
21913
  name: normalizedName,
21883
21914
  description,
21915
+ labels,
21884
21916
  props,
21885
21917
  examples,
21886
21918
  usageGuidance: [...new Set(usageGuidance)],
21887
21919
  // Remove duplicates
21920
+ supplementalDocs: supplementalDocs ?? void 0,
21888
21921
  subComponents: subComponents && subComponents.length > 0 ? subComponents : void 0,
21889
21922
  defaultArgs: storiesInfo?.defaultArgs
21890
21923
  };
21891
21924
  }
21892
21925
 
21893
21926
  // src/tools/get-setup.ts
21894
- import * as path8 from "node:path";
21927
+ import * as path9 from "node:path";
21895
21928
  function getSetupGuide() {
21896
21929
  const libraryRoot = getLibraryRootPath();
21897
- const quickStartPath = path8.join(
21930
+ const quickStartPath = path9.join(
21898
21931
  libraryRoot,
21899
21932
  "docs",
21900
21933
  "public-docs",
@@ -21904,7 +21937,7 @@ function getSetupGuide() {
21904
21937
  if (quickStart) {
21905
21938
  return quickStart;
21906
21939
  }
21907
- const readmePath = path8.join(libraryRoot, "README.md");
21940
+ const readmePath = path9.join(libraryRoot, "README.md");
21908
21941
  const readme = readTextFile(readmePath);
21909
21942
  if (readme) {
21910
21943
  return readme;
@@ -21914,10 +21947,10 @@ function getSetupGuide() {
21914
21947
 
21915
21948
  // src/tools/list-chat-kit-components.ts
21916
21949
  import * as fs6 from "node:fs";
21917
- import * as path10 from "node:path";
21950
+ import * as path11 from "node:path";
21918
21951
 
21919
21952
  // src/readers/chat-kit-types-reader.ts
21920
- import * as path9 from "node:path";
21953
+ import * as path10 from "node:path";
21921
21954
  var TYPE_OR_INTERFACE2 = "(?:interface|type)";
21922
21955
  function parseJSDoc2(comment) {
21923
21956
  const lines = comment.replace(/\/\*\*|\*\/|\*/g, "").split("\n").map((line) => line.trim()).filter(Boolean);
@@ -22051,7 +22084,7 @@ function readChatKitTypesFile(filePath, componentName) {
22051
22084
  if (!content) {
22052
22085
  return null;
22053
22086
  }
22054
- const resolvedName = componentName || path9.basename(path9.dirname(filePath));
22087
+ const resolvedName = componentName || path10.basename(path10.dirname(filePath));
22055
22088
  const exactRegex = new RegExp(
22056
22089
  `export\\s+${TYPE_OR_INTERFACE2}\\s+(${resolvedName}Props)\\b`
22057
22090
  );
@@ -22084,8 +22117,8 @@ function readChatKitTypesFile(filePath, componentName) {
22084
22117
  };
22085
22118
  }
22086
22119
  function readChatKitComponentTypes(componentDir) {
22087
- const typesPath = path9.join(componentDir, "types.ts");
22088
- return readChatKitTypesFile(typesPath, path9.basename(componentDir));
22120
+ const typesPath = path10.join(componentDir, "types.ts");
22121
+ return readChatKitTypesFile(typesPath, path10.basename(componentDir));
22089
22122
  }
22090
22123
 
22091
22124
  // src/tools/list-chat-kit-components.ts
@@ -22106,10 +22139,10 @@ function listChatKitComponents(filter) {
22106
22139
  const srcPath = getChatKitSourcePath();
22107
22140
  const meta = loadChatKitComponentsMeta();
22108
22141
  const allComponents = getChatKitCategoryDirs().flatMap((category) => {
22109
- const categoryPath = path10.join(srcPath, category);
22142
+ const categoryPath = path11.join(srcPath, category);
22110
22143
  if (!isDirectory(categoryPath)) return [];
22111
22144
  return fs6.readdirSync(categoryPath, { withFileTypes: true }).filter((e) => e.isDirectory() && isChatKitComponent(e.name)).map((e) => {
22112
- const componentDir = path10.join(categoryPath, e.name);
22145
+ const componentDir = path11.join(categoryPath, e.name);
22113
22146
  const componentMeta = meta[e.name];
22114
22147
  return {
22115
22148
  name: e.name,
@@ -22123,14 +22156,14 @@ function listChatKitComponents(filter) {
22123
22156
  }
22124
22157
 
22125
22158
  // src/tools/get-chat-kit-docs.ts
22126
- import * as path11 from "node:path";
22159
+ import * as path12 from "node:path";
22127
22160
  function normalizeChatKitName(name) {
22128
22161
  return name.startsWith(CHAT_KIT_PREFIX) ? name : `${CHAT_KIT_PREFIX}${name}`;
22129
22162
  }
22130
22163
  function findChatKitComponentDir(componentName) {
22131
22164
  const srcPath = getChatKitSourcePath();
22132
22165
  for (const category of getChatKitCategoryDirs()) {
22133
- const dir = path11.join(srcPath, category, componentName);
22166
+ const dir = path12.join(srcPath, category, componentName);
22134
22167
  if (isDirectory(dir)) return dir;
22135
22168
  }
22136
22169
  return null;
@@ -22168,7 +22201,7 @@ function getChatKitComponentDocs(componentName) {
22168
22201
  if (!description) {
22169
22202
  description = `${name} component from @aleph-alpha/chat-kit`;
22170
22203
  }
22171
- const indexPath = path11.join(componentDir, "index.ts");
22204
+ const indexPath = path12.join(componentDir, "index.ts");
22172
22205
  const subComponents = readTextFile(indexPath) ? extractSubComponents2(indexPath, name) : void 0;
22173
22206
  if (storiesInfo?.argTypes) {
22174
22207
  for (const argType of storiesInfo.argTypes) {
@@ -22212,6 +22245,12 @@ function formatProp(prop) {
22212
22245
  }
22213
22246
  function formatComponentDocs(docs) {
22214
22247
  const sections = [`# ${docs.name}`, docs.description, ""];
22248
+ if (docs.labels.length > 0) {
22249
+ sections.push(
22250
+ `**Labels:** ${docs.labels.map((label) => `\`${label}\``).join(", ")}`,
22251
+ ""
22252
+ );
22253
+ }
22215
22254
  if (docs.props.length > 0) {
22216
22255
  sections.push("## Props", "");
22217
22256
  docs.props.forEach((prop) => sections.push(...formatProp(prop)));
@@ -22249,6 +22288,22 @@ function formatComponentDocs(docs) {
22249
22288
  docs.usageGuidance.forEach((guidance) => sections.push(`- ${guidance}`));
22250
22289
  sections.push("");
22251
22290
  }
22291
+ if (docs.supplementalDocs?.designNotes) {
22292
+ sections.push(
22293
+ ...formatSupplementalDocsSection(
22294
+ "Design Notes",
22295
+ docs.supplementalDocs.designNotes
22296
+ )
22297
+ );
22298
+ }
22299
+ if (docs.supplementalDocs?.accessibility) {
22300
+ sections.push(
22301
+ ...formatSupplementalDocsSection(
22302
+ "Accessibility",
22303
+ docs.supplementalDocs.accessibility
22304
+ )
22305
+ );
22306
+ }
22252
22307
  if (docs.examples.length > 0) {
22253
22308
  sections.push("## Examples", "");
22254
22309
  docs.examples.forEach((example) => {
@@ -22261,6 +22316,37 @@ function formatComponentDocs(docs) {
22261
22316
  }
22262
22317
  return sections.join("\n").trim();
22263
22318
  }
22319
+ function formatSupplementalDocsSection(heading, section) {
22320
+ if (!section) return [];
22321
+ const lines = [`## ${heading}`, ""];
22322
+ lines.push(`### ${section.title}`, "");
22323
+ if (section.summary) {
22324
+ lines.push(section.summary, "");
22325
+ }
22326
+ for (const block of section.sections ?? []) {
22327
+ lines.push(`#### ${block.title}`, "");
22328
+ if (block.content) {
22329
+ lines.push(block.content, "");
22330
+ }
22331
+ for (const item of block.items ?? []) {
22332
+ lines.push(`- ${item}`);
22333
+ }
22334
+ if (block.items?.length) {
22335
+ lines.push("");
22336
+ }
22337
+ }
22338
+ if (section.do?.length) {
22339
+ lines.push("#### Do", "");
22340
+ section.do.forEach((item) => lines.push(`- ${item}`));
22341
+ lines.push("");
22342
+ }
22343
+ if (section.dont?.length) {
22344
+ lines.push("#### Don't", "");
22345
+ section.dont.forEach((item) => lines.push(`- ${item}`));
22346
+ lines.push("");
22347
+ }
22348
+ return lines;
22349
+ }
22264
22350
  async function startServer() {
22265
22351
  const server = new McpServer({
22266
22352
  name: "ui-library",
@@ -22291,7 +22377,8 @@ async function startServer() {
22291
22377
  Object.entries(grouped).forEach(([category, comps]) => {
22292
22378
  sections.push(`## ${category}`, "");
22293
22379
  comps.forEach((comp) => {
22294
- sections.push(`- **${comp.name}**: ${comp.description}`);
22380
+ const labels = comp.labels.length > 0 ? ` [${comp.labels.join(", ")}]` : "";
22381
+ sections.push(`- **${comp.name}**${labels}: ${comp.description}`);
22295
22382
  });
22296
22383
  sections.push("");
22297
22384
  });