@1money/component-ui 0.0.22 → 0.0.24

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 (101) hide show
  1. package/es/components/Input/Input/Input.css +1 -1
  2. package/es/index.css +1 -1
  3. package/es/stories/docs/ComponentDocsPage.js +234 -0
  4. package/es/stories/docs/componentDocMeta.js +97 -0
  5. package/es/stories/docs/storybook-docs.css +79 -0
  6. package/lib/components/Input/Input/Input.css +1 -1
  7. package/lib/index.css +1 -1
  8. package/lib/stories/docs/ComponentDocsPage.js +244 -0
  9. package/lib/stories/docs/componentDocMeta.js +104 -0
  10. package/lib/stories/docs/storybook-docs.css +79 -0
  11. package/package.json +23 -8
  12. package/scripts/mcp-server/README.md +267 -0
  13. package/scripts/mcp-server/bin.mjs +2 -0
  14. package/scripts/mcp-server/drift.json +5 -0
  15. package/scripts/mcp-server/examples.generated.json +2651 -0
  16. package/scripts/mcp-server/index.generated.json +18098 -0
  17. package/scripts/mcp-server/index.mjs +308 -26
  18. package/scripts/mcp-server/tools/get-examples.mjs +125 -0
  19. package/scripts/mcp-server/tools/get-library-info.mjs +25 -0
  20. package/scripts/mcp-server/tools/get-symbol.mjs +232 -0
  21. package/scripts/mcp-server/tools/get-token.mjs +60 -0
  22. package/scripts/mcp-server/tools/list-icons.mjs +38 -0
  23. package/scripts/mcp-server/tools/list-symbols.mjs +46 -0
  24. package/scripts/mcp-server/tools/resolve-import.mjs +125 -0
  25. package/scripts/mcp-server/tools/search-symbols.mjs +79 -0
  26. package/.agents/skills/1money-component-dev/SKILL.md +0 -224
  27. package/.agents/skills/1money-component-dev/checklist.md +0 -159
  28. package/.agents/skills/1money-component-dev/references/ComponentPatterns.md +0 -478
  29. package/.agents/skills/1money-component-dev/references/FigmaExtractionChecklist.md +0 -144
  30. package/.agents/skills/1money-component-dev/references/HooksGuide.md +0 -360
  31. package/.agents/skills/1money-component-dev/references/SemanticColors.md +0 -215
  32. package/.agents/skills/1money-component-dev/references/StyleSystemAPI.md +0 -389
  33. package/.claude/settings.local.json +0 -111
  34. package/.claude/skills/1money-component-dev/SKILL.md +0 -229
  35. package/.claude/skills/1money-component-dev/checklist.md +0 -159
  36. package/.claude/skills/1money-component-dev/references/ComponentPatterns.md +0 -478
  37. package/.claude/skills/1money-component-dev/references/FigmaExtractionChecklist.md +0 -144
  38. package/.claude/skills/1money-component-dev/references/HooksGuide.md +0 -360
  39. package/.claude/skills/1money-component-dev/references/SemanticColors.md +0 -215
  40. package/.claude/skills/1money-component-dev/references/StyleSystemAPI.md +0 -389
  41. package/.claude/skills/1money-component-review/SKILL.md +0 -316
  42. package/.claude/skills/component-pipeline/SKILL.md +0 -116
  43. package/.claude/skills/component-pipeline/checklist.md +0 -125
  44. package/.hintrc +0 -13
  45. package/@types/global.d.ts +0 -28
  46. package/AGENTS.md +0 -546
  47. package/CLAUDE.md +0 -1
  48. package/jest.setup.d.ts +0 -1
  49. package/jest.setup.ts +0 -1
  50. package/patches/primereact.patch +0 -323
  51. package/patches/react-pro-sidebar.patch +0 -6421
  52. package/public/favicon.ico +0 -0
  53. package/public/fonts/Aeonik/Aeonik-Air.ttf +0 -0
  54. package/public/fonts/Aeonik/Aeonik-AirItalic.ttf +0 -0
  55. package/public/fonts/Aeonik/Aeonik-Black.ttf +0 -0
  56. package/public/fonts/Aeonik/Aeonik-BlackItalic.ttf +0 -0
  57. package/public/fonts/Aeonik/Aeonik-Bold.ttf +0 -0
  58. package/public/fonts/Aeonik/Aeonik-BoldItalic.ttf +0 -0
  59. package/public/fonts/Aeonik/Aeonik-Light.ttf +0 -0
  60. package/public/fonts/Aeonik/Aeonik-LightItalic.ttf +0 -0
  61. package/public/fonts/Aeonik/Aeonik-Medium.ttf +0 -0
  62. package/public/fonts/Aeonik/Aeonik-MediumItalic.ttf +0 -0
  63. package/public/fonts/Aeonik/Aeonik-Regular.ttf +0 -0
  64. package/public/fonts/Aeonik/Aeonik-RegularItalic.ttf +0 -0
  65. package/public/fonts/Aeonik/Aeonik-Thin.ttf +0 -0
  66. package/public/fonts/Aeonik/Aeonik-ThinItalic.ttf +0 -0
  67. package/public/fonts/Inter/Inter-Black.ttf +0 -0
  68. package/public/fonts/Inter/Inter-BlackItalic.ttf +0 -0
  69. package/public/fonts/Inter/Inter-Bold.ttf +0 -0
  70. package/public/fonts/Inter/Inter-BoldItalic.ttf +0 -0
  71. package/public/fonts/Inter/Inter-ExtraBold.ttf +0 -0
  72. package/public/fonts/Inter/Inter-ExtraBoldItalic.ttf +0 -0
  73. package/public/fonts/Inter/Inter-ExtraLight.ttf +0 -0
  74. package/public/fonts/Inter/Inter-ExtraLightItalic.ttf +0 -0
  75. package/public/fonts/Inter/Inter-Italic.ttf +0 -0
  76. package/public/fonts/Inter/Inter-Light.ttf +0 -0
  77. package/public/fonts/Inter/Inter-LightItalic.ttf +0 -0
  78. package/public/fonts/Inter/Inter-Medium.ttf +0 -0
  79. package/public/fonts/Inter/Inter-MediumItalic.ttf +0 -0
  80. package/public/fonts/Inter/Inter-Regular.ttf +0 -0
  81. package/public/fonts/Inter/Inter-SemiBold.ttf +0 -0
  82. package/public/fonts/Inter/Inter-SemiBoldItalic.ttf +0 -0
  83. package/public/fonts/Inter/Inter-Thin.ttf +0 -0
  84. package/public/fonts/Inter/Inter-ThinItalic.ttf +0 -0
  85. package/public/fonts/Outfit/Outfit-Black.ttf +0 -0
  86. package/public/fonts/Outfit/Outfit-Bold.ttf +0 -0
  87. package/public/fonts/Outfit/Outfit-ExtraBold.ttf +0 -0
  88. package/public/fonts/Outfit/Outfit-ExtraLight.ttf +0 -0
  89. package/public/fonts/Outfit/Outfit-Light.ttf +0 -0
  90. package/public/fonts/Outfit/Outfit-Medium.ttf +0 -0
  91. package/public/fonts/Outfit/Outfit-Regular.ttf +0 -0
  92. package/public/fonts/Outfit/Outfit-SemiBold.ttf +0 -0
  93. package/public/fonts/Outfit/Outfit-Thin.ttf +0 -0
  94. package/public/github-mark.svg +0 -3
  95. package/public/tokens/GYEN.svg +0 -9
  96. package/public/tokens/PYUSD.svg +0 -9
  97. package/public/tokens/USDT.svg +0 -6
  98. package/scripts/mcp-server/resources.d.mts +0 -1
  99. package/scripts/mcp-server/resources.mjs +0 -102
  100. package/test/jsdom-global-register.d.ts +0 -1
  101. package/test/jsdom-global-register.js +0 -1
@@ -1,45 +1,327 @@
1
1
  /* eslint-disable no-undef */
2
2
  /* eslint-env node */
3
+ /**
4
+ * 1money-react-ui MCP stdio server.
5
+ *
6
+ * Loads the committed `index.generated.json`, `drift.json`, and `package.json`
7
+ * at startup (never on per-request basis) and serves 8 MCP tools over a
8
+ * stdio transport.
9
+ *
10
+ * Use `node scripts/mcp-server/index.mjs --selftest` to run each handler
11
+ * with a canned input — useful for smoke-testing without a real MCP client.
12
+ */
13
+
3
14
  import process from 'node:process';
4
- import { createServer } from 'node:http';
5
- import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
6
- import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
7
- import { registerComponentResources } from './resources.mjs';
15
+ import path from 'node:path';
16
+ import fs from 'node:fs/promises';
17
+ import { fileURLToPath } from 'node:url';
18
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
19
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
20
+ import {
21
+ ListToolsRequestSchema,
22
+ CallToolRequestSchema
23
+ } from '@modelcontextprotocol/sdk/types.js';
8
24
 
9
- async function main() {
10
- const host = process.env.MCP_HOST || '127.0.0.1';
11
- const port = Number(process.env.MCP_PORT || 8686);
25
+ import listSymbols from './tools/list-symbols.mjs';
26
+ import searchSymbols from './tools/search-symbols.mjs';
27
+ import getSymbol from './tools/get-symbol.mjs';
28
+ import getExamples from './tools/get-examples.mjs';
29
+ import listIcons from './tools/list-icons.mjs';
30
+ import getToken from './tools/get-token.mjs';
31
+ import resolveImport from './tools/resolve-import.mjs';
32
+ import getLibraryInfo from './tools/get-library-info.mjs';
12
33
 
13
- const server = new McpServer({
14
- name: '1money-react-ui',
15
- version: '0.1.0'
16
- });
34
+ const EXPECTED_SCHEMA_VERSION = '1';
35
+ const SERVER_NAME = '1money-react-ui';
36
+ const SERVER_VERSION = '0.1.0';
37
+
38
+ const __filename = fileURLToPath(import.meta.url);
39
+ const __dirname = path.dirname(__filename);
40
+ const repoRoot = path.resolve(__dirname, '..', '..');
41
+ const indexPath = path.join(__dirname, 'index.generated.json');
42
+ const driftPath = path.join(__dirname, 'drift.json');
43
+ const examplesPath = path.join(__dirname, 'examples.generated.json');
44
+ const pkgPath = path.join(repoRoot, 'package.json');
45
+
46
+ /**
47
+ * Tool catalog — exposed to clients via tools/list. Input schemas are plain
48
+ * JSON Schema (not Zod) so we don't take a hard dep on zod here; the server
49
+ * routes to plain JS handlers below that do their own manual validation.
50
+ */
51
+ const TOOL_CATALOG = [
52
+ {
53
+ name: 'list_symbols',
54
+ description:
55
+ 'List top-level exported symbols (components, modules, hooks, types). Namespace roots (ProForm, Icons, Input) surface as kind=module.',
56
+ inputSchema: {
57
+ type: 'object',
58
+ properties: {
59
+ kind: {
60
+ type: 'string',
61
+ enum: ['component', 'module', 'hook', 'function', 'type', 'all'],
62
+ default: 'all',
63
+ description: 'Filter by symbol kind. Use "all" to include every kind.'
64
+ },
65
+ category: {
66
+ type: 'string',
67
+ description: 'Optional category filter (e.g., "input", "display").'
68
+ }
69
+ },
70
+ additionalProperties: false
71
+ },
72
+ handler: listSymbols
73
+ },
74
+ {
75
+ name: 'search_symbols',
76
+ description:
77
+ 'Fuzzy search over the symbol index. Searches name, aliases (searchTags), summary, and prop names.',
78
+ inputSchema: {
79
+ type: 'object',
80
+ properties: {
81
+ query: { type: 'string', description: 'Search term.' },
82
+ limit: { type: 'integer', minimum: 1, default: 5 }
83
+ },
84
+ required: ['query'],
85
+ additionalProperties: false
86
+ },
87
+ handler: searchSymbols
88
+ },
89
+ {
90
+ name: 'get_symbol',
91
+ description:
92
+ 'Fetch a detailed symbol record. Accepts both flat names (e.g., "ProFormItem") and dotted paths (e.g., "ProForm.Item"). Returns { kind: "not_exported", hint } when the name cannot be resolved.',
93
+ inputSchema: {
94
+ type: 'object',
95
+ properties: {
96
+ name: { type: 'string', description: 'Flat or dotted symbol name.' },
97
+ include: {
98
+ type: 'array',
99
+ items: { enum: ['props', 'examples', 'members', 'notes', 'related'] },
100
+ default: ['props', 'members']
101
+ }
102
+ },
103
+ required: ['name'],
104
+ additionalProperties: false
105
+ },
106
+ handler: getSymbol
107
+ },
108
+ {
109
+ name: 'get_examples',
110
+ description:
111
+ 'Fetch curated usage examples for a symbol. Sources: README fenced blocks, Storybook `render` bodies, and canonical snippets. Each entry carries a compilable flag.',
112
+ inputSchema: {
113
+ type: 'object',
114
+ properties: {
115
+ name: { type: 'string' },
116
+ limit: { type: 'integer', minimum: 1, default: 3 },
117
+ source: {
118
+ type: 'string',
119
+ enum: ['all', 'readme', 'stories', 'canonical'],
120
+ default: 'all'
121
+ }
122
+ },
123
+ required: ['name'],
124
+ additionalProperties: false
125
+ },
126
+ handler: getExamples
127
+ },
128
+ {
129
+ name: 'list_icons',
130
+ description:
131
+ 'List icon names for the <Icons /> component. Optionally filter by case-insensitive substring.',
132
+ inputSchema: {
133
+ type: 'object',
134
+ properties: {
135
+ query: { type: 'string' },
136
+ limit: { type: 'integer', minimum: 1 }
137
+ },
138
+ additionalProperties: false
139
+ },
140
+ handler: listIcons
141
+ },
142
+ {
143
+ name: 'get_token',
144
+ description:
145
+ 'Query design tokens by name, kind, or name prefix. Filters combine with AND semantics.',
146
+ inputSchema: {
147
+ type: 'object',
148
+ properties: {
149
+ name: { type: 'string' },
150
+ kind: {
151
+ type: 'string',
152
+ enum: [
153
+ 'color',
154
+ 'spacing',
155
+ 'radius',
156
+ 'shadow',
157
+ 'sizing',
158
+ 'opacity',
159
+ 'typography',
160
+ 'breakpoint'
161
+ ]
162
+ },
163
+ prefix: { type: 'string' }
164
+ },
165
+ additionalProperties: false
166
+ },
167
+ handler: getToken
168
+ },
169
+ {
170
+ name: 'resolve_import',
171
+ description:
172
+ 'Resolve how to import a symbol. Supports flat names and namespace-member paths (e.g., "ProForm.Item"). Rejects Icons.<Name> with a clear hint.',
173
+ inputSchema: {
174
+ type: 'object',
175
+ properties: {
176
+ symbol: { type: 'string' }
177
+ },
178
+ required: ['symbol'],
179
+ additionalProperties: false
180
+ },
181
+ handler: resolveImport
182
+ },
183
+ {
184
+ name: 'get_library_info',
185
+ description:
186
+ 'Return package metadata: name, version, peer deps, available subpath exports, CSS entry, and schema version.',
187
+ inputSchema: {
188
+ type: 'object',
189
+ properties: {},
190
+ additionalProperties: false
191
+ },
192
+ handler: getLibraryInfo
193
+ }
194
+ ];
195
+
196
+ async function loadContext() {
197
+ const [indexRaw, driftRaw, examplesRaw, pkgRaw] = await Promise.all([
198
+ fs.readFile(indexPath, 'utf8'),
199
+ fs.readFile(driftPath, 'utf8'),
200
+ fs.readFile(examplesPath, 'utf8'),
201
+ fs.readFile(pkgPath, 'utf8')
202
+ ]);
203
+
204
+ const index = JSON.parse(indexRaw);
205
+ const drift = JSON.parse(driftRaw);
206
+ const examplesIndex = JSON.parse(examplesRaw);
207
+ const pkg = JSON.parse(pkgRaw);
208
+
209
+ if (index.schemaVersion !== EXPECTED_SCHEMA_VERSION) {
210
+ console.error(
211
+ `[mcp] schemaVersion mismatch: expected '${EXPECTED_SCHEMA_VERSION}', got '${index.schemaVersion}'. ` +
212
+ 'Regenerate index.generated.json with `pnpm build:mcp-index` and ensure the indexer produces the expected schemaVersion.'
213
+ );
214
+ process.exit(1);
215
+ }
216
+
217
+ if (examplesIndex.schemaVersion !== EXPECTED_SCHEMA_VERSION) {
218
+ console.error(
219
+ `[mcp] schemaVersion mismatch in examples.generated.json: expected '${EXPECTED_SCHEMA_VERSION}', got '${examplesIndex.schemaVersion}'. ` +
220
+ 'Regenerate with `pnpm build:mcp-index`.'
221
+ );
222
+ process.exit(1);
223
+ }
224
+
225
+ return { index, drift, examplesIndex, pkg };
226
+ }
227
+
228
+ function toToolResult(value) {
229
+ return {
230
+ content: [{ type: 'text', text: JSON.stringify(value, null, 2) }],
231
+ structuredContent: value
232
+ };
233
+ }
17
234
 
18
- console.info('[mcp] Starting 1money-react-ui MCP server...');
235
+ function toToolError(message) {
236
+ return {
237
+ content: [{ type: 'text', text: message }],
238
+ isError: true
239
+ };
240
+ }
241
+
242
+ function findTool(name) {
243
+ return TOOL_CATALOG.find(t => t.name === name);
244
+ }
19
245
 
20
- const registeredCount = await registerComponentResources(server);
21
- console.info(`[mcp] Registered ${registeredCount} component resources from src/components`);
246
+ async function runTool(name, rawInput, ctx) {
247
+ const tool = findTool(name);
248
+ if (!tool) {
249
+ throw new Error(`Unknown tool: ${name}`);
250
+ }
251
+ return Promise.resolve(tool.handler(rawInput ?? {}, ctx));
252
+ }
22
253
 
23
- const transport = new StreamableHTTPServerTransport();
24
- console.info(`[mcp] Binding HTTP transport on http://${host}:${port}/mcp`);
254
+ async function runSelfTest(ctx) {
255
+ const cannedInputs = {
256
+ list_symbols: { kind: 'component' },
257
+ search_symbols: { query: 'button', limit: 3 },
258
+ get_symbol: { name: 'ProForm.Item' },
259
+ get_examples: { name: 'Button' },
260
+ list_icons: { query: 'chevron', limit: 5 },
261
+ get_token: { kind: 'breakpoint' },
262
+ resolve_import: { symbol: 'ProForm.Item' },
263
+ get_library_info: {}
264
+ };
25
265
 
26
- const httpServer = createServer(async (req, res) => {
266
+ const results = [];
267
+ for (const tool of TOOL_CATALOG) {
268
+ const input = cannedInputs[tool.name] ?? {};
27
269
  try {
28
- await transport.handleRequest(req, res);
29
- } catch (error) {
30
- console.error('[mcp] HTTP handler error:', error);
31
- res.statusCode = 500;
32
- res.end('Internal MCP server error');
270
+ const output = await runTool(tool.name, input, ctx);
271
+ results.push({ name: tool.name, ok: true, output });
272
+ } catch (err) {
273
+ results.push({ name: tool.name, ok: false, error: err.message });
274
+ }
275
+ }
276
+
277
+ process.stdout.write(JSON.stringify({ selftest: true, toolCount: results.length, results }, null, 2) + '\n');
278
+ const anyFailed = results.some(r => !r.ok);
279
+ process.exit(anyFailed ? 1 : 0);
280
+ }
281
+
282
+ async function startStdioServer(ctx) {
283
+ const server = new Server(
284
+ { name: SERVER_NAME, version: SERVER_VERSION },
285
+ { capabilities: { tools: {} } }
286
+ );
287
+
288
+ server.setRequestHandler(ListToolsRequestSchema, () => ({
289
+ tools: TOOL_CATALOG.map(({ name, description, inputSchema }) => ({
290
+ name,
291
+ description,
292
+ inputSchema
293
+ }))
294
+ }));
295
+
296
+ server.setRequestHandler(CallToolRequestSchema, async request => {
297
+ const { name, arguments: args } = request.params;
298
+ try {
299
+ const output = await runTool(name, args ?? {}, ctx);
300
+ return toToolResult(output);
301
+ } catch (err) {
302
+ const message = err instanceof Error ? err.message : String(err);
303
+ return toToolError(message);
33
304
  }
34
305
  });
35
306
 
307
+ const transport = new StdioServerTransport();
36
308
  await server.connect(transport);
309
+ console.error(
310
+ `[mcp] ${SERVER_NAME} v${SERVER_VERSION} listening on stdio (tools: ${TOOL_CATALOG.length})`
311
+ );
312
+ }
37
313
 
38
- await new Promise(resolve => httpServer.listen(port, host, resolve));
39
- console.info('[mcp] Server ready at http://%s:%d/mcp', host, port);
314
+ async function main() {
315
+ const argv = process.argv.slice(2);
316
+ const ctx = await loadContext();
317
+ if (argv.includes('--selftest')) {
318
+ await runSelfTest(ctx);
319
+ return;
320
+ }
321
+ await startStdioServer(ctx);
40
322
  }
41
323
 
42
- main().catch(error => {
43
- console.error('[mcp] Fatal error:', error);
324
+ main().catch(err => {
325
+ console.error('[mcp] Fatal error:', err);
44
326
  process.exit(1);
45
327
  });
@@ -0,0 +1,125 @@
1
+ /* eslint-disable no-undef */
2
+ /* eslint-env node */
3
+ /**
4
+ * Tool: get_examples
5
+ *
6
+ * Returns curated usage examples for a symbol.
7
+ *
8
+ * Input: { name, limit = 3, source = 'all' }
9
+ * Output: { examples: [{ title, code, source, compilable }] }
10
+ *
11
+ * Name resolution mirrors `get_symbol`:
12
+ * - dotted paths (`ProForm.Item`) resolve through a module's memberMap
13
+ * - flat names (`Button`) resolve directly
14
+ * - unknown names return `{ examples: [], note, hint }`
15
+ *
16
+ * The example bodies live in `examples.generated.json` (content-hashed). The
17
+ * per-symbol references (in `symbol.examples`) are hydrated against that
18
+ * payload at request time.
19
+ */
20
+
21
+ const VALID_SOURCES = ['all', 'readme', 'stories', 'canonical'];
22
+ const DEFAULT_LIMIT = 3;
23
+ const LOCAL_PREFIX = '$local:';
24
+
25
+ function validateInput(input) {
26
+ const args = input && typeof input === 'object' ? input : {};
27
+ if (typeof args.name !== 'string' || args.name.trim().length === 0) {
28
+ throw new Error('get_examples: `name` must be a non-empty string');
29
+ }
30
+ const source = args.source ?? 'all';
31
+ if (!VALID_SOURCES.includes(source)) {
32
+ throw new Error(
33
+ `get_examples: invalid source '${source}', expected one of ${VALID_SOURCES.join(', ')}`,
34
+ );
35
+ }
36
+ const limit =
37
+ typeof args.limit === 'number' && Number.isFinite(args.limit) && args.limit > 0
38
+ ? Math.floor(args.limit)
39
+ : DEFAULT_LIMIT;
40
+ return { name: args.name.trim(), source, limit };
41
+ }
42
+
43
+ function buildByName(index) {
44
+ const byName = new Map();
45
+ for (const sym of index.symbols) {
46
+ byName.set(sym.name, sym);
47
+ }
48
+ return byName;
49
+ }
50
+
51
+ /** Resolve a dotted-path lookup against a module's memberMap. */
52
+ function resolveDotted(inputName, byName) {
53
+ const dotIdx = inputName.indexOf('.');
54
+ const ownerName = inputName.slice(0, dotIdx);
55
+ const memberKey = inputName.slice(dotIdx + 1);
56
+ const owner = byName.get(ownerName);
57
+ if (!owner || owner.kind !== 'module' || !owner.memberMap) return null;
58
+ const target = owner.memberMap[memberKey];
59
+ if (typeof target !== 'string') return null;
60
+ if (target.startsWith(LOCAL_PREFIX)) {
61
+ return { internal: true, ownerName };
62
+ }
63
+ return byName.get(target) ?? null;
64
+ }
65
+
66
+ function hintForMissing(name) {
67
+ if (/^Icons\.[A-Z]/.test(name)) {
68
+ return 'Icon names are string keys, not exported symbols. Use `<Icons name="chevronDown" />` (camelCase) and call `list_icons` for names.';
69
+ }
70
+ if (/^use[A-Z]/.test(name)) {
71
+ return 'This hook may live in `@1money/hooks`, not `@1money/component-ui`. Check that package.';
72
+ }
73
+ return `No exported symbol named '${name}'. Use search_symbols to discover candidates.`;
74
+ }
75
+
76
+ export default function getExamples(input, ctx) {
77
+ const { name, source, limit } = validateInput(input);
78
+ const { index, examplesIndex } = ctx ?? {};
79
+ if (!index || !Array.isArray(index.symbols)) {
80
+ throw new Error('get_examples: context missing `index`');
81
+ }
82
+ if (!examplesIndex || typeof examplesIndex.examples !== 'object') {
83
+ throw new Error('get_examples: context missing `examplesIndex`');
84
+ }
85
+
86
+ const byName = buildByName(index);
87
+
88
+ let sym = null;
89
+ if (name.includes('.')) {
90
+ const resolved = resolveDotted(name, byName);
91
+ if (resolved && resolved.internal) {
92
+ return {
93
+ examples: [],
94
+ note: `'${name}' is an internal member of '${resolved.ownerName}'; not separately exported.`,
95
+ };
96
+ }
97
+ sym = resolved ?? null;
98
+ } else {
99
+ sym = byName.get(name) ?? null;
100
+ }
101
+
102
+ if (!sym) {
103
+ return { examples: [], note: hintForMissing(name) };
104
+ }
105
+
106
+ const refs = Array.isArray(sym.examples) ? sym.examples : [];
107
+ const filtered =
108
+ source === 'all' ? refs : refs.filter(r => r && r.source === source);
109
+
110
+ const hydrated = [];
111
+ for (const ref of filtered) {
112
+ if (!ref || typeof ref.hash !== 'string') continue;
113
+ const body = examplesIndex.examples[ref.hash];
114
+ if (!body) continue;
115
+ hydrated.push({
116
+ title: body.title,
117
+ code: body.code,
118
+ source: body.source,
119
+ compilable: body.compilable,
120
+ });
121
+ if (hydrated.length >= limit) break;
122
+ }
123
+
124
+ return { examples: hydrated };
125
+ }
@@ -0,0 +1,25 @@
1
+ /* eslint-disable no-undef */
2
+ /* eslint-env node */
3
+ /**
4
+ * Tool: get_library_info
5
+ *
6
+ * Returns package metadata loaded at server startup (never per-request).
7
+ */
8
+
9
+ export default function getLibraryInfo(_input, ctx) {
10
+ const { index, pkg } = ctx;
11
+
12
+ const exportsMap = (pkg && typeof pkg.exports === 'object' && pkg.exports) || {};
13
+ const subpathExports = Object.keys(exportsMap)
14
+ .filter(key => key !== '.' && key !== './index.css')
15
+ .sort();
16
+
17
+ return {
18
+ name: pkg?.name ?? null,
19
+ version: pkg?.version ?? null,
20
+ peerDependencies: pkg?.peerDependencies ?? {},
21
+ subpathExports,
22
+ cssEntry: '@1money/component-ui/index.css',
23
+ schemaVersion: index?.schemaVersion ?? null
24
+ };
25
+ }