conductor-figma 0.1.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.
@@ -0,0 +1,292 @@
1
+ // ═══════════════════════════════════════════
2
+ // CONDUCTOR — Tool Registry
3
+ // ═══════════════════════════════════════════
4
+ // All 61 MCP tools, organized by category.
5
+ // Each tool has: name, description, category, inputSchema, handler reference.
6
+
7
+ export const CATEGORIES = {
8
+ create: { label: 'Create', icon: '⊞', count: 8 },
9
+ layout: { label: 'Layout', icon: '▤', count: 7 },
10
+ typography: { label: 'Typography', icon: '◆', count: 6 },
11
+ color: { label: 'Color & Style', icon: '◑', count: 7 },
12
+ components: { label: 'Components', icon: '◎', count: 6 },
13
+ spacing: { label: 'Spacing & Grid', icon: '◧', count: 6 },
14
+ audit: { label: 'Audit & Critique', icon: '◉', count: 6 },
15
+ accessibility:{ label: 'Accessibility', icon: '♿', count: 5 },
16
+ responsive: { label: 'Responsive', icon: '↔', count: 4 },
17
+ export: { label: 'Export & Handoff', icon: '⤓', count: 6 },
18
+ };
19
+
20
+ function str(desc) { return { type: 'string', description: desc }; }
21
+ function num(desc) { return { type: 'number', description: desc }; }
22
+ function bool(desc) { return { type: 'boolean', description: desc }; }
23
+ function arr(desc, items) { return { type: 'array', description: desc, items: items || { type: 'string' } }; }
24
+ function opt(schema) { return { ...schema, optional: true }; }
25
+
26
+ export const TOOLS = [
27
+ // ═══ CREATE ═══
28
+ { name: 'create_frame', category: 'create',
29
+ description: 'Create an auto-layout frame with grid-aligned spacing, proper padding, and constraints.',
30
+ inputSchema: { type: 'object', properties: { name: str('Frame name'), width: opt(num('Width')), height: opt(num('Height')), direction: opt(str('horizontal or vertical')), padding: opt(num('Padding (snapped to grid)')), gap: opt(num('Gap (snapped to grid)')), fill: opt(str('Background color hex')) }, required: ['name'] } },
31
+
32
+ { name: 'create_page', category: 'create',
33
+ description: 'Create a full page from intent: landing, pricing, dashboard, settings, auth. Generates proper section hierarchy with auto-layout.',
34
+ inputSchema: { type: 'object', properties: { pageType: str('Page type: landing, pricing, dashboard, settings, auth, blog, portfolio, docs'), title: opt(str('Page title')), sections: opt(arr('Section types to include')), brandColor: opt(str('Primary brand color hex')), darkMode: opt(bool('Generate dark mode variant')) }, required: ['pageType'] } },
35
+
36
+ { name: 'create_section', category: 'create',
37
+ description: 'Create a page section: hero, features, testimonials, FAQ, CTA, pricing, stats, team. Pattern-aware with proper hierarchy.',
38
+ inputSchema: { type: 'object', properties: { sectionType: str('Section type: hero, features, testimonials, faq, cta, pricing, stats, team, footer, header'), heading: opt(str('Section heading')), content: opt(str('Content description')), columns: opt(num('Number of columns for grid sections')) }, required: ['sectionType'] } },
39
+
40
+ { name: 'create_card', category: 'create',
41
+ description: 'Create a card with proper padding, radius, shadow depth, and content hierarchy.',
42
+ inputSchema: { type: 'object', properties: { variant: opt(str('Card variant: default, elevated, outlined, filled')), title: opt(str('Card title')), description: opt(str('Card description')), hasImage: opt(bool('Include image placeholder')), hasAction: opt(bool('Include action button')), width: opt(num('Card width')) }, required: [] } },
43
+
44
+ { name: 'create_form', category: 'create',
45
+ description: 'Create a form layout with labels, inputs, validation states, help text, and submit flow.',
46
+ inputSchema: { type: 'object', properties: { fields: arr('Field definitions', { type: 'object', properties: { name: str('Field name'), type: str('text, email, password, select, textarea, checkbox, radio'), label: str('Field label'), required: bool('Required field') } }), submitLabel: opt(str('Submit button text')), layout: opt(str('vertical or horizontal')) }, required: ['fields'] } },
47
+
48
+ { name: 'create_table', category: 'create',
49
+ description: 'Create a data table with header row, data rows, sorting indicators, and pagination controls.',
50
+ inputSchema: { type: 'object', properties: { columns: arr('Column definitions', { type: 'object', properties: { name: str('Column name'), width: num('Column width') } }), rows: opt(num('Number of data rows')), hasPagination: opt(bool('Include pagination')), hasSorting: opt(bool('Include sort indicators')), hasCheckbox: opt(bool('Include row checkboxes')) }, required: ['columns'] } },
51
+
52
+ { name: 'create_modal', category: 'create',
53
+ description: 'Create a modal with overlay, header, content area, and action buttons. Proper sizing and constraints.',
54
+ inputSchema: { type: 'object', properties: { title: str('Modal title'), size: opt(str('sm, md, lg, xl')), hasCloseButton: opt(bool('Include close button')), actions: opt(arr('Action button labels')) }, required: ['title'] } },
55
+
56
+ { name: 'create_nav', category: 'create',
57
+ description: 'Create navigation: topbar, sidebar, breadcrumbs, or tabs. Includes active states and responsive structure.',
58
+ inputSchema: { type: 'object', properties: { navType: str('topbar, sidebar, breadcrumbs, tabs, bottom-nav'), items: arr('Navigation items'), logoText: opt(str('Logo text')), hasSearch: opt(bool('Include search')), hasAvatar: opt(bool('Include user avatar')) }, required: ['navType', 'items'] } },
59
+
60
+ // ═══ LAYOUT ═══
61
+ { name: 'layout_auto', category: 'layout',
62
+ description: 'Convert any frame to auto-layout with inferred direction, gap, and padding. Removes absolute positioning.',
63
+ inputSchema: { type: 'object', properties: { nodeId: str('Figma node ID to convert'), direction: opt(str('horizontal or vertical (auto-detected if omitted)')), gap: opt(num('Gap in px (auto-detected if omitted)')), padding: opt(num('Padding in px')) }, required: ['nodeId'] } },
64
+
65
+ { name: 'layout_grid', category: 'layout',
66
+ description: 'Apply a column grid to a frame: 12-col, 8-col, or custom with gutters and margins.',
67
+ inputSchema: { type: 'object', properties: { nodeId: str('Figma node ID'), columns: opt(num('Number of columns (default 12)')), gutter: opt(num('Gutter width')), margin: opt(num('Outer margin')), type: opt(str('stretch, center, left, right')) }, required: ['nodeId'] } },
68
+
69
+ { name: 'layout_stack', category: 'layout',
70
+ description: 'Stack children vertically or horizontally with consistent grid-aligned spacing.',
71
+ inputSchema: { type: 'object', properties: { nodeId: str('Parent node ID'), direction: str('horizontal or vertical'), gap: opt(num('Gap (snapped to grid)')), align: opt(str('start, center, end, stretch')) }, required: ['nodeId', 'direction'] } },
72
+
73
+ { name: 'layout_wrap', category: 'layout',
74
+ description: 'Create a wrap-layout for tag clouds, pill groups, or flexible card grids.',
75
+ inputSchema: { type: 'object', properties: { nodeId: str('Parent node ID'), gap: opt(num('Gap between items')), maxWidth: opt(num('Max width before wrapping')) }, required: ['nodeId'] } },
76
+
77
+ { name: 'layout_constrain', category: 'layout',
78
+ description: 'Set responsive constraints on a frame: fill, hug, fixed, min/max width and height.',
79
+ inputSchema: { type: 'object', properties: { nodeId: str('Node ID'), horizontal: opt(str('fill, hug, fixed')), vertical: opt(str('fill, hug, fixed')), minWidth: opt(num('Min width')), maxWidth: opt(num('Max width')), minHeight: opt(num('Min height')), maxHeight: opt(num('Max height')) }, required: ['nodeId'] } },
80
+
81
+ { name: 'layout_align', category: 'layout',
82
+ description: 'Align and distribute selected frames on the grid. Handles both alignment and even distribution.',
83
+ inputSchema: { type: 'object', properties: { nodeIds: arr('Node IDs to align'), alignment: str('left, center, right, top, middle, bottom, distribute-h, distribute-v') }, required: ['nodeIds', 'alignment'] } },
84
+
85
+ { name: 'layout_nest', category: 'layout',
86
+ description: 'Restructure flat, absolute-positioned layers into a proper auto-layout tree based on spatial relationships.',
87
+ inputSchema: { type: 'object', properties: { nodeId: str('Parent frame to restructure'), depth: opt(num('Max nesting depth (default 3)')) }, required: ['nodeId'] } },
88
+
89
+ // ═══ TYPOGRAPHY ═══
90
+ { name: 'type_scale', category: 'typography',
91
+ description: 'Generate or detect a type scale. Supports minor third (1.2), major third (1.25), perfect fourth (1.333), and more.',
92
+ inputSchema: { type: 'object', properties: { action: str('generate or detect'), baseSize: opt(num('Base font size (default 16)')), scaleRatio: opt(str('Scale name: minor-third, major-third, perfect-fourth, etc.')), nodeId: opt(str('Node ID to detect scale from')) }, required: ['action'] } },
93
+
94
+ { name: 'type_hierarchy', category: 'typography',
95
+ description: 'Set heading levels with proper size, weight, and line-height ratios across a frame.',
96
+ inputSchema: { type: 'object', properties: { nodeId: str('Frame to apply hierarchy to'), levels: opt(num('Number of heading levels (default 4)')), baseSize: opt(num('Body text size')) }, required: ['nodeId'] } },
97
+
98
+ { name: 'type_pair', category: 'typography',
99
+ description: 'Suggest font pairings from loaded fonts or recommend Google Fonts combinations.',
100
+ inputSchema: { type: 'object', properties: { headingFont: opt(str('Heading font family')), bodyFont: opt(str('Body font family')), style: opt(str('modern, classic, technical, editorial, playful')) }, required: [] } },
101
+
102
+ { name: 'type_measure', category: 'typography',
103
+ description: 'Check line length (45-75 chars optimal), line-height ratios, and letter-spacing for readability.',
104
+ inputSchema: { type: 'object', properties: { nodeId: str('Text node or frame to check') }, required: ['nodeId'] } },
105
+
106
+ { name: 'type_apply', category: 'typography',
107
+ description: 'Apply text styles consistently to all matching text elements across frames.',
108
+ inputSchema: { type: 'object', properties: { nodeId: str('Root frame'), styles: { type: 'object', description: 'Text styles to apply by element type' } }, required: ['nodeId'] } },
109
+
110
+ { name: 'type_audit', category: 'typography',
111
+ description: 'Find every unique text style in a page. Flag off-scale sizes, inconsistent weights, and orphaned styles.',
112
+ inputSchema: { type: 'object', properties: { nodeId: str('Frame or page to audit') }, required: ['nodeId'] } },
113
+
114
+ // ═══ COLOR & STYLE ═══
115
+ { name: 'color_palette', category: 'color',
116
+ description: 'Generate a full color palette (50-950 shades) from a single brand color.',
117
+ inputSchema: { type: 'object', properties: { baseColor: str('Brand color hex'), steps: opt(arr('Shade steps', { type: 'number' })) }, required: ['baseColor'] } },
118
+
119
+ { name: 'color_semantic', category: 'color',
120
+ description: 'Create semantic color tokens: surface, text, border, accent, danger, success, warning, info.',
121
+ inputSchema: { type: 'object', properties: { brandColor: str('Primary brand color hex') }, required: ['brandColor'] } },
122
+
123
+ { name: 'color_darkmode', category: 'color',
124
+ description: 'Generate a dark mode variant of any frame or color set, preserving WCAG contrast ratios.',
125
+ inputSchema: { type: 'object', properties: { nodeId: opt(str('Frame to generate dark mode for')), colors: opt({ type: 'object', description: 'Color map to invert' }) }, required: [] } },
126
+
127
+ { name: 'color_contrast', category: 'color',
128
+ description: 'Check WCAG contrast for all text/background pairs in a frame. Reports AA and AAA compliance.',
129
+ inputSchema: { type: 'object', properties: { nodeId: opt(str('Frame to check')), foreground: opt(str('Foreground color hex')), background: opt(str('Background color hex')) }, required: [] } },
130
+
131
+ { name: 'color_apply', category: 'color',
132
+ description: 'Apply color styles to elements by semantic role: primary, secondary, muted, accent.',
133
+ inputSchema: { type: 'object', properties: { nodeId: str('Frame to apply colors to'), colorMap: { type: 'object', description: 'Role-to-color mapping' } }, required: ['nodeId'] } },
134
+
135
+ { name: 'style_shadow', category: 'color',
136
+ description: 'Generate an elevation/shadow system: sm, md, lg, xl, 2xl with consistent blur, spread, and opacity.',
137
+ inputSchema: { type: 'object', properties: { levels: opt(arr('Shadow levels to generate')), color: opt(str('Shadow color hex')) }, required: [] } },
138
+
139
+ { name: 'style_radius', category: 'color',
140
+ description: 'Generate and apply a consistent border-radius scale across all frames.',
141
+ inputSchema: { type: 'object', properties: { base: opt(num('Base radius (default 4)')), nodeId: opt(str('Frame to apply to')) }, required: [] } },
142
+
143
+ // ═══ COMPONENTS ═══
144
+ { name: 'component_list', category: 'components',
145
+ description: 'List all components in the current file or team library, with variant info.',
146
+ inputSchema: { type: 'object', properties: { source: opt(str('file or library')), filter: opt(str('Search filter')) }, required: [] } },
147
+
148
+ { name: 'component_use', category: 'components',
149
+ description: 'Instantiate a component by name with variant properties set.',
150
+ inputSchema: { type: 'object', properties: { componentName: str('Component to instantiate'), variants: opt({ type: 'object', description: 'Variant property values' }), x: opt(num('X position')), y: opt(num('Y position')) }, required: ['componentName'] } },
151
+
152
+ { name: 'component_create', category: 'components',
153
+ description: 'Create a new component from a frame with proper variant structure.',
154
+ inputSchema: { type: 'object', properties: { nodeId: str('Frame to convert to component'), name: str('Component name'), variants: opt(arr('Variant property definitions')) }, required: ['nodeId', 'name'] } },
155
+
156
+ { name: 'component_swap', category: 'components',
157
+ description: 'Swap one component instance for another across an entire frame tree.',
158
+ inputSchema: { type: 'object', properties: { nodeId: str('Root frame to search'), fromComponent: str('Component to replace'), toComponent: str('Component to replace with') }, required: ['nodeId', 'fromComponent', 'toComponent'] } },
159
+
160
+ { name: 'component_detach', category: 'components',
161
+ description: 'Detach component instances and flatten to editable frames.',
162
+ inputSchema: { type: 'object', properties: { nodeId: str('Instance or frame to detach') }, required: ['nodeId'] } },
163
+
164
+ { name: 'component_audit', category: 'components',
165
+ description: 'Find detached instances, missing components, unused variants, and inconsistent overrides.',
166
+ inputSchema: { type: 'object', properties: { nodeId: opt(str('Frame to audit (entire page if omitted)')) }, required: [] } },
167
+
168
+ // ═══ SPACING & GRID ═══
169
+ { name: 'spacing_scale', category: 'spacing',
170
+ description: 'Define a base spacing unit (4px or 8px) and generate the full scale.',
171
+ inputSchema: { type: 'object', properties: { base: opt(num('Base unit (default 8)')), steps: opt(num('Number of steps (default 12)')) }, required: [] } },
172
+
173
+ { name: 'spacing_fix', category: 'spacing',
174
+ description: 'Snap all off-grid spacing values in a frame to the nearest scale value.',
175
+ inputSchema: { type: 'object', properties: { nodeId: str('Frame to fix'), base: opt(num('Base unit (default 8)')) }, required: ['nodeId'] } },
176
+
177
+ { name: 'spacing_audit', category: 'spacing',
178
+ description: 'Report every spacing value in a frame: padding, margin, gap. Flag inconsistencies and off-grid values.',
179
+ inputSchema: { type: 'object', properties: { nodeId: str('Frame to audit'), base: opt(num('Base unit (default 8)')) }, required: ['nodeId'] } },
180
+
181
+ { name: 'spacing_rhythm', category: 'spacing',
182
+ description: 'Check vertical rhythm: are section gaps consistent and proportional? Flags irregular spacing patterns.',
183
+ inputSchema: { type: 'object', properties: { nodeId: str('Frame to check') }, required: ['nodeId'] } },
184
+
185
+ { name: 'grid_apply', category: 'spacing',
186
+ description: 'Apply a layout grid to a frame: columns, rows, or custom grid with configurable gutter and margin.',
187
+ inputSchema: { type: 'object', properties: { nodeId: str('Frame to apply grid to'), type: str('columns, rows, grid'), count: opt(num('Column/row count')), gutter: opt(num('Gutter size')), margin: opt(num('Margin')) }, required: ['nodeId', 'type'] } },
188
+
189
+ { name: 'grid_check', category: 'spacing',
190
+ description: 'Verify all children of a frame align to the parent layout grid.',
191
+ inputSchema: { type: 'object', properties: { nodeId: str('Frame to check') }, required: ['nodeId'] } },
192
+
193
+ // ═══ AUDIT & CRITIQUE ═══
194
+ { name: 'audit_full', category: 'audit',
195
+ description: 'Full design audit: spacing, typography, color, components, accessibility, hierarchy. Returns a 0-100 score with per-category breakdown.',
196
+ inputSchema: { type: 'object', properties: { nodeId: opt(str('Frame to audit (current page if omitted)')) }, required: [] } },
197
+
198
+ { name: 'audit_hierarchy', category: 'audit',
199
+ description: 'Check visual hierarchy: are primary elements dominant? Are heading levels properly differentiated?',
200
+ inputSchema: { type: 'object', properties: { nodeId: str('Frame to check') }, required: ['nodeId'] } },
201
+
202
+ { name: 'audit_consistency', category: 'audit',
203
+ description: 'Find elements that look similar but use different styles. Flags inconsistent text, colors, spacing, and radii.',
204
+ inputSchema: { type: 'object', properties: { nodeId: str('Frame to check') }, required: ['nodeId'] } },
205
+
206
+ { name: 'audit_alignment', category: 'audit',
207
+ description: 'Flag misaligned elements, uneven margins, off-center content, and broken visual axes.',
208
+ inputSchema: { type: 'object', properties: { nodeId: str('Frame to check'), tolerance: opt(num('Pixel tolerance (default 2)')) }, required: ['nodeId'] } },
209
+
210
+ { name: 'audit_density', category: 'audit',
211
+ description: 'Check information density: too cramped or too sparse? Measures whitespace ratio and content distribution.',
212
+ inputSchema: { type: 'object', properties: { nodeId: str('Frame to check') }, required: ['nodeId'] } },
213
+
214
+ { name: 'audit_score', category: 'audit',
215
+ description: 'Generate a 0-100 design health score with per-category breakdown and actionable improvement suggestions.',
216
+ inputSchema: { type: 'object', properties: { nodeId: opt(str('Frame to score')) }, required: [] } },
217
+
218
+ // ═══ ACCESSIBILITY ═══
219
+ { name: 'a11y_contrast', category: 'accessibility',
220
+ description: 'Check all text/background color pairs against WCAG AA (4.5:1) and AAA (7:1) standards.',
221
+ inputSchema: { type: 'object', properties: { nodeId: opt(str('Frame to check')), level: opt(str('aa or aaa (default aa)')) }, required: [] } },
222
+
223
+ { name: 'a11y_touch', category: 'accessibility',
224
+ description: 'Verify all interactive elements meet the 44x44px minimum touch target size.',
225
+ inputSchema: { type: 'object', properties: { nodeId: str('Frame to check'), minSize: opt(num('Minimum size in px (default 44)')) }, required: ['nodeId'] } },
226
+
227
+ { name: 'a11y_focus', category: 'accessibility',
228
+ description: 'Generate focus ring styles for all interactive elements: buttons, inputs, links, toggles.',
229
+ inputSchema: { type: 'object', properties: { nodeId: str('Frame to add focus states to'), color: opt(str('Focus ring color hex')), offset: opt(num('Ring offset in px')) }, required: ['nodeId'] } },
230
+
231
+ { name: 'a11y_labels', category: 'accessibility',
232
+ description: 'Check for missing labels on inputs, buttons, and icon-only elements. Flags unlabeled interactive content.',
233
+ inputSchema: { type: 'object', properties: { nodeId: str('Frame to check') }, required: ['nodeId'] } },
234
+
235
+ { name: 'a11y_fix', category: 'accessibility',
236
+ description: 'Auto-fix accessibility issues: bump insufficient contrast, enlarge small touch targets, add visible focus states.',
237
+ inputSchema: { type: 'object', properties: { nodeId: str('Frame to fix'), fixes: opt(arr('Specific fixes: contrast, touch, focus, labels')) }, required: ['nodeId'] } },
238
+
239
+ // ═══ RESPONSIVE ═══
240
+ { name: 'responsive_variant', category: 'responsive',
241
+ description: 'Generate mobile (375px), tablet (768px), and desktop (1440px) variants of any frame.',
242
+ inputSchema: { type: 'object', properties: { nodeId: str('Frame to generate variants from'), breakpoints: opt(arr('Breakpoint widths', { type: 'number' })) }, required: ['nodeId'] } },
243
+
244
+ { name: 'responsive_reflow', category: 'responsive',
245
+ description: 'Reflow a desktop layout into mobile: stack columns, resize typography, adjust spacing.',
246
+ inputSchema: { type: 'object', properties: { nodeId: str('Desktop frame to reflow'), targetWidth: num('Target width in px') }, required: ['nodeId', 'targetWidth'] } },
247
+
248
+ { name: 'responsive_breakpoints', category: 'responsive',
249
+ description: 'Set up breakpoint frames side by side: 375, 768, 1024, 1440. Ready for responsive design.',
250
+ inputSchema: { type: 'object', properties: { widths: opt(arr('Breakpoint widths', { type: 'number' })), height: opt(num('Frame height')) }, required: [] } },
251
+
252
+ { name: 'responsive_check', category: 'responsive',
253
+ description: 'Verify text doesn\'t overflow, images maintain aspect ratio, and touch targets remain accessible at each breakpoint.',
254
+ inputSchema: { type: 'object', properties: { nodeId: str('Frame to check') }, required: ['nodeId'] } },
255
+
256
+ // ═══ EXPORT & HANDOFF ═══
257
+ { name: 'export_tokens_css', category: 'export',
258
+ description: 'Export all design tokens as CSS custom properties.',
259
+ inputSchema: { type: 'object', properties: { nodeId: opt(str('Frame to extract tokens from')), includeColors: opt(bool('Include colors')), includeSpacing: opt(bool('Include spacing')), includeTypography: opt(bool('Include typography')) }, required: [] } },
260
+
261
+ { name: 'export_tokens_tailwind', category: 'export',
262
+ description: 'Export tokens as a Tailwind CSS config theme extension.',
263
+ inputSchema: { type: 'object', properties: { nodeId: opt(str('Frame to extract tokens from')) }, required: [] } },
264
+
265
+ { name: 'export_tokens_json', category: 'export',
266
+ description: 'Export tokens in W3C Design Tokens format (JSON).',
267
+ inputSchema: { type: 'object', properties: { nodeId: opt(str('Frame to extract tokens from')) }, required: [] } },
268
+
269
+ { name: 'export_tokens_scss', category: 'export',
270
+ description: 'Export tokens as SCSS variables and maps.',
271
+ inputSchema: { type: 'object', properties: { nodeId: opt(str('Frame to extract tokens from')) }, required: [] } },
272
+
273
+ { name: 'export_spec', category: 'export',
274
+ description: 'Generate a design spec: measurements, spacing tokens, color values, component annotations.',
275
+ inputSchema: { type: 'object', properties: { nodeId: str('Frame to generate spec for'), format: opt(str('markdown or json')) }, required: ['nodeId'] } },
276
+
277
+ { name: 'export_changelog', category: 'export',
278
+ description: 'Diff two frames and export what changed as structured markdown or JSON.',
279
+ inputSchema: { type: 'object', properties: { nodeIdA: str('First frame (before)'), nodeIdB: str('Second frame (after)'), format: opt(str('markdown or json')) }, required: ['nodeIdA', 'nodeIdB'] } },
280
+ ];
281
+
282
+ export function getToolsByCategory(category) {
283
+ return TOOLS.filter(t => t.category === category);
284
+ }
285
+
286
+ export function getToolByName(name) {
287
+ return TOOLS.find(t => t.name === name);
288
+ }
289
+
290
+ export function getAllToolNames() {
291
+ return TOOLS.map(t => t.name);
292
+ }