bestax-mcp 0.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.
Files changed (144) hide show
  1. package/README.md +90 -0
  2. package/data/catalog.json +1869 -0
  3. package/data/components/Autocomplete.json +604 -0
  4. package/data/components/Avatar.json +220 -0
  5. package/data/components/Avatars.json +294 -0
  6. package/data/components/Badge.json +261 -0
  7. package/data/components/Block.json +105 -0
  8. package/data/components/Box.json +157 -0
  9. package/data/components/Breadcrumb.json +155 -0
  10. package/data/components/Button.json +599 -0
  11. package/data/components/Buttons.json +533 -0
  12. package/data/components/Card.json +506 -0
  13. package/data/components/Carousel.json +512 -0
  14. package/data/components/Cell.json +154 -0
  15. package/data/components/Checkbox.json +176 -0
  16. package/data/components/Checkboxes.json +240 -0
  17. package/data/components/Code.json +128 -0
  18. package/data/components/Collapse.json +218 -0
  19. package/data/components/Column.json +284 -0
  20. package/data/components/Columns.json +542 -0
  21. package/data/components/ConfigProvider.json +16 -0
  22. package/data/components/Container.json +149 -0
  23. package/data/components/Content.json +228 -0
  24. package/data/components/Control.json +484 -0
  25. package/data/components/DateInput.json +872 -0
  26. package/data/components/DateTimeInput.json +952 -0
  27. package/data/components/Delete.json +153 -0
  28. package/data/components/Dialog.json +285 -0
  29. package/data/components/Divider.json +68 -0
  30. package/data/components/Dropdown.json +353 -0
  31. package/data/components/Emphasis.json +99 -0
  32. package/data/components/Field.json +539 -0
  33. package/data/components/Figure.json +143 -0
  34. package/data/components/File.json +403 -0
  35. package/data/components/Footer.json +109 -0
  36. package/data/components/Grid.json +357 -0
  37. package/data/components/Hero.json +340 -0
  38. package/data/components/Icon.json +232 -0
  39. package/data/components/IconText.json +307 -0
  40. package/data/components/Image.json +166 -0
  41. package/data/components/Input.json +583 -0
  42. package/data/components/Level.json +332 -0
  43. package/data/components/Link.json +154 -0
  44. package/data/components/LinkButton.json +247 -0
  45. package/data/components/ListItem.json +101 -0
  46. package/data/components/Loading.json +323 -0
  47. package/data/components/Media.json +345 -0
  48. package/data/components/Menu.json +317 -0
  49. package/data/components/Message.json +303 -0
  50. package/data/components/Modal.json +444 -0
  51. package/data/components/Navbar.json +996 -0
  52. package/data/components/Notification.json +165 -0
  53. package/data/components/Numberinput.json +364 -0
  54. package/data/components/OrderedList.json +189 -0
  55. package/data/components/Pagination.json +619 -0
  56. package/data/components/Panel.json +582 -0
  57. package/data/components/Paragraph.json +107 -0
  58. package/data/components/Pre.json +114 -0
  59. package/data/components/Progress.json +137 -0
  60. package/data/components/Radio.json +164 -0
  61. package/data/components/Radios.json +240 -0
  62. package/data/components/Rate.json +466 -0
  63. package/data/components/Reveal.json +177 -0
  64. package/data/components/Section.json +123 -0
  65. package/data/components/Select.json +526 -0
  66. package/data/components/Sidebar.json +488 -0
  67. package/data/components/Skeleton.json +162 -0
  68. package/data/components/Slider.json +534 -0
  69. package/data/components/Span.json +100 -0
  70. package/data/components/Steps.json +452 -0
  71. package/data/components/Strong.json +105 -0
  72. package/data/components/SubTitle.json +233 -0
  73. package/data/components/Switch.json +291 -0
  74. package/data/components/Table.json +490 -0
  75. package/data/components/Tabs.json +592 -0
  76. package/data/components/Tag.json +197 -0
  77. package/data/components/Taginput.json +587 -0
  78. package/data/components/Tags.json +181 -0
  79. package/data/components/TextArea.json +483 -0
  80. package/data/components/Theme.json +65 -0
  81. package/data/components/TimeInput.json +906 -0
  82. package/data/components/Title.json +240 -0
  83. package/data/components/Toast.json +308 -0
  84. package/data/components/Tooltip.json +212 -0
  85. package/data/components/UnorderedList.json +149 -0
  86. package/data/components/Valid value constants.json +16 -0
  87. package/data/components/classNames.json +65 -0
  88. package/data/components/useBulmaClasses.json +169 -0
  89. package/data/components/usePrefixedClassNames.json +25 -0
  90. package/data/skills/bestax-custom-component/SKILL.md +196 -0
  91. package/data/skills/bestax-custom-component/examples/stat-card.tsx +105 -0
  92. package/data/skills/bestax-custom-component/references/api.md +90 -0
  93. package/data/skills/bestax-custom-component/references/component-catalog.md +149 -0
  94. package/data/skills/bestax-custom-component/references/library-contributor.md +395 -0
  95. package/data/skills/bestax-custom-component/references/patterns.md +136 -0
  96. package/data/skills/bestax-form/SKILL.md +254 -0
  97. package/data/skills/bestax-form/references/api.md +103 -0
  98. package/data/skills/bestax-form/references/patterns.md +210 -0
  99. package/data/skills/bestax-icons/SKILL.md +80 -0
  100. package/data/skills/bestax-icons/examples/icon-usage.tsx +80 -0
  101. package/data/skills/bestax-icons/references/icon-libraries.md +131 -0
  102. package/data/skills/bestax-layout-scaffold/SKILL.md +196 -0
  103. package/data/skills/bestax-layout-scaffold/examples/app-shell.tsx +86 -0
  104. package/data/skills/bestax-layout-scaffold/examples/card-grid.tsx +106 -0
  105. package/data/skills/bestax-layout-scaffold/examples/centered.tsx +56 -0
  106. package/data/skills/bestax-layout-scaffold/examples/content-page.tsx +90 -0
  107. package/data/skills/bestax-layout-scaffold/examples/landing.tsx +122 -0
  108. package/data/skills/bestax-layout-scaffold/references/archetypes.md +246 -0
  109. package/data/skills/bestax-layout-scaffold/references/layout-components.md +269 -0
  110. package/data/skills/bestax-migrate/SKILL.md +78 -0
  111. package/data/skills/bestax-migrate/references/component-map.md +91 -0
  112. package/data/skills/bestax-migrate/references/css-migration.md +100 -0
  113. package/data/skills/bestax-migrate/references/prop-map.md +48 -0
  114. package/data/skills/bestax-migrate/references/unmappables.md +124 -0
  115. package/data/skills/bestax-optimize/SKILL.md +131 -0
  116. package/data/skills/bestax-optimize/references/modular-build.md +173 -0
  117. package/data/skills/bestax-theming/SKILL.md +117 -0
  118. package/data/skills/bestax-theming/examples/dark-mode.tsx +38 -0
  119. package/data/skills/bestax-theming/examples/theme-config.tsx +60 -0
  120. package/data/skills/bestax-theming/references/css-variables.md +466 -0
  121. package/data/skills/bestax-theming/references/themeable-components.md +119 -0
  122. package/data/skills.json +148 -0
  123. package/dist/data.d.ts +131 -0
  124. package/dist/data.d.ts.map +1 -0
  125. package/dist/data.js +111 -0
  126. package/dist/format.d.ts +37 -0
  127. package/dist/format.d.ts.map +1 -0
  128. package/dist/format.js +178 -0
  129. package/dist/helper-props.d.ts +57 -0
  130. package/dist/helper-props.d.ts.map +1 -0
  131. package/dist/helper-props.js +249 -0
  132. package/dist/index.d.ts +3 -0
  133. package/dist/index.d.ts.map +1 -0
  134. package/dist/index.js +18 -0
  135. package/dist/search.d.ts +32 -0
  136. package/dist/search.d.ts.map +1 -0
  137. package/dist/search.js +194 -0
  138. package/dist/server.d.ts +28 -0
  139. package/dist/server.d.ts.map +1 -0
  140. package/dist/server.js +616 -0
  141. package/dist/version.d.ts +29 -0
  142. package/dist/version.d.ts.map +1 -0
  143. package/dist/version.js +147 -0
  144. package/package.json +70 -0
@@ -0,0 +1,148 @@
1
+ {
2
+ "skills": [
3
+ {
4
+ "name": "bestax-custom-component",
5
+ "description": "Build a custom React component in the bestax/Bulma style. In an app using @allxsmith/bestax-bulma — compose existing components, helper props, public hooks (useBulmaClasses, usePrefixedClassNames), and --bulma-* CSS variables. In the bestax monorepo — the full component pipeline (SCSS partial, stories, tests, docs, wiring). Use when creating a component beyond stock Bulma or extending one.",
6
+ "promptName": "custom-component",
7
+ "dir": "bestax-custom-component",
8
+ "references": [
9
+ { "id": "api", "file": "references/api.md", "bytes": 5379 },
10
+ {
11
+ "id": "component-catalog",
12
+ "file": "references/component-catalog.md",
13
+ "bytes": 17351
14
+ },
15
+ {
16
+ "id": "library-contributor",
17
+ "file": "references/library-contributor.md",
18
+ "bytes": 15257
19
+ },
20
+ { "id": "patterns", "file": "references/patterns.md", "bytes": 4601 }
21
+ ],
22
+ "examples": [
23
+ { "id": "stat-card", "file": "examples/stat-card.tsx", "bytes": 3828 }
24
+ ]
25
+ },
26
+ {
27
+ "name": "bestax-form",
28
+ "description": "Build forms with @allxsmith/bestax-bulma — Field/Control/Label/Help composition, inputs, selects, checkboxes, radios, switches, and advanced controls (Autocomplete, Slider, Numberinput, Rate, Taginput, File, date/time). There is no form/validation library; this skill shows the components and the validate-it-yourself error pattern. Use when building a form, wiring inputs to state, or showing validation/error state.",
29
+ "promptName": "form",
30
+ "dir": "bestax-form",
31
+ "references": [
32
+ { "id": "api", "file": "references/api.md", "bytes": 8378 },
33
+ { "id": "patterns", "file": "references/patterns.md", "bytes": 5566 }
34
+ ],
35
+ "examples": []
36
+ },
37
+ {
38
+ "name": "bestax-icons",
39
+ "description": "Use icons in an app built with @allxsmith/bestax-bulma — the Icon/IconText components and the five supported libraries (Font Awesome, Material Design Icons, Ionicons, Google Material Icons, Material Symbols). Use when adding an icon, choosing or configuring the app-wide icon library, fixing an icon that renders blank, pairing icons with text, or making icons accessible (decorative vs labeled).",
40
+ "promptName": "icons",
41
+ "dir": "bestax-icons",
42
+ "references": [
43
+ {
44
+ "id": "icon-libraries",
45
+ "file": "references/icon-libraries.md",
46
+ "bytes": 6179
47
+ }
48
+ ],
49
+ "examples": [
50
+ { "id": "icon-usage", "file": "examples/icon-usage.tsx", "bytes": 2720 }
51
+ ]
52
+ },
53
+ {
54
+ "name": "bestax-layout-scaffold",
55
+ "description": "Scaffold a complete, responsive page layout with @allxsmith/bestax-bulma — app shells/dashboards, marketing/landing pages, centered auth/settings pages, and card-grid catalogs. Use when building a full page or overall app layout (not a single component).",
56
+ "promptName": "layout-scaffold",
57
+ "dir": "bestax-layout-scaffold",
58
+ "references": [
59
+ {
60
+ "id": "archetypes",
61
+ "file": "references/archetypes.md",
62
+ "bytes": 8038
63
+ },
64
+ {
65
+ "id": "layout-components",
66
+ "file": "references/layout-components.md",
67
+ "bytes": 14389
68
+ }
69
+ ],
70
+ "examples": [
71
+ { "id": "app-shell", "file": "examples/app-shell.tsx", "bytes": 2765 },
72
+ { "id": "card-grid", "file": "examples/card-grid.tsx", "bytes": 2700 },
73
+ { "id": "centered", "file": "examples/centered.tsx", "bytes": 1443 },
74
+ {
75
+ "id": "content-page",
76
+ "file": "examples/content-page.tsx",
77
+ "bytes": 2608
78
+ },
79
+ { "id": "landing", "file": "examples/landing.tsx", "bytes": 3910 }
80
+ ]
81
+ },
82
+ {
83
+ "name": "bestax-migrate",
84
+ "description": "Migrate an existing app from react-bulma-components (v4) to @allxsmith/bestax-bulma on Bulma v1 — run the bestax-migrate codemod, then resolve every TODO(bestax-migrate) comment it leaves using the mapping references. Use when a repo imports react-bulma-components and wants to move to bestax-bulma, when TODO(bestax-migrate) comments are present in a codebase, or when asked to migrate off an unmaintained React Bulma library.",
85
+ "promptName": "migrate",
86
+ "dir": "bestax-migrate",
87
+ "references": [
88
+ {
89
+ "id": "component-map",
90
+ "file": "references/component-map.md",
91
+ "bytes": 11894
92
+ },
93
+ {
94
+ "id": "css-migration",
95
+ "file": "references/css-migration.md",
96
+ "bytes": 5679
97
+ },
98
+ { "id": "prop-map", "file": "references/prop-map.md", "bytes": 6363 },
99
+ {
100
+ "id": "unmappables",
101
+ "file": "references/unmappables.md",
102
+ "bytes": 4866
103
+ }
104
+ ],
105
+ "examples": []
106
+ },
107
+ {
108
+ "name": "bestax-optimize",
109
+ "description": "Reduce the built CSS size of an app using @allxsmith/bestax-bulma — measure raw and gzip size, then apply the cheapest lever that fits (lighter prebuilt CSS flavor, hand-rolled modular Sass build, import and icon-asset hygiene). Use when the CSS bundle looks too big, a size budget or Lighthouse audit flags stylesheet weight, switching bestax.css to a versions/*.css flavor, or setting up a modular @use Bulma/Sass build.",
110
+ "promptName": "optimize",
111
+ "dir": "bestax-optimize",
112
+ "references": [
113
+ {
114
+ "id": "modular-build",
115
+ "file": "references/modular-build.md",
116
+ "bytes": 7761
117
+ }
118
+ ],
119
+ "examples": []
120
+ },
121
+ {
122
+ "name": "bestax-theming",
123
+ "description": "Customize colors, branding, dark mode, and visual tokens of an app built with @allxsmith/bestax-bulma. Use when changing the primary/brand color, recoloring components, overriding Bulma --bulma-* CSS variables, setting fonts/radius/spacing tokens, adding light/dark mode, or configuring the app-wide icon library / class prefix via ConfigProvider.",
124
+ "promptName": "theming",
125
+ "dir": "bestax-theming",
126
+ "references": [
127
+ {
128
+ "id": "css-variables",
129
+ "file": "references/css-variables.md",
130
+ "bytes": 24452
131
+ },
132
+ {
133
+ "id": "themeable-components",
134
+ "file": "references/themeable-components.md",
135
+ "bytes": 20268
136
+ }
137
+ ],
138
+ "examples": [
139
+ { "id": "dark-mode", "file": "examples/dark-mode.tsx", "bytes": 1148 },
140
+ {
141
+ "id": "theme-config",
142
+ "file": "examples/theme-config.tsx",
143
+ "bytes": 2089
144
+ }
145
+ ]
146
+ }
147
+ ]
148
+ }
package/dist/data.d.ts ADDED
@@ -0,0 +1,131 @@
1
+ /** Bumped by the generator when the shape changes incompatibly. */
2
+ export declare const SUPPORTED_SCHEMA_VERSION = 1;
3
+ export interface PropRow {
4
+ name: string;
5
+ type: string;
6
+ default: string | null;
7
+ description: string;
8
+ required: boolean;
9
+ inherited: boolean;
10
+ deprecated: boolean;
11
+ deprecationNote?: string;
12
+ /** Docs slug defining a value union too large to inline, e.g. Bulma colors. */
13
+ valuesRef?: string;
14
+ }
15
+ export interface TypeDef {
16
+ name: string;
17
+ expansion: string;
18
+ summary: string;
19
+ }
20
+ export interface Part {
21
+ /** Dot-path: `Navbar`, `Navbar.Brand`. */
22
+ path: string;
23
+ summary: string;
24
+ /** Set when the sub-component is also exported standalone. */
25
+ component: string | null;
26
+ props: PropRow[];
27
+ extraProps: PropRow[];
28
+ catchAll: string | null;
29
+ types: TypeDef[];
30
+ }
31
+ export interface CssVar {
32
+ css: string;
33
+ sass: string | null;
34
+ default: string;
35
+ /** `component`: declared on the component's own selector. `global`: on :root. */
36
+ scope: 'component' | 'global';
37
+ }
38
+ export interface Example {
39
+ title: string;
40
+ code: string;
41
+ }
42
+ export interface ComponentRecord {
43
+ name: string;
44
+ kind: 'component' | 'helper';
45
+ category: string;
46
+ slug: string;
47
+ docsUrl: string;
48
+ summary: string;
49
+ import: string;
50
+ examples: Example[];
51
+ accessibility: string | null;
52
+ related: string[];
53
+ storybook: string | null;
54
+ parts: Part[];
55
+ cssVars: CssVar[];
56
+ sourceFile?: string;
57
+ rootClass?: string | null;
58
+ /** Helper pages ship as prose — they have no props interface. */
59
+ doc?: string;
60
+ }
61
+ export interface CatalogEntry {
62
+ name: string;
63
+ kind: 'component' | 'helper';
64
+ category: string;
65
+ purpose: string;
66
+ slug: string;
67
+ import: string;
68
+ compound: boolean;
69
+ propCount: number;
70
+ exampleCount: number;
71
+ }
72
+ export interface Catalog {
73
+ schemaVersion: number;
74
+ generatedFrom: {
75
+ package: string;
76
+ version: string;
77
+ };
78
+ docsBase: string;
79
+ categories: {
80
+ id: string;
81
+ label: string;
82
+ components: string[];
83
+ }[];
84
+ components: CatalogEntry[];
85
+ cssVarIndex: Record<string, string>;
86
+ }
87
+ export interface SkillFile {
88
+ id: string;
89
+ file: string;
90
+ bytes: number;
91
+ }
92
+ export interface Skill {
93
+ name: string;
94
+ description: string;
95
+ /** `bestax-theming` -> `theming`, the name an MCP client shows for the prompt. */
96
+ promptName: string;
97
+ dir: string;
98
+ references: SkillFile[];
99
+ examples: SkillFile[];
100
+ }
101
+ /** `dist/data.js` and `src/data.ts` are both one level under the package root. */
102
+ export declare const DATA_DIR: string;
103
+ /**
104
+ * The index and the server ship in the same tarball, so a mismatch here is a
105
+ * broken build rather than a user running something stale. Fail loudly instead
106
+ * of serving half of every field.
107
+ */
108
+ export declare function assertSchema(catalog: Catalog): Catalog;
109
+ export declare function loadCatalog(): Promise<Catalog>;
110
+ /**
111
+ * Resolve a user-supplied name to a real component.
112
+ *
113
+ * Tolerant on purpose — a model asks for `navbar`, `<Button>` or
114
+ * `Navbar.Brand`, and refusing any of those wastes a round trip when the
115
+ * intent is unambiguous.
116
+ */
117
+ export declare function resolveName(input: string): Promise<string | null>;
118
+ export declare function loadComponent(name: string): Promise<ComponentRecord>;
119
+ export declare function loadSkills(): Promise<Skill[]>;
120
+ /**
121
+ * A skill's SKILL.md or one of its reference/example files.
122
+ *
123
+ * Bodies are copied into `data/skills/` at build time (see
124
+ * `scripts/sync-skills.mjs`) rather than committed, so a source checkout that
125
+ * has not been built has the manifest but no bodies. Say so rather than
126
+ * surfacing an ENOENT — the fix is `pnpm --filter bestax-mcp build`.
127
+ */
128
+ export declare function loadSkillFile(dir: string, relative?: string): Promise<string>;
129
+ /** Test seam — the loaders memoise for the life of a stdio session. */
130
+ export declare function resetCaches(): void;
131
+ //# sourceMappingURL=data.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data.d.ts","sourceRoot":"","sources":["../src/data.ts"],"names":[],"mappings":"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"}
package/dist/data.js ADDED
@@ -0,0 +1,111 @@
1
+ /**
2
+ * Loaders for the generated index in `data/`.
3
+ *
4
+ * Everything here is lazy and cached. A stdio server is spawned fresh by every
5
+ * client, so startup cost is paid on every session: the catalog (~76 KB) is the
6
+ * only file read eagerly, and a component's own file is pulled the first time a
7
+ * tool asks for it.
8
+ *
9
+ * Nothing in this module is written by hand — regenerate with `pnpm gen:mcp`.
10
+ */
11
+ import { readFile } from 'node:fs/promises';
12
+ import { existsSync } from 'node:fs';
13
+ import { dirname, join } from 'node:path';
14
+ import { fileURLToPath } from 'node:url';
15
+ /** Bumped by the generator when the shape changes incompatibly. */
16
+ export const SUPPORTED_SCHEMA_VERSION = 1;
17
+ const HERE = dirname(fileURLToPath(import.meta.url));
18
+ /** `dist/data.js` and `src/data.ts` are both one level under the package root. */
19
+ export const DATA_DIR = join(HERE, '..', 'data');
20
+ const readJson = async (path) => JSON.parse(await readFile(path, 'utf8'));
21
+ /**
22
+ * The index and the server ship in the same tarball, so a mismatch here is a
23
+ * broken build rather than a user running something stale. Fail loudly instead
24
+ * of serving half of every field.
25
+ */
26
+ export function assertSchema(catalog) {
27
+ if (catalog.schemaVersion !== SUPPORTED_SCHEMA_VERSION) {
28
+ throw new Error(`bestax-mcp: data/catalog.json is schema version ${catalog.schemaVersion}, ` +
29
+ `but this server understands ${SUPPORTED_SCHEMA_VERSION}. Reinstall bestax-mcp.`);
30
+ }
31
+ return catalog;
32
+ }
33
+ let catalogPromise = null;
34
+ export function loadCatalog() {
35
+ catalogPromise ??= readJson(join(DATA_DIR, 'catalog.json')).then(assertSchema);
36
+ return catalogPromise;
37
+ }
38
+ const componentCache = new Map();
39
+ /**
40
+ * Resolve a user-supplied name to a real component.
41
+ *
42
+ * Tolerant on purpose — a model asks for `navbar`, `<Button>` or
43
+ * `Navbar.Brand`, and refusing any of those wastes a round trip when the
44
+ * intent is unambiguous.
45
+ */
46
+ export async function resolveName(input) {
47
+ const catalog = await loadCatalog();
48
+ const cleaned = input.trim().replace(/^<|\/?>$/g, '');
49
+ const root = cleaned.split('.')[0];
50
+ const exact = catalog.components.find(c => c.name === root);
51
+ if (exact)
52
+ return exact.name;
53
+ const lower = root.toLowerCase();
54
+ const ci = catalog.components.find(c => c.name.toLowerCase() === lower);
55
+ return ci ? ci.name : null;
56
+ }
57
+ export function loadComponent(name) {
58
+ let cached = componentCache.get(name);
59
+ if (!cached) {
60
+ cached = readJson(join(DATA_DIR, 'components', `${name}.json`));
61
+ componentCache.set(name, cached);
62
+ }
63
+ return cached;
64
+ }
65
+ let skillsPromise = null;
66
+ /**
67
+ * Skill bodies, memoised like every other loader in this file. `inlineStyleRule()` slices a
68
+ * section out of bestax-layout-scaffold on every `get_helper_props` call and `nearMissRule()`
69
+ * does the same on every unfiltered `list_components`; without this each of those re-read a
70
+ * 15 KB file from disk. The bodies are immutable for the life of a stdio session.
71
+ */
72
+ const skillFileCache = new Map();
73
+ export function loadSkills() {
74
+ skillsPromise ??= readJson(join(DATA_DIR, 'skills.json')).then(d => d.skills);
75
+ return skillsPromise;
76
+ }
77
+ /**
78
+ * A skill's SKILL.md or one of its reference/example files.
79
+ *
80
+ * Bodies are copied into `data/skills/` at build time (see
81
+ * `scripts/sync-skills.mjs`) rather than committed, so a source checkout that
82
+ * has not been built has the manifest but no bodies. Say so rather than
83
+ * surfacing an ENOENT — the fix is `pnpm --filter bestax-mcp build`.
84
+ */
85
+ export async function loadSkillFile(dir, relative = 'SKILL.md') {
86
+ // Defence in depth: `relative` reaches these loaders from tool arguments, and
87
+ // the manifest is the only thing allowed to name a file.
88
+ if (relative.includes('..') || relative.startsWith('/')) {
89
+ throw new Error(`bestax-mcp: refusing to read "${relative}"`);
90
+ }
91
+ const cacheKey = `${dir}/${relative}`;
92
+ const hit = skillFileCache.get(cacheKey);
93
+ if (hit)
94
+ return hit;
95
+ const path = join(DATA_DIR, 'skills', dir, relative);
96
+ if (!existsSync(path)) {
97
+ throw new Error(`bestax-mcp: ${dir}/${relative} is not in this build. Skill bodies are ` +
98
+ `synced by \`pnpm --filter bestax-mcp build\`; a published tarball ` +
99
+ `always carries them.`);
100
+ }
101
+ const read = readFile(path, 'utf8');
102
+ skillFileCache.set(cacheKey, read);
103
+ return read;
104
+ }
105
+ /** Test seam — the loaders memoise for the life of a stdio session. */
106
+ export function resetCaches() {
107
+ catalogPromise = null;
108
+ skillsPromise = null;
109
+ componentCache.clear();
110
+ skillFileCache.clear();
111
+ }
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Rendering for tool responses.
3
+ *
4
+ * Responses are markdown, not JSON. The consumer is a language model, and a
5
+ * prop table it can read costs fewer tokens than the same data as nested
6
+ * objects with repeated keys — and it does not tempt the model into echoing
7
+ * JSON structure back into the code it writes.
8
+ *
9
+ * The other rule here is that nothing is dumped in full when a summary will do.
10
+ * `get_component` returns a component's props; the 24 usage examples are a
11
+ * separate call, because most questions do not need them.
12
+ */
13
+ import type { CatalogEntry, ComponentRecord, CssVar, Example, Part, Skill } from './data.js';
14
+ export declare function table(headers: string[], rows: string[][]): string;
15
+ export declare function renderPart(part: Part, { heading }?: {
16
+ heading?: boolean | undefined;
17
+ }): string;
18
+ export declare function renderComponent(record: ComponentRecord, include: string[]): string;
19
+ export declare function renderExamples(examples: Example[]): string;
20
+ export declare function renderCssVars(vars: CssVar[]): string;
21
+ export declare function renderCatalog(entries: CatalogEntry[]): string;
22
+ export declare function renderSkills(skills: Skill[]): string;
23
+ /** Wrap a body as an MCP text result, appending the version note when there is one. */
24
+ export declare function textResult(body: string, note: string | null): {
25
+ content: {
26
+ type: "text";
27
+ text: string;
28
+ }[];
29
+ };
30
+ export declare function errorResult(message: string): {
31
+ isError: boolean;
32
+ content: {
33
+ type: "text";
34
+ text: string;
35
+ }[];
36
+ };
37
+ //# sourceMappingURL=format.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EACV,YAAY,EACZ,eAAe,EACf,MAAM,EACN,OAAO,EACP,IAAI,EAEJ,KAAK,EACN,MAAM,WAAW,CAAC;AAUnB,wBAAgB,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,MAAM,CAOjE;AAsBD,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,OAAc,EAAE;;CAAK,GAAG,MAAM,CAiCtE;AAED,wBAAgB,eAAe,CAC7B,MAAM,EAAE,eAAe,EACvB,OAAO,EAAE,MAAM,EAAE,GAChB,MAAM,CAsDR;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,MAAM,CAI1D;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,CAmBpD;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,MAAM,CAkB7D;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,CAgBpD;AAED,uFAAuF;AACvF,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;;;;;EAM3D;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM;;;;;;EAK1C"}
package/dist/format.js ADDED
@@ -0,0 +1,178 @@
1
+ /** Escape a cell for a markdown table — the parser splits on pipes first. */
2
+ const cell = (text) => String(text ?? '')
3
+ .replace(/\\/g, '\\\\')
4
+ .replace(/\|/g, '\\|')
5
+ .replace(/\r?\n/g, ' ')
6
+ .trim();
7
+ export function table(headers, rows) {
8
+ if (!rows.length)
9
+ return '';
10
+ return [
11
+ `| ${headers.join(' | ')} |`,
12
+ `| ${headers.map(() => '---').join(' | ')} |`,
13
+ ...rows.map(r => `| ${r.map(cell).join(' | ')} |`),
14
+ ].join('\n');
15
+ }
16
+ function propRows(props) {
17
+ return props.map(p => {
18
+ const notes = [
19
+ p.deprecated
20
+ ? `**Deprecated.**${p.deprecationNote ? ` ${p.deprecationNote}` : ''}`
21
+ : '',
22
+ p.description,
23
+ // The valid-value unions are too large to inline in a cell; name the page
24
+ // that lists them so the model can ask for it rather than guess.
25
+ p.valuesRef ? `(values: ${p.valuesRef})` : '',
26
+ ].filter(Boolean);
27
+ return [
28
+ `\`${p.name}\``,
29
+ `\`${p.type}\``,
30
+ p.default ? `\`${p.default}\`` : '—',
31
+ notes.join(' '),
32
+ ];
33
+ });
34
+ }
35
+ export function renderPart(part, { heading = true } = {}) {
36
+ const out = [];
37
+ if (heading)
38
+ out.push(`### ${part.path}`);
39
+ if (part.summary)
40
+ out.push(part.summary);
41
+ if (part.component) {
42
+ out.push(`Also exported standalone as \`${part.component}\` — call \`get_props\` with that name for its full table.`);
43
+ }
44
+ const rows = [...propRows(part.props), ...propRows(part.extraProps)];
45
+ if (part.catchAll) {
46
+ rows.push(['`...`', part.catchAll, '—', 'See `get_helper_props`.']);
47
+ }
48
+ if (rows.length) {
49
+ out.push(table(['Prop', 'Type', 'Default', 'Notes'], rows));
50
+ }
51
+ else if (!part.component) {
52
+ out.push('No props of its own beyond the standard HTML attributes.');
53
+ }
54
+ if (part.types.length) {
55
+ out.push([
56
+ '**Types:**',
57
+ '',
58
+ ...part.types.map(t => `- \`${t.name}\`: \`${t.expansion}\`${t.summary ? ` — ${t.summary}` : ''}`),
59
+ ].join('\n'));
60
+ }
61
+ return out.join('\n\n');
62
+ }
63
+ export function renderComponent(record, include) {
64
+ const out = [`# ${record.name}`];
65
+ if (record.summary)
66
+ out.push(record.summary);
67
+ out.push(`\`\`\`tsx\n${record.import}\n\`\`\``);
68
+ if (record.kind === 'helper') {
69
+ // Helper pages are reference prose with signature blocks, not tables — and for
70
+ // useBulmaClasses that prose is 51,054 characters. It used to be pushed unconditionally,
71
+ // outside any `include` check, so the DEFAULT call returned all of it and no argument
72
+ // could ask for less. Now it is opt-in, and the default is a pointer at the tool that
73
+ // exists to serve exactly this and can narrow it by group.
74
+ if (include.includes('reference') && record.doc) {
75
+ out.push(record.doc);
76
+ }
77
+ else {
78
+ out.push(`This is a helper, not a component — its reference is large and grouped. ` +
79
+ `Call \`get_helper_props()\` for every prop with its accepted values, or ` +
80
+ `\`get_helper_props({ group })\` for one area with examples. ` +
81
+ `Pass \`include: ["reference"]\` here for the full prose.`);
82
+ }
83
+ }
84
+ else if (include.includes('props')) {
85
+ const [root, ...subs] = record.parts;
86
+ if (root)
87
+ out.push(renderPart(root, { heading: false }));
88
+ if (subs.length) {
89
+ out.push(`**Subcomponents:** ${subs.map(s => `\`${s.path}\``).join(', ')}. ` +
90
+ `Call \`get_props\` with a dot-path for any of them.`);
91
+ }
92
+ }
93
+ if (include.includes('examples') && record.examples.length) {
94
+ out.push('## Examples', renderExamples(record.examples.slice(0, 5)));
95
+ if (record.examples.length > 5) {
96
+ out.push(`_${record.examples.length - 5} more — call \`get_examples\` for the rest._`);
97
+ }
98
+ }
99
+ if (include.includes('cssVars') && record.cssVars.length) {
100
+ out.push('## CSS Variables', renderCssVars(record.cssVars));
101
+ }
102
+ if (include.includes('accessibility') && record.accessibility) {
103
+ out.push('## Accessibility', record.accessibility);
104
+ }
105
+ if (include.includes('related') && record.related.length) {
106
+ out.push(`**Related:** ${record.related.map(r => `\`${r}\``).join(', ')}.`);
107
+ }
108
+ const links = [`Docs: ${record.docsUrl}`];
109
+ if (record.storybook)
110
+ links.push(`Storybook: ${record.storybook}`);
111
+ out.push(links.join(' · '));
112
+ return out.join('\n\n');
113
+ }
114
+ export function renderExamples(examples) {
115
+ return examples
116
+ .map(e => `### ${e.title}\n\n\`\`\`tsx\n${e.code}\n\`\`\``)
117
+ .join('\n\n');
118
+ }
119
+ export function renderCssVars(vars) {
120
+ const body = table(['CSS Variable', 'Sass Variable', 'Default'], vars.map(v => [
121
+ `\`${v.css}\``,
122
+ v.sass ? `\`${v.sass}\`` : '—',
123
+ `\`${v.default}\``,
124
+ ]));
125
+ // Where Bulma declares the default decides where an override has to go, and
126
+ // getting that wrong is the single most common theming failure.
127
+ const scopes = new Set(vars.map(v => v.scope));
128
+ const note = scopes.has('component')
129
+ ? "Variables scoped `component` are declared on the component's own element — " +
130
+ 'override them there or via `className`; a value set on an ancestor is only ' +
131
+ 'inherited and loses to the component-level declaration.'
132
+ : 'These are declared globally, so overriding them on `:root` (or with the ' +
133
+ '`Theme` component) retheme every instance.';
134
+ return `${body}\n\n${note}`;
135
+ }
136
+ export function renderCatalog(entries) {
137
+ const byCategory = new Map();
138
+ for (const e of entries) {
139
+ const list = byCategory.get(e.category) ?? [];
140
+ list.push(e);
141
+ byCategory.set(e.category, list);
142
+ }
143
+ return [...byCategory]
144
+ .map(([category, list]) => [
145
+ `## ${category}`,
146
+ ...list.map(e => `- **${e.name}**${e.compound ? ' (compound)' : ''} — ${e.purpose}`),
147
+ ].join('\n'))
148
+ .join('\n\n');
149
+ }
150
+ export function renderSkills(skills) {
151
+ return skills
152
+ .map(s => [
153
+ `## ${s.name}`,
154
+ s.description,
155
+ s.references.length
156
+ ? `References: ${s.references.map(r => `\`${r.id}\``).join(', ')} — ` +
157
+ `call \`get_skill\` with \`reference\` to read one.`
158
+ : null,
159
+ `MCP prompt: \`${s.promptName}\`.`,
160
+ ]
161
+ .filter(Boolean)
162
+ .join('\n\n'))
163
+ .join('\n\n');
164
+ }
165
+ /** Wrap a body as an MCP text result, appending the version note when there is one. */
166
+ export function textResult(body, note) {
167
+ return {
168
+ content: [
169
+ { type: 'text', text: note ? `${body}\n\n${note}` : body },
170
+ ],
171
+ };
172
+ }
173
+ export function errorResult(message) {
174
+ return {
175
+ isError: true,
176
+ content: [{ type: 'text', text: message }],
177
+ };
178
+ }
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Shaping the helper-prop reference so asking one question does not cost the whole page.
3
+ *
4
+ * `get_helper_props` was 54,886 characters — 49% of everything a cold-start builder read in
5
+ * a measured session, on the tool this server's own `instructions` tell every client to call
6
+ * before writing styling. Its `group` argument was supposed to prevent that and did not: the
7
+ * filter substring-matched whole section BODIES, and three sections (`Supported Props`,
8
+ * `Viewport-Specific Properties`, `Full TypeScript Definition`) name every helper keyword, so
9
+ * `group: "text"` matched 21 of 41 sections — 87% of the page.
10
+ *
11
+ * Matching headings instead is not the fix either; it is a regression. `spacing` and
12
+ * `typography` — two of the three groups the tool's own description advertises — match no
13
+ * heading at all and would answer nothing.
14
+ *
15
+ * So the groups are curated, and each one carries its own slice of the prop table. The
16
+ * governing rule is that **no call ever loses a prop name**: the default lists all 46 with
17
+ * their accepted values, because a builder has to be able to look up a valid value in one
18
+ * call. What moves behind `group` is the prose and the live examples, which are re-fetchable
19
+ * and which nothing breaks without.
20
+ */
21
+ /**
22
+ * Markdown tables in the generated index are column-padded for human reading. That padding
23
+ * is 32% of this document — 16,352 characters, of which `Supported Props` alone contributes
24
+ * 12,455. Stripping it is free: no model reads alignment, and the cell contents are
25
+ * untouched.
26
+ */
27
+ export declare function reflowTables(md: string): string;
28
+ export interface HelperGroup {
29
+ /** Section headings, matched exactly against the `##`/`###` line. */
30
+ headings: string[];
31
+ /** Prop names whose rows are sliced out of the Supported Props table. */
32
+ props: string[];
33
+ /** Words a builder is likely to use for this group instead of its name. */
34
+ aliases: string[];
35
+ }
36
+ /**
37
+ * Every prop in the table belongs to exactly one group — checked by a test, because a prop
38
+ * that falls through the map is a prop a `group` call can never surface.
39
+ */
40
+ export declare const HELPER_GROUPS: Record<string, HelperGroup>;
41
+ export declare const GROUP_NAMES: string[];
42
+ /** A builder's word → a group name, or null when nothing sensible matches. */
43
+ export declare function resolveGroup(input: string): string | null;
44
+ /** The `## Supported Props` table, reflowed, header rows plus the rows for `props`. */
45
+ export declare function propTable(doc: string, props?: string[]): string;
46
+ /**
47
+ * The no-argument answer: every prop and every accepted value, and nothing else.
48
+ *
49
+ * Deliberately excluded, and why each is safe to drop: `Full TypeScript Definition` (5,143)
50
+ * is a lossless restatement of the table above it; `Composable Mini-Hooks` (4,792) is
51
+ * material for writing a component, which is `bestax-custom-component`'s job; the twenty-odd
52
+ * live example blocks are reachable through `group`.
53
+ */
54
+ export declare function renderHelperDefault(doc: string): string;
55
+ /** One group: its example sections, then just its rows of the prop table. */
56
+ export declare function renderHelperGroup(doc: string, name: string): string;
57
+ //# sourceMappingURL=helper-props.d.ts.map