tabbied-mcp 0.2.4 → 0.3.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/README.md CHANGED
@@ -71,7 +71,7 @@ and `render_design` says what to install. Needs Node 20 or later.
71
71
  | Tool | What it does |
72
72
  | --- | --- |
73
73
  | `search_designs` | Filter by motif, mood, density, intended use, free text, or SVG-export support. |
74
- | `get_design` | The full record for one slug, plus ready-to-paste snippets. |
74
+ | `get_design` | The full record for one slug, plus ready-to-paste code for React, Vue, Svelte, the web component, plain HTML and plain JavaScript (`framework` picks one). |
75
75
  | `preview_design` | The rendered preview image for up to six designs, so the model can *look*. |
76
76
  | `get_docs` | The complete API reference (`llms-full.txt`). |
77
77
  | `list_templates` | The Tabbied website templates, a page at a time, filtered by category or by words. |
@@ -80,7 +80,8 @@ and `render_design` says what to install. Needs Node 20 or later.
80
80
 
81
81
  Slugs are opaque - `cleat`, `karst`, `radius` - so the intended flow is
82
82
  `search_designs` to narrow, `preview_design` to look, then `get_design` for the
83
- options. Choosing off tags alone is the main way this goes wrong.
83
+ options and the code for the project's setup. Choosing off tags alone is the
84
+ main way this goes wrong.
84
85
 
85
86
  The website templates are licensed per Tabbied account, not with this package:
86
87
  downloading one needs an account that has chosen it, under the
package/dist/info.d.ts CHANGED
@@ -7,4 +7,4 @@ export declare const VERSION = "0.2.4";
7
7
  * sizing rule is the most common way a correct-looking integration renders as
8
8
  * nothing.
9
9
  */
10
- export declare const INSTRUCTIONS = "Tabbied is a catalog of generative patterns (css-doodle) usable as backgrounds, textures, posters, and exported SVG/PNG assets.\n\nDesigns are addressed by slug, and slugs are opaque - \"cleat\", \"karst\", \"radius\" say nothing about what they look like. Never guess one: call search_designs, which filters on a closed vocabulary of motifs, moods, density, and intended use.\n\nMetadata narrows the field; it does not settle it. These are pictures, so call preview_design on your shortlist and look before you commit. Choosing off tags alone is the main way this goes wrong.\n\nWhen you write integration code, remember a pattern has no intrinsic size: it fills its parent and collapses to nothing in a parent that sizes to content. Pass height or aspectRatio unless the parent is definitely sized. get_docs has the full API contract and recipes.";
10
+ export declare const INSTRUCTIONS = "Tabbied is a catalog of generative patterns (css-doodle) usable as backgrounds, textures, posters, and exported SVG/PNG assets.\n\nDesigns are addressed by slug, and slugs are opaque - \"cleat\", \"karst\", \"radius\" say nothing about what they look like. Never guess one: call search_designs, which filters on a closed vocabulary of motifs, moods, density, and intended use.\n\nMetadata narrows the field; it does not settle it. These are pictures, so call preview_design on your shortlist and look before you commit. Choosing off tags alone is the main way this goes wrong.\n\nThe package works in React, Vue, Svelte and SvelteKit, any page or CMS through the <tabbied-pattern> web component, plain HTML with no build step, and framework-free JavaScript. get_design writes ready-to-paste code for each; pass framework to get only the one the project uses, and match it to the project rather than defaulting to React.\n\nWhen you write integration code, remember a pattern has no intrinsic size: it fills its parent and collapses to nothing in a parent that sizes to content. Pass height or aspectRatio unless the parent is definitely sized. get_docs has the full API contract and recipes.";
package/dist/info.js CHANGED
@@ -19,5 +19,7 @@ Designs are addressed by slug, and slugs are opaque - "cleat", "karst", "radius"
19
19
 
20
20
  Metadata narrows the field; it does not settle it. These are pictures, so call preview_design on your shortlist and look before you commit. Choosing off tags alone is the main way this goes wrong.
21
21
 
22
+ The package works in React, Vue, Svelte and SvelteKit, any page or CMS through the <tabbied-pattern> web component, plain HTML with no build step, and framework-free JavaScript. get_design writes ready-to-paste code for each; pass framework to get only the one the project uses, and match it to the project rather than defaulting to React.
23
+
22
24
  When you write integration code, remember a pattern has no intrinsic size: it fills its parent and collapses to nothing in a parent that sizes to content. Pass height or aspectRatio unless the parent is definitely sized. get_docs has the full API contract and recipes.`;
23
25
  //# sourceMappingURL=info.js.map
package/dist/info.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"info.js","sourceRoot":"","sources":["../src/info.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,EAAE;AACF,8EAA8E;AAC9E,2EAA2E;AAC3E,wDAAwD;AACxD,4EAA4E;AAC5E,MAAM,CAAC,MAAM,WAAW,GAAG,SAAS,CAAC;AACrC,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAC;AAE/B;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG;;;;;;6QAMiP,CAAC","sourcesContent":["// Server identity and the instructions clients hand to the model.\n//\n// VERSION is a literal rather than a package.json read because this module is\n// bundled into a Cloudflare Worker, which has no filesystem. The release's\n// `version-packages` step rewrites it from package.json\n// (scripts/sync-version.mjs), and test/info.test.mjs pins the two together.\nexport const SERVER_NAME = 'tabbied';\nexport const VERSION = '0.2.4';\n\n/**\n * Shown to the model as a preamble. It carries what no tool description can,\n * because they are properties of the *set* rather than of one call: slugs\n * cannot be guessed, the previews are what a choice should rest on, and the\n * sizing rule is the most common way a correct-looking integration renders as\n * nothing.\n */\nexport const INSTRUCTIONS = `Tabbied is a catalog of generative patterns (css-doodle) usable as backgrounds, textures, posters, and exported SVG/PNG assets.\n\nDesigns are addressed by slug, and slugs are opaque - \"cleat\", \"karst\", \"radius\" say nothing about what they look like. Never guess one: call search_designs, which filters on a closed vocabulary of motifs, moods, density, and intended use.\n\nMetadata narrows the field; it does not settle it. These are pictures, so call preview_design on your shortlist and look before you commit. Choosing off tags alone is the main way this goes wrong.\n\nWhen you write integration code, remember a pattern has no intrinsic size: it fills its parent and collapses to nothing in a parent that sizes to content. Pass height or aspectRatio unless the parent is definitely sized. get_docs has the full API contract and recipes.`;\n"]}
1
+ {"version":3,"file":"info.js","sourceRoot":"","sources":["../src/info.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,EAAE;AACF,8EAA8E;AAC9E,2EAA2E;AAC3E,wDAAwD;AACxD,4EAA4E;AAC5E,MAAM,CAAC,MAAM,WAAW,GAAG,SAAS,CAAC;AACrC,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAC;AAE/B;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG;;;;;;;;6QAQiP,CAAC","sourcesContent":["// Server identity and the instructions clients hand to the model.\n//\n// VERSION is a literal rather than a package.json read because this module is\n// bundled into a Cloudflare Worker, which has no filesystem. The release's\n// `version-packages` step rewrites it from package.json\n// (scripts/sync-version.mjs), and test/info.test.mjs pins the two together.\nexport const SERVER_NAME = 'tabbied';\nexport const VERSION = '0.2.4';\n\n/**\n * Shown to the model as a preamble. It carries what no tool description can,\n * because they are properties of the *set* rather than of one call: slugs\n * cannot be guessed, the previews are what a choice should rest on, and the\n * sizing rule is the most common way a correct-looking integration renders as\n * nothing.\n */\nexport const INSTRUCTIONS = `Tabbied is a catalog of generative patterns (css-doodle) usable as backgrounds, textures, posters, and exported SVG/PNG assets.\n\nDesigns are addressed by slug, and slugs are opaque - \"cleat\", \"karst\", \"radius\" say nothing about what they look like. Never guess one: call search_designs, which filters on a closed vocabulary of motifs, moods, density, and intended use.\n\nMetadata narrows the field; it does not settle it. These are pictures, so call preview_design on your shortlist and look before you commit. Choosing off tags alone is the main way this goes wrong.\n\nThe package works in React, Vue, Svelte and SvelteKit, any page or CMS through the <tabbied-pattern> web component, plain HTML with no build step, and framework-free JavaScript. get_design writes ready-to-paste code for each; pass framework to get only the one the project uses, and match it to the project rather than defaulting to React.\n\nWhen you write integration code, remember a pattern has no intrinsic size: it fills its parent and collapses to nothing in a parent that sizes to content. Pass height or aspectRatio unless the parent is definitely sized. get_docs has the full API contract and recipes.`;\n"]}
package/dist/templates.js CHANGED
@@ -187,6 +187,8 @@ function listTool(context) {
187
187
  ? Math.max(Math.trunc(args.offset), 0)
188
188
  : 0;
189
189
  const matched = catalog.templates.filter((entry) => {
190
+ // The fields the site's template gallery searches too
191
+ // (lib/catalogSearch.ts, `templateKeywords`).
190
192
  const haystack = `${entry.slug} ${entry.name} ${entry.category ?? ''} ${entry.topic ?? ''}`.toLowerCase();
191
193
  return (terms.every((term) => haystack.includes(term)) &&
192
194
  (!category ||
@@ -1 +1 @@
1
- {"version":3,"file":"templates.js","sourceRoot":"","sources":["../src/templates.ts"],"names":[],"mappings":"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","sourcesContent":["// The template-site tools: what an agent needs to start somebody's site from a\n// finished template rather than from an empty page.\n//\n// The design tools answer \"which pattern?\"; these answer \"which *site*, and\n// what may I change about it?\". The useful move with a template is to swap the\n// brand out of it, and the editable-section spec (docs/editable-templates.md)\n// is the list of what may be swapped.\n//\n// Both are thin readers over artifacts the site already generates, so an agent\n// and the web builder see the same bytes. Neither needs a browser, so unlike\n// `render_design` they work over both transports.\nimport type {\n TemplateCatalog,\n TemplateCatalogEntry,\n TemplateSpec,\n Tool,\n ToolContent,\n ToolContext,\n ToolResult,\n} from './types.js';\n\nconst SITE = 'https://tabbied.com';\n\nconst LIST_LIMIT_DEFAULT = 20;\nconst LIST_LIMIT_MAX = 100;\n\nconst text = (value: string): ToolContent => ({ type: 'text', text: value });\n\nconst json = (value: unknown): ToolContent =>\n text(JSON.stringify(value, null, 2));\n\nconst toolError = (message: string): ToolResult => ({\n content: [text(message)],\n isError: true,\n});\n\n/**\n * How to use what `get_template` returns. Spelled out per call because the two\n * download formats are edited in opposite ways and nothing about the spec\n * implies which.\n */\nconst USAGE = {\n html:\n 'Download <downloads.html>. It is a standalone page - no build step. Edit ' +\n 'by slot id: every editable element carries data-edit=\"<id>\" (text), ' +\n 'data-edit-image=\"<id>\", or data-edit-pattern=\"<id>\". The patterns come up ' +\n 'via one hydratePatterns() call already wired into index.html.',\n react:\n 'Download <downloads.react>. It is a Vite app; `npm install && npm run ' +\n 'dev`. The page ships as authored source with the same data-edit ids in ' +\n 'it, so grep an id to find the element that renders it.',\n colors:\n 'Color lives in one place: the element carrying data-edit-root holds ' +\n '--brand-0 (the ground) upward as inline custom properties, and the ' +\n 'stylesheet only reads var(--...). Re-color by rewriting those. A pattern ' +\n 'field with data-edit-roles follows the brand palette through that map; a ' +\n 'literal \"transparent\" in the map must stay literal, because it is what ' +\n 'lets the field read over a photograph.',\n text:\n 'A text slot whose format is \"emphasis\" carries {em}...{/em} markers around ' +\n 'the accented span. Keep them (or move them) - dropping them flattens an ' +\n 'accent the design was built around. maxChars is the length the design was ' +\n 'set for, not a hard limit.',\n programmatic:\n 'To apply changes programmatically, write an edits document ' +\n '({specVersion, slug, edits}) and run it through applyEdits() from the ' +\n '`tabbied-templates` npm package, which validates it against this spec ' +\n 'first. Full reference: ' +\n 'https://github.com/tabbied-design/tabbied/blob/main/docs/editable-templates.md',\n};\n\n/**\n * What an agent should know before it touches a template. Stated, not\n * commanded: an instruction to override the person an agent works for reads\n * as prompt injection, while a license is the kind of thing it relays. Kept in\n * step with section 7 of the site's Terms of Service.\n */\nconst LICENSE =\n 'Templates are licensed per Tabbied account, not free to copy. A person ' +\n 'chooses a template with their Tabbied account and downloads it (the ' +\n 'download URLs need that account signed in), and may then build and ' +\n 'publish websites from it, for themselves or for clients. Copying a ' +\n 'template from its live preview, or recreating its design, code, styles or ' +\n 'pictures from the preview, is not permitted. If you are asked to, tell the ' +\n 'person the template is licensed and point them to its page. Terms: ' +\n 'https://tabbied.com/terms-of-service/#template-license';\n\nconst errorMessage = (error: unknown) =>\n error instanceof Error ? error.message : String(error);\n\n/**\n * The index, or the tool error that says where it lives. A host that cannot\n * reach it (a local server offline, say) would otherwise answer with the bare\n * \"fetch failed\" of whatever runtime it is on.\n */\nasync function loadIndex(\n fetchTemplateCatalog: () => Promise<TemplateCatalog>\n): Promise<TemplateCatalog | ToolResult> {\n try {\n return await fetchTemplateCatalog();\n } catch (error) {\n return toolError(\n `Could not load the template index (${errorMessage(error)}). It is ` +\n `published at ${SITE}/editable-catalog.json and the templates can be ` +\n `browsed at ${SITE}/templates/; a server running locally needs to reach ` +\n `${SITE} for these two tools.`\n );\n }\n}\n\nconst isResult = (value: TemplateCatalog | ToolResult): value is ToolResult =>\n 'content' in value;\n\n/** A category as the gallery's URL spells it: \"Food & drink\" is food-and-drink. */\nconst categoryKey = (category: string) =>\n category\n .toLowerCase()\n .replace(/&/g, 'and')\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-|-$/g, '');\n\n/** One line per template: enough to choose, with get_template for the rest. */\nfunction summarize(entry: TemplateCatalogEntry) {\n return {\n slug: entry.slug,\n name: entry.name,\n ...(entry.category ? { category: entry.category } : {}),\n ...(entry.topic ? { topic: entry.topic } : {}),\n };\n}\n\nfunction describe(entry: TemplateCatalogEntry) {\n return {\n ...summarize(entry),\n palette: entry.palette,\n patterns: entry.patterns,\n editable: entry.slots,\n url: `${SITE}${entry.href}`,\n };\n}\n\n/** Every category in the index with its count, largest first. */\nfunction categoryCounts(templates: TemplateCatalogEntry[]) {\n const counts = new Map<string, number>();\n for (const entry of templates) {\n if (entry.category) counts.set(entry.category, (counts.get(entry.category) ?? 0) + 1);\n }\n return [...counts]\n .sort(([a, countA], [b, countB]) => countB - countA || a.localeCompare(b))\n .map(([category, count]) => ({ category, count }));\n}\n\n/**\n * Suggest near-misses for a slug that isn't in the catalog, so a wrong guess\n * comes back as a correction rather than a dead end.\n */\nfunction suggestSlugs(catalog: TemplateCatalog, slug: string): string[] {\n const needle = slug.toLowerCase();\n const prefix = needle.slice(0, 3);\n\n if (!needle) return [];\n\n return catalog.templates\n .filter(\n (entry) =>\n entry.slug.startsWith(prefix) ||\n entry.name.toLowerCase().includes(needle) ||\n entry.slug.includes(needle)\n )\n .map((entry) => entry.slug)\n .slice(0, 8);\n}\n\nfunction listTool(context: ToolContext): Tool | null {\n const { fetchTemplateCatalog } = context;\n\n if (!fetchTemplateCatalog) return null;\n\n return {\n definition: {\n name: 'list_templates',\n title: 'List the editable template sites',\n description:\n 'The Tabbied template sites that can be customized: finished, ' +\n 'single-page sites for a business, each built around a pattern and ' +\n 'downloadable as plain HTML or as a React (Vite) project. Returns a ' +\n 'page of one-line entries (slug, name, category, what the business ' +\n 'is), the count that matched, and every category with its count; ' +\n 'filter by category or query and page with offset. Start here when ' +\n 'the task is \"build me a site\" rather than \"pick me a pattern\" - then ' +\n 'get_template for the one you want. Templates are licensed per ' +\n 'Tabbied account: see `license` in the result.',\n inputSchema: {\n type: 'object',\n properties: {\n query: {\n type: 'string',\n description:\n 'Words matched against the slug, name, category, and what the ' +\n 'business is (e.g. \"bakery\", \"dentist\"). Every word must appear.',\n },\n category: {\n type: 'string',\n description:\n 'A gallery category, e.g. \"Food & drink\" (or food-and-drink). ' +\n 'Every result lists the categories there are.',\n },\n detail: {\n type: 'boolean',\n description:\n \"Also return each template's palette, patterns, editable slot \" +\n 'counts and URL. Off by default to keep the page short.',\n },\n limit: {\n type: 'integer',\n minimum: 1,\n maximum: LIST_LIMIT_MAX,\n description: `Templates per page (default ${LIST_LIMIT_DEFAULT}).`,\n },\n offset: {\n type: 'integer',\n minimum: 0,\n description: 'How many matches to skip, for the next page (default 0).',\n },\n },\n additionalProperties: false,\n },\n annotations: { readOnlyHint: true, openWorldHint: true },\n },\n async run(args) {\n const catalog = await loadIndex(fetchTemplateCatalog);\n if (isResult(catalog)) return catalog;\n\n const terms =\n typeof args.query === 'string'\n ? args.query.toLowerCase().split(/\\s+/).filter(Boolean)\n : [];\n const category =\n typeof args.category === 'string' && args.category.trim()\n ? args.category.trim()\n : null;\n const limit = Math.min(\n Math.max(\n typeof args.limit === 'number' && Number.isFinite(args.limit)\n ? Math.trunc(args.limit)\n : LIST_LIMIT_DEFAULT,\n 1\n ),\n LIST_LIMIT_MAX\n );\n const offset =\n typeof args.offset === 'number' && Number.isFinite(args.offset)\n ? Math.max(Math.trunc(args.offset), 0)\n : 0;\n\n const matched = catalog.templates.filter((entry) => {\n const haystack =\n `${entry.slug} ${entry.name} ${entry.category ?? ''} ${entry.topic ?? ''}`.toLowerCase();\n return (\n terms.every((term) => haystack.includes(term)) &&\n (!category ||\n (entry.category !== undefined &&\n categoryKey(entry.category) === categoryKey(category)))\n );\n });\n\n const categories = categoryCounts(catalog.templates);\n const total = catalog.templates.length;\n\n if (matched.length === 0) {\n return {\n content: [\n json({\n matched: 0,\n total,\n ...(categories.length > 0 ? { categories } : {}),\n hint:\n category && categories.length === 0\n ? 'This index carries no categories (an older deployment of the ' +\n 'site); filter with query instead.'\n : 'Nothing matches every filter. Check the category against the ' +\n 'list above, use fewer or broader query words, or drop both ' +\n 'to page through everything.',\n }),\n ],\n };\n }\n\n const page = matched.slice(offset, offset + limit);\n const nextOffset = offset + page.length;\n\n return {\n content: [\n json({\n matched: matched.length,\n total,\n offset,\n returned: page.length,\n ...(page.length === 0\n ? { hint: `offset ${offset} is past the last match; there are ${matched.length}.` }\n : nextOffset < matched.length\n ? {\n next:\n `Showing ${offset + 1}-${nextOffset} of ${matched.length}. ` +\n `Pass offset ${nextOffset} for the next page, or narrow with ` +\n 'category or query.',\n }\n : {}),\n // Absent from an index written before categories were added.\n ...(categories.length > 0 ? { categories } : {}),\n license: LICENSE,\n templates: page.map(args.detail === true ? describe : summarize),\n }),\n ],\n };\n },\n };\n}\n\nfunction getTool(context: ToolContext): Tool | null {\n const { fetchTemplateCatalog, fetchTemplate } = context;\n\n if (!fetchTemplateCatalog || !fetchTemplate) return null;\n\n return {\n definition: {\n name: 'get_template',\n title: 'Get one template site and everything editable in it',\n description:\n \"A template's full editable-section spec: every text, image, and \" +\n 'pattern slot with its id and its current value, the brand palette, ' +\n 'the fonts, and the two download URLs. The slot ids are the contract - ' +\n 'they exist in the downloaded markup as data-edit* attributes, so an ' +\n 'id from this response is directly greppable in the files you ' +\n 'download. Includes usage notes for editing each format, and the ' +\n 'license the template is under.',\n inputSchema: {\n type: 'object',\n properties: {\n slug: {\n type: 'string',\n minLength: 1,\n description: 'Template slug, from list_templates.',\n },\n },\n required: ['slug'],\n additionalProperties: false,\n },\n annotations: { readOnlyHint: true, openWorldHint: true },\n },\n async run(args) {\n const slug = typeof args.slug === 'string' ? args.slug.trim() : '';\n\n if (!slug) return toolError('get_template needs a `slug`.');\n\n const catalog = await loadIndex(fetchTemplateCatalog);\n if (isResult(catalog)) return catalog;\n\n const entry = catalog.templates.find(\n (candidate) => candidate.slug === slug\n );\n\n if (!entry) {\n const suggestions = suggestSlugs(catalog, slug);\n\n return toolError(\n `No editable template \"${slug}\". ` +\n (suggestions.length > 0\n ? `Did you mean: ${suggestions.join(', ')}?`\n : 'Call list_templates for the available slugs.')\n );\n }\n\n let spec: TemplateSpec;\n\n try {\n spec = await fetchTemplate(slug);\n } catch (error) {\n return toolError(\n `Could not load the spec for \"${slug}\" (${errorMessage(error)}). It ` +\n `is published at ${SITE}${entry.spec}, and the template's page is ` +\n `${SITE}${entry.href}.`\n );\n }\n\n const downloads = {\n html: `${SITE}${entry.downloads.html}`,\n react: `${SITE}${entry.downloads.react}`,\n };\n\n return {\n content: [\n json({\n ...spec,\n url: `${SITE}${entry.href}`,\n license: LICENSE,\n downloads,\n usage: {\n html: USAGE.html.replace('<downloads.html>', downloads.html),\n react: USAGE.react.replace('<downloads.react>', downloads.react),\n colors: USAGE.colors,\n text: USAGE.text,\n programmatic: USAGE.programmatic,\n },\n }),\n ],\n };\n },\n };\n}\n\n/** The template tools, dropped when the host cannot resolve their data. */\nexport function templateTools(context: ToolContext): Tool[] {\n return [listTool(context), getTool(context)].filter(\n (tool): tool is Tool => tool !== null\n );\n}\n"]}
1
+ {"version":3,"file":"templates.js","sourceRoot":"","sources":["../src/templates.ts"],"names":[],"mappings":"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","sourcesContent":["// The template-site tools: what an agent needs to start somebody's site from a\n// finished template rather than from an empty page.\n//\n// The design tools answer \"which pattern?\"; these answer \"which *site*, and\n// what may I change about it?\". The useful move with a template is to swap the\n// brand out of it, and the editable-section spec (docs/editable-templates.md)\n// is the list of what may be swapped.\n//\n// Both are thin readers over artifacts the site already generates, so an agent\n// and the web builder see the same bytes. Neither needs a browser, so unlike\n// `render_design` they work over both transports.\nimport type {\n TemplateCatalog,\n TemplateCatalogEntry,\n TemplateSpec,\n Tool,\n ToolContent,\n ToolContext,\n ToolResult,\n} from './types.js';\n\nconst SITE = 'https://tabbied.com';\n\nconst LIST_LIMIT_DEFAULT = 20;\nconst LIST_LIMIT_MAX = 100;\n\nconst text = (value: string): ToolContent => ({ type: 'text', text: value });\n\nconst json = (value: unknown): ToolContent =>\n text(JSON.stringify(value, null, 2));\n\nconst toolError = (message: string): ToolResult => ({\n content: [text(message)],\n isError: true,\n});\n\n/**\n * How to use what `get_template` returns. Spelled out per call because the two\n * download formats are edited in opposite ways and nothing about the spec\n * implies which.\n */\nconst USAGE = {\n html:\n 'Download <downloads.html>. It is a standalone page - no build step. Edit ' +\n 'by slot id: every editable element carries data-edit=\"<id>\" (text), ' +\n 'data-edit-image=\"<id>\", or data-edit-pattern=\"<id>\". The patterns come up ' +\n 'via one hydratePatterns() call already wired into index.html.',\n react:\n 'Download <downloads.react>. It is a Vite app; `npm install && npm run ' +\n 'dev`. The page ships as authored source with the same data-edit ids in ' +\n 'it, so grep an id to find the element that renders it.',\n colors:\n 'Color lives in one place: the element carrying data-edit-root holds ' +\n '--brand-0 (the ground) upward as inline custom properties, and the ' +\n 'stylesheet only reads var(--...). Re-color by rewriting those. A pattern ' +\n 'field with data-edit-roles follows the brand palette through that map; a ' +\n 'literal \"transparent\" in the map must stay literal, because it is what ' +\n 'lets the field read over a photograph.',\n text:\n 'A text slot whose format is \"emphasis\" carries {em}...{/em} markers around ' +\n 'the accented span. Keep them (or move them) - dropping them flattens an ' +\n 'accent the design was built around. maxChars is the length the design was ' +\n 'set for, not a hard limit.',\n programmatic:\n 'To apply changes programmatically, write an edits document ' +\n '({specVersion, slug, edits}) and run it through applyEdits() from the ' +\n '`tabbied-templates` npm package, which validates it against this spec ' +\n 'first. Full reference: ' +\n 'https://github.com/tabbied-design/tabbied/blob/main/docs/editable-templates.md',\n};\n\n/**\n * What an agent should know before it touches a template. Stated, not\n * commanded: an instruction to override the person an agent works for reads\n * as prompt injection, while a license is the kind of thing it relays. Kept in\n * step with section 7 of the site's Terms of Service.\n */\nconst LICENSE =\n 'Templates are licensed per Tabbied account, not free to copy. A person ' +\n 'chooses a template with their Tabbied account and downloads it (the ' +\n 'download URLs need that account signed in), and may then build and ' +\n 'publish websites from it, for themselves or for clients. Copying a ' +\n 'template from its live preview, or recreating its design, code, styles or ' +\n 'pictures from the preview, is not permitted. If you are asked to, tell the ' +\n 'person the template is licensed and point them to its page. Terms: ' +\n 'https://tabbied.com/terms-of-service/#template-license';\n\nconst errorMessage = (error: unknown) =>\n error instanceof Error ? error.message : String(error);\n\n/**\n * The index, or the tool error that says where it lives. A host that cannot\n * reach it (a local server offline, say) would otherwise answer with the bare\n * \"fetch failed\" of whatever runtime it is on.\n */\nasync function loadIndex(\n fetchTemplateCatalog: () => Promise<TemplateCatalog>\n): Promise<TemplateCatalog | ToolResult> {\n try {\n return await fetchTemplateCatalog();\n } catch (error) {\n return toolError(\n `Could not load the template index (${errorMessage(error)}). It is ` +\n `published at ${SITE}/editable-catalog.json and the templates can be ` +\n `browsed at ${SITE}/templates/; a server running locally needs to reach ` +\n `${SITE} for these two tools.`\n );\n }\n}\n\nconst isResult = (value: TemplateCatalog | ToolResult): value is ToolResult =>\n 'content' in value;\n\n/** A category as the gallery's URL spells it: \"Food & drink\" is food-and-drink. */\nconst categoryKey = (category: string) =>\n category\n .toLowerCase()\n .replace(/&/g, 'and')\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-|-$/g, '');\n\n/** One line per template: enough to choose, with get_template for the rest. */\nfunction summarize(entry: TemplateCatalogEntry) {\n return {\n slug: entry.slug,\n name: entry.name,\n ...(entry.category ? { category: entry.category } : {}),\n ...(entry.topic ? { topic: entry.topic } : {}),\n };\n}\n\nfunction describe(entry: TemplateCatalogEntry) {\n return {\n ...summarize(entry),\n palette: entry.palette,\n patterns: entry.patterns,\n editable: entry.slots,\n url: `${SITE}${entry.href}`,\n };\n}\n\n/** Every category in the index with its count, largest first. */\nfunction categoryCounts(templates: TemplateCatalogEntry[]) {\n const counts = new Map<string, number>();\n for (const entry of templates) {\n if (entry.category) counts.set(entry.category, (counts.get(entry.category) ?? 0) + 1);\n }\n return [...counts]\n .sort(([a, countA], [b, countB]) => countB - countA || a.localeCompare(b))\n .map(([category, count]) => ({ category, count }));\n}\n\n/**\n * Suggest near-misses for a slug that isn't in the catalog, so a wrong guess\n * comes back as a correction rather than a dead end.\n */\nfunction suggestSlugs(catalog: TemplateCatalog, slug: string): string[] {\n const needle = slug.toLowerCase();\n const prefix = needle.slice(0, 3);\n\n if (!needle) return [];\n\n return catalog.templates\n .filter(\n (entry) =>\n entry.slug.startsWith(prefix) ||\n entry.name.toLowerCase().includes(needle) ||\n entry.slug.includes(needle)\n )\n .map((entry) => entry.slug)\n .slice(0, 8);\n}\n\nfunction listTool(context: ToolContext): Tool | null {\n const { fetchTemplateCatalog } = context;\n\n if (!fetchTemplateCatalog) return null;\n\n return {\n definition: {\n name: 'list_templates',\n title: 'List the editable template sites',\n description:\n 'The Tabbied template sites that can be customized: finished, ' +\n 'single-page sites for a business, each built around a pattern and ' +\n 'downloadable as plain HTML or as a React (Vite) project. Returns a ' +\n 'page of one-line entries (slug, name, category, what the business ' +\n 'is), the count that matched, and every category with its count; ' +\n 'filter by category or query and page with offset. Start here when ' +\n 'the task is \"build me a site\" rather than \"pick me a pattern\" - then ' +\n 'get_template for the one you want. Templates are licensed per ' +\n 'Tabbied account: see `license` in the result.',\n inputSchema: {\n type: 'object',\n properties: {\n query: {\n type: 'string',\n description:\n 'Words matched against the slug, name, category, and what the ' +\n 'business is (e.g. \"bakery\", \"dentist\"). Every word must appear.',\n },\n category: {\n type: 'string',\n description:\n 'A gallery category, e.g. \"Food & drink\" (or food-and-drink). ' +\n 'Every result lists the categories there are.',\n },\n detail: {\n type: 'boolean',\n description:\n \"Also return each template's palette, patterns, editable slot \" +\n 'counts and URL. Off by default to keep the page short.',\n },\n limit: {\n type: 'integer',\n minimum: 1,\n maximum: LIST_LIMIT_MAX,\n description: `Templates per page (default ${LIST_LIMIT_DEFAULT}).`,\n },\n offset: {\n type: 'integer',\n minimum: 0,\n description: 'How many matches to skip, for the next page (default 0).',\n },\n },\n additionalProperties: false,\n },\n annotations: { readOnlyHint: true, openWorldHint: true },\n },\n async run(args) {\n const catalog = await loadIndex(fetchTemplateCatalog);\n if (isResult(catalog)) return catalog;\n\n const terms =\n typeof args.query === 'string'\n ? args.query.toLowerCase().split(/\\s+/).filter(Boolean)\n : [];\n const category =\n typeof args.category === 'string' && args.category.trim()\n ? args.category.trim()\n : null;\n const limit = Math.min(\n Math.max(\n typeof args.limit === 'number' && Number.isFinite(args.limit)\n ? Math.trunc(args.limit)\n : LIST_LIMIT_DEFAULT,\n 1\n ),\n LIST_LIMIT_MAX\n );\n const offset =\n typeof args.offset === 'number' && Number.isFinite(args.offset)\n ? Math.max(Math.trunc(args.offset), 0)\n : 0;\n\n const matched = catalog.templates.filter((entry) => {\n // The fields the site's template gallery searches too\n // (lib/catalogSearch.ts, `templateKeywords`).\n const haystack =\n `${entry.slug} ${entry.name} ${entry.category ?? ''} ${entry.topic ?? ''}`.toLowerCase();\n return (\n terms.every((term) => haystack.includes(term)) &&\n (!category ||\n (entry.category !== undefined &&\n categoryKey(entry.category) === categoryKey(category)))\n );\n });\n\n const categories = categoryCounts(catalog.templates);\n const total = catalog.templates.length;\n\n if (matched.length === 0) {\n return {\n content: [\n json({\n matched: 0,\n total,\n ...(categories.length > 0 ? { categories } : {}),\n hint:\n category && categories.length === 0\n ? 'This index carries no categories (an older deployment of the ' +\n 'site); filter with query instead.'\n : 'Nothing matches every filter. Check the category against the ' +\n 'list above, use fewer or broader query words, or drop both ' +\n 'to page through everything.',\n }),\n ],\n };\n }\n\n const page = matched.slice(offset, offset + limit);\n const nextOffset = offset + page.length;\n\n return {\n content: [\n json({\n matched: matched.length,\n total,\n offset,\n returned: page.length,\n ...(page.length === 0\n ? { hint: `offset ${offset} is past the last match; there are ${matched.length}.` }\n : nextOffset < matched.length\n ? {\n next:\n `Showing ${offset + 1}-${nextOffset} of ${matched.length}. ` +\n `Pass offset ${nextOffset} for the next page, or narrow with ` +\n 'category or query.',\n }\n : {}),\n // Absent from an index written before categories were added.\n ...(categories.length > 0 ? { categories } : {}),\n license: LICENSE,\n templates: page.map(args.detail === true ? describe : summarize),\n }),\n ],\n };\n },\n };\n}\n\nfunction getTool(context: ToolContext): Tool | null {\n const { fetchTemplateCatalog, fetchTemplate } = context;\n\n if (!fetchTemplateCatalog || !fetchTemplate) return null;\n\n return {\n definition: {\n name: 'get_template',\n title: 'Get one template site and everything editable in it',\n description:\n \"A template's full editable-section spec: every text, image, and \" +\n 'pattern slot with its id and its current value, the brand palette, ' +\n 'the fonts, and the two download URLs. The slot ids are the contract - ' +\n 'they exist in the downloaded markup as data-edit* attributes, so an ' +\n 'id from this response is directly greppable in the files you ' +\n 'download. Includes usage notes for editing each format, and the ' +\n 'license the template is under.',\n inputSchema: {\n type: 'object',\n properties: {\n slug: {\n type: 'string',\n minLength: 1,\n description: 'Template slug, from list_templates.',\n },\n },\n required: ['slug'],\n additionalProperties: false,\n },\n annotations: { readOnlyHint: true, openWorldHint: true },\n },\n async run(args) {\n const slug = typeof args.slug === 'string' ? args.slug.trim() : '';\n\n if (!slug) return toolError('get_template needs a `slug`.');\n\n const catalog = await loadIndex(fetchTemplateCatalog);\n if (isResult(catalog)) return catalog;\n\n const entry = catalog.templates.find(\n (candidate) => candidate.slug === slug\n );\n\n if (!entry) {\n const suggestions = suggestSlugs(catalog, slug);\n\n return toolError(\n `No editable template \"${slug}\". ` +\n (suggestions.length > 0\n ? `Did you mean: ${suggestions.join(', ')}?`\n : 'Call list_templates for the available slugs.')\n );\n }\n\n let spec: TemplateSpec;\n\n try {\n spec = await fetchTemplate(slug);\n } catch (error) {\n return toolError(\n `Could not load the spec for \"${slug}\" (${errorMessage(error)}). It ` +\n `is published at ${SITE}${entry.spec}, and the template's page is ` +\n `${SITE}${entry.href}.`\n );\n }\n\n const downloads = {\n html: `${SITE}${entry.downloads.html}`,\n react: `${SITE}${entry.downloads.react}`,\n };\n\n return {\n content: [\n json({\n ...spec,\n url: `${SITE}${entry.href}`,\n license: LICENSE,\n downloads,\n usage: {\n html: USAGE.html.replace('<downloads.html>', downloads.html),\n react: USAGE.react.replace('<downloads.react>', downloads.react),\n colors: USAGE.colors,\n text: USAGE.text,\n programmatic: USAGE.programmatic,\n },\n }),\n ],\n };\n },\n };\n}\n\n/** The template tools, dropped when the host cannot resolve their data. */\nexport function templateTools(context: ToolContext): Tool[] {\n return [listTool(context), getTool(context)].filter(\n (tool): tool is Tool => tool !== null\n );\n}\n"]}
package/dist/tools.js CHANGED
@@ -8,6 +8,7 @@
8
8
  // The point is design *selection*. Slugs are opaque ("cleat", "karst") and
9
9
  // these are pictures, so search narrows on closed-vocabulary enums, then
10
10
  // preview_design puts the shortlist in front of the model before it commits.
11
+ import { SNIPPET_SETUPS, buildSnippet, buildSnippets, parseRatio, } from 'tabbied/snippets';
11
12
  import { templateTools } from './templates.js';
12
13
  const SEARCH_LIMIT_DEFAULT = 20;
13
14
  const SEARCH_LIMIT_MAX = 50;
@@ -51,38 +52,45 @@ function summarize(design) {
51
52
  preview: design.preview,
52
53
  };
53
54
  }
55
+ /**
56
+ * What a free-text query is matched against: slug, name, the closed-vocabulary
57
+ * tags, moods and uses, and the description. The site's gallery search
58
+ * (lib/catalogSearch.ts) reads the same fields, so "dots" finds the designs
59
+ * tagged dots in both, not only one whose name says it.
60
+ */
61
+ function designKeywords(design) {
62
+ return [
63
+ design.slug,
64
+ design.name,
65
+ ...design.tags,
66
+ ...design.mood,
67
+ ...design.goodFor,
68
+ design.description ?? '',
69
+ ]
70
+ .join(' ')
71
+ .toLowerCase();
72
+ }
54
73
  function findDesign(catalog, slug) {
55
74
  if (typeof slug !== 'string')
56
75
  return null;
57
76
  return catalog.designs.find((design) => design.slug === slug) ?? null;
58
77
  }
59
- const ASPECT_RATIO_DEFAULT = '2:3';
60
78
  /**
61
- * The React snippet: a component at the design's own aspect ratio. The ratio
62
- * is the catalog's id (`2:3`) written as CSS's `2 / 3`, which is what the
63
- * prop takes - the id itself is not valid CSS and would size nothing. Same
64
- * shape as the editor's "Copy React component", so the two agree.
79
+ * The snippets' input for one design as the catalog describes it: its own
80
+ * ratio (the catalog's `2:3` id, which the builders write as CSS's `2 / 3`)
81
+ * and its own ground color, with nothing else chosen, so each snippet draws
82
+ * the design as authored. The builders are tabbied/snippets, the same ones
83
+ * the site's editor copies from, so the two agree.
65
84
  */
66
- function reactSnippet(design) {
67
- const ratio = design.defaultAspectRatio ?? ASPECT_RATIO_DEFAULT;
68
- const [width, height] = /^(\d+):(\d+)$/.exec(ratio)?.slice(1) ?? ['2', '3'];
69
- const component = `${design.slug.charAt(0).toUpperCase()}${design.slug.slice(1)}Pattern`;
70
- return [
71
- `import { TabbiedPattern } from 'tabbied/react';`,
72
- `import { ${design.slug} } from 'tabbied/patterns';`,
73
- ``,
74
- `// As wide as its parent, at the ${width}:${height} ratio it was designed at.`,
75
- `// Add maxWidth to bound it, or swap aspectRatio for a fixed height.`,
76
- `export function ${component}() {`,
77
- ` return (`,
78
- ` <TabbiedPattern`,
79
- ` pattern={${design.slug}}`,
80
- ` aspectRatio="${width} / ${height}"`,
81
- ` />`,
82
- ` );`,
83
- `}`,
84
- ].join('\n');
85
+ function snippetInput(catalog, design) {
86
+ return {
87
+ slug: design.slug,
88
+ ratio: parseRatio(design.defaultAspectRatio),
89
+ ...(design.palette[0] ? { ground: design.palette[0] } : {}),
90
+ version: catalog.version,
91
+ };
85
92
  }
93
+ const isSetup = (value) => typeof value === 'string' && SNIPPET_SETUPS.includes(value);
86
94
  /** What the CLI command in `usage.cli` needs where it runs. */
87
95
  const CLI_SETUP = 'Rendering needs Playwright, found from the current directory first: ' +
88
96
  '`npm i -D playwright && npx playwright install chromium`. With nothing ' +
@@ -121,8 +129,9 @@ function searchTool(catalog) {
121
129
  properties: {
122
130
  query: {
123
131
  type: 'string',
124
- description: 'Free text matched against slug, name, and description. Every ' +
125
- 'whitespace-separated word must appear somewhere in the entry.',
132
+ description: 'Free text matched against slug, name, tags, mood, goodFor and ' +
133
+ 'description. Every whitespace-separated word must appear ' +
134
+ 'somewhere in the entry.',
126
135
  },
127
136
  tags: {
128
137
  type: 'array',
@@ -177,7 +186,7 @@ function searchTool(catalog) {
177
186
  ? Math.trunc(args.limit)
178
187
  : SEARCH_LIMIT_DEFAULT, 1), SEARCH_LIMIT_MAX);
179
188
  const matches = (design) => {
180
- const haystack = `${design.slug} ${design.name} ${design.description ?? ''}`.toLowerCase();
189
+ const haystack = designKeywords(design);
181
190
  return (terms.every((term) => haystack.includes(term)) &&
182
191
  (!wantTags || wantTags.every((tag) => design.tags.includes(tag))) &&
183
192
  (!wantMood || wantMood.every((mood) => design.mood.includes(mood))) &&
@@ -197,9 +206,7 @@ function searchTool(catalog) {
197
206
  const breakdown = [
198
207
  ...(terms.length
199
208
  ? [
200
- alone(`query "${args.query}"`, (design) => terms.every((term) => `${design.slug} ${design.name} ${design.description ?? ''}`
201
- .toLowerCase()
202
- .includes(term))),
209
+ alone(`query "${args.query}"`, (design) => terms.every((term) => designKeywords(design).includes(term))),
203
210
  ]
204
211
  : []),
205
212
  ...(wantTags ?? []).map((tag) => alone(`tag "${tag}"`, (design) => design.tags.includes(tag))),
@@ -251,8 +258,11 @@ function getDesignTool(catalog) {
251
258
  title: 'Get design details',
252
259
  description: 'The full catalog record for one design - palette, every option with its ' +
253
260
  'range and default, SVG-export support, preview URL - plus ready-to-paste ' +
254
- 'React and vanilla snippets. Call this once a slug is chosen; ' +
255
- 'search_designs already returns enough to shortlist.',
261
+ 'code for every setup: React, Vue, a Svelte action, the <tabbied-pattern> ' +
262
+ 'web component, plain HTML with no build step, and framework-free ' +
263
+ 'JavaScript (createPattern). Pass `framework` to get only the one the ' +
264
+ 'project uses. Call this once a slug is chosen; search_designs already ' +
265
+ 'returns enough to shortlist.',
256
266
  inputSchema: {
257
267
  type: 'object',
258
268
  properties: {
@@ -261,6 +271,14 @@ function getDesignTool(catalog) {
261
271
  minLength: 1,
262
272
  description: 'The design slug, e.g. "radius". Slugs are not guessable.',
263
273
  },
274
+ framework: {
275
+ type: 'string',
276
+ enum: [...SNIPPET_SETUPS],
277
+ description: 'Only this setup\'s snippet: react, vue, svelte (the action, ' +
278
+ 'SvelteKit included), element (the web component, for any page or ' +
279
+ 'CMS), html (data attributes and one script, no build step) or core ' +
280
+ '(createPattern on any element). Omit for all six.',
281
+ },
264
282
  },
265
283
  required: ['slug'],
266
284
  additionalProperties: false,
@@ -279,7 +297,16 @@ function getDesignTool(catalog) {
279
297
  : '') +
280
298
  'Use search_designs to find one - slugs are opaque and cannot be guessed.');
281
299
  }
282
- const snippet = (template) => template.replaceAll('<slug>', design.slug);
300
+ // The schema rejects an unknown setup before this runs; this keeps a
301
+ // direct call (the toolset, without the SDK in front) as strict.
302
+ const framework = args.framework;
303
+ if (framework != null && !isSetup(framework)) {
304
+ return toolError(`Unknown framework "${String(framework)}". One of: ${SNIPPET_SETUPS.join(', ')}.`);
305
+ }
306
+ const input = snippetInput(catalog, design);
307
+ const snippets = framework
308
+ ? { [framework]: buildSnippet(framework, input) }
309
+ : buildSnippets(input);
283
310
  // A design that cannot be vectorized gets a command that works.
284
311
  const extension = design.svgExport.supported ? 'svg' : 'png';
285
312
  return {
@@ -288,9 +315,8 @@ function getDesignTool(catalog) {
288
315
  ...design,
289
316
  usage: {
290
317
  install: catalog.usage.install,
291
- import: snippet(catalog.usage.import),
292
- react: reactSnippet(design),
293
- core: snippet(catalog.usage.core),
318
+ import: `import { ${design.slug} } from 'tabbied/patterns';`,
319
+ ...snippets,
294
320
  fit: catalog.usage.fit,
295
321
  cli: `npx tabbied render ${design.slug} --out ${design.slug}.${extension}`,
296
322
  cliSetup: CLI_SETUP,
@@ -387,8 +413,9 @@ function docsTool(context) {
387
413
  definition: {
388
414
  name: 'get_docs',
389
415
  title: 'Get the Tabbied reference',
390
- description: 'The complete agent-facing reference (llms-full.txt): entry points, the ' +
391
- 'React and vanilla APIs, sizing rules that compile but render wrong, ' +
416
+ description: 'The complete agent-facing reference (llms-full.txt): every entry point ' +
417
+ '(React, Vue, Svelte, the web component, plain HTML and the ' +
418
+ 'framework-free core), sizing rules that compile but render wrong, ' +
392
419
  'integration recipes, and the share-link URL scheme. Fetch this once ' +
393
420
  'before writing integration code; the per-design tools do not repeat it.',
394
421
  inputSchema: { type: 'object', additionalProperties: false },
package/dist/tools.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"tools.js","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"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","sourcesContent":["// The Tabbied toolset: four thin wrappers over catalog.json, the template tools\n// (templates.ts), and whatever the host adds (the stdio server adds\n// `render_design`).\n//\n// Nothing here touches node or the Worker runtime; the host injects what\n// differs via ToolContext, so both transports describe a design identically.\n//\n// The point is design *selection*. Slugs are opaque (\"cleat\", \"karst\") and\n// these are pictures, so search narrows on closed-vocabulary enums, then\n// preview_design puts the shortlist in front of the model before it commits.\nimport { templateTools } from './templates.js';\nimport type {\n Catalog,\n CatalogDesign,\n Tool,\n ToolContent,\n ToolContext,\n ToolDefinition,\n ToolResult,\n} from './types.js';\n\nconst SEARCH_LIMIT_DEFAULT = 20;\nconst SEARCH_LIMIT_MAX = 50;\nconst PREVIEW_MAX_SLUGS = 6;\n\n// Previews reach a few hundred KB and base64 adds a third, so six large ones\n// would spend megabytes of context. The batch stops early and says so rather\n// than silently truncating the list.\nconst PREVIEW_BYTE_BUDGET = 1_500_000;\n\n// ---- helpers ---------------------------------------------------------------\n\nconst text = (value: string): ToolContent => ({ type: 'text', text: value });\n\nconst json = (value: unknown): ToolContent =>\n text(JSON.stringify(value, null, 2));\n\nconst toolError = (message: string): ToolResult => ({\n content: [text(message)],\n isError: true,\n});\n\n/** Distinct values of a repeated field, sorted - the vocabulary actually in use. */\nfunction vocabulary(\n designs: CatalogDesign[],\n field: 'tags' | 'mood' | 'goodFor'\n): string[] {\n return [...new Set(designs.flatMap((design) => design[field]))].sort();\n}\n\nfunction densities(designs: CatalogDesign[]): string[] {\n return [...new Set(designs.map((design) => design.density))].sort();\n}\n\nfunction asStringArray(value: unknown): string[] | null {\n if (value == null) return null;\n const list = Array.isArray(value) ? value : [value];\n const strings = list.filter((entry): entry is string => typeof entry === 'string');\n return strings.length ? strings : null;\n}\n\n/** The compact form used in search hits - enough to shortlist, not the full record. */\nfunction summarize(design: CatalogDesign) {\n return {\n slug: design.slug,\n name: design.name,\n ...(design.description ? { description: design.description } : {}),\n tags: design.tags,\n mood: design.mood,\n density: design.density,\n goodFor: design.goodFor,\n svgExport: design.svgExport.supported,\n preview: design.preview,\n };\n}\n\nfunction findDesign(catalog: Catalog, slug: unknown): CatalogDesign | null {\n if (typeof slug !== 'string') return null;\n return catalog.designs.find((design) => design.slug === slug) ?? null;\n}\n\nconst ASPECT_RATIO_DEFAULT = '2:3';\n\n/**\n * The React snippet: a component at the design's own aspect ratio. The ratio\n * is the catalog's id (`2:3`) written as CSS's `2 / 3`, which is what the\n * prop takes - the id itself is not valid CSS and would size nothing. Same\n * shape as the editor's \"Copy React component\", so the two agree.\n */\nfunction reactSnippet(design: CatalogDesign): string {\n const ratio = design.defaultAspectRatio ?? ASPECT_RATIO_DEFAULT;\n const [width, height] = /^(\\d+):(\\d+)$/.exec(ratio)?.slice(1) ?? ['2', '3'];\n const component = `${design.slug.charAt(0).toUpperCase()}${design.slug.slice(1)}Pattern`;\n\n return [\n `import { TabbiedPattern } from 'tabbied/react';`,\n `import { ${design.slug} } from 'tabbied/patterns';`,\n ``,\n `// As wide as its parent, at the ${width}:${height} ratio it was designed at.`,\n `// Add maxWidth to bound it, or swap aspectRatio for a fixed height.`,\n `export function ${component}() {`,\n ` return (`,\n ` <TabbiedPattern`,\n ` pattern={${design.slug}}`,\n ` aspectRatio=\"${width} / ${height}\"`,\n ` />`,\n ` );`,\n `}`,\n ].join('\\n');\n}\n\n/** What the CLI command in `usage.cli` needs where it runs. */\nconst CLI_SETUP =\n 'Rendering needs Playwright, found from the current directory first: ' +\n '`npm i -D playwright && npx playwright install chromium`. With nothing ' +\n 'installed, run `npx -y -p tabbied -p playwright tabbied render ...` ' +\n 'instead (and `npx playwright install chromium` once).';\n\n/** Near misses for an unknown slug: a shared three-letter prefix, or a name match. */\nfunction suggestSlugs(catalog: Catalog, slug: string): string[] {\n const needle = slug.trim().toLowerCase();\n // An empty needle is a prefix of every slug, so it would \"suggest\" the first\n // eight in the catalog.\n if (!needle) return [];\n return catalog.designs\n .filter(\n (design) =>\n design.slug.startsWith(needle.slice(0, 3)) ||\n design.name.toLowerCase().includes(needle)\n )\n .slice(0, 8)\n .map((design) => design.slug);\n}\n\n// ---- search_designs --------------------------------------------------------\n\nfunction searchTool(catalog: Catalog): Tool {\n const tags = vocabulary(catalog.designs, 'tags');\n const moods = vocabulary(catalog.designs, 'mood');\n const goodFor = vocabulary(catalog.designs, 'goodFor');\n const densityValues = densities(catalog.designs);\n\n const definition: ToolDefinition = {\n name: 'search_designs',\n title: 'Search designs',\n description:\n `Find Tabbied designs by visible motif, feel, busyness, or intended use. ` +\n `Filters combine with AND - listing two tags returns only designs carrying ` +\n `both - so start broad and narrow. Returns compact entries including a ` +\n `preview image URL; follow up with preview_design to actually look at the ` +\n `shortlist before choosing, because these are pictures and the metadata ` +\n `only narrows the field. ${catalog.count} designs in total.`,\n inputSchema: {\n type: 'object',\n properties: {\n query: {\n type: 'string',\n description:\n 'Free text matched against slug, name, and description. Every ' +\n 'whitespace-separated word must appear somewhere in the entry.',\n },\n tags: {\n type: 'array',\n items: { type: 'string', enum: tags },\n description: 'Visible motifs. A design must carry every tag listed.',\n },\n mood: {\n type: 'array',\n items: { type: 'string', enum: moods },\n description: 'The feel of the design at a glance.',\n },\n density: {\n type: 'string',\n enum: densityValues,\n description:\n 'How busy the surface is. sparse takes overlaid text well; dense is ' +\n 'ink-dominated.',\n },\n goodFor: {\n type: 'array',\n items: { type: 'string', enum: goodFor },\n description: 'Uses the design suits with no customization.',\n },\n svgExport: {\n type: 'boolean',\n description:\n 'Restrict to designs that can (true) or cannot (false) be exported ' +\n 'as true vector SVG. Some use CSS (smooth conic sweeps, double or ' +\n 'dashed borders, 3D transforms) that SVG cannot represent faithfully.',\n },\n limit: {\n type: 'integer',\n minimum: 1,\n maximum: SEARCH_LIMIT_MAX,\n description: `Maximum hits to return (default ${SEARCH_LIMIT_DEFAULT}).`,\n },\n },\n additionalProperties: false,\n },\n annotations: { readOnlyHint: true, openWorldHint: false },\n };\n\n return {\n definition,\n run(args) {\n const wantTags = asStringArray(args.tags);\n const wantMood = asStringArray(args.mood);\n const wantGoodFor = asStringArray(args.goodFor);\n const density = typeof args.density === 'string' ? args.density : null;\n const svgExport =\n typeof args.svgExport === 'boolean' ? args.svgExport : null;\n const terms =\n typeof args.query === 'string'\n ? args.query.toLowerCase().split(/\\s+/).filter(Boolean)\n : [];\n\n const limit = Math.min(\n Math.max(\n typeof args.limit === 'number' && Number.isFinite(args.limit)\n ? Math.trunc(args.limit)\n : SEARCH_LIMIT_DEFAULT,\n 1\n ),\n SEARCH_LIMIT_MAX\n );\n\n const matches = (design: CatalogDesign) => {\n const haystack =\n `${design.slug} ${design.name} ${design.description ?? ''}`.toLowerCase();\n return (\n terms.every((term) => haystack.includes(term)) &&\n (!wantTags || wantTags.every((tag) => design.tags.includes(tag))) &&\n (!wantMood || wantMood.every((mood) => design.mood.includes(mood))) &&\n (!wantGoodFor ||\n wantGoodFor.every((use) => design.goodFor.includes(use))) &&\n (!density || design.density === density) &&\n (svgExport === null || design.svgExport.supported === svgExport)\n );\n };\n\n const hits = catalog.designs.filter(matches);\n\n // From an empty result an agent can't tell an over-narrow AND from a\n // wrongly guessed vocabulary, so report how each filter does on its own.\n if (hits.length === 0) {\n const alone = (label: string, predicate: (d: CatalogDesign) => boolean) => ({\n filter: label,\n matches: catalog.designs.filter(predicate).length,\n });\n const breakdown = [\n ...(terms.length\n ? [\n alone(`query \"${args.query}\"`, (design) =>\n terms.every((term) =>\n `${design.slug} ${design.name} ${design.description ?? ''}`\n .toLowerCase()\n .includes(term)\n )\n ),\n ]\n : []),\n ...(wantTags ?? []).map((tag) =>\n alone(`tag \"${tag}\"`, (design) => design.tags.includes(tag))\n ),\n ...(wantMood ?? []).map((mood) =>\n alone(`mood \"${mood}\"`, (design) => design.mood.includes(mood))\n ),\n ...(wantGoodFor ?? []).map((use) =>\n alone(`goodFor \"${use}\"`, (design) => design.goodFor.includes(use))\n ),\n ...(density\n ? [alone(`density \"${density}\"`, (design) => design.density === density)]\n : []),\n ...(svgExport !== null\n ? [alone(`svgExport ${svgExport}`, (design) => design.svgExport.supported === svgExport)]\n : []),\n ];\n\n return {\n content: [\n json({\n matched: 0,\n total: catalog.count,\n note:\n 'No design satisfies every filter at once. Each filter on its ' +\n 'own matches the counts below - drop the ones scoring 0 (likely ' +\n 'out of vocabulary) and relax the rest.',\n filtersIndependently: breakdown,\n vocabulary: {\n tags,\n mood: moods,\n density: densityValues,\n goodFor,\n },\n }),\n ],\n };\n }\n\n return {\n content: [\n json({\n matched: hits.length,\n total: catalog.count,\n returned: Math.min(hits.length, limit),\n designs: hits.slice(0, limit).map(summarize),\n }),\n ],\n };\n },\n };\n}\n\n// ---- get_design ------------------------------------------------------------\n\nfunction getDesignTool(catalog: Catalog): Tool {\n const definition: ToolDefinition = {\n name: 'get_design',\n title: 'Get design details',\n description:\n 'The full catalog record for one design - palette, every option with its ' +\n 'range and default, SVG-export support, preview URL - plus ready-to-paste ' +\n 'React and vanilla snippets. Call this once a slug is chosen; ' +\n 'search_designs already returns enough to shortlist.',\n inputSchema: {\n type: 'object',\n properties: {\n slug: {\n type: 'string',\n minLength: 1,\n description: 'The design slug, e.g. \"radius\". Slugs are not guessable.',\n },\n },\n required: ['slug'],\n additionalProperties: false,\n },\n annotations: { readOnlyHint: true, openWorldHint: false },\n };\n\n return {\n definition,\n run(args) {\n const design = findDesign(catalog, args.slug);\n if (!design) {\n const near = suggestSlugs(catalog, String(args.slug ?? ''));\n return toolError(\n `No design with slug \"${args.slug}\". ` +\n (near.length\n ? `Closest slugs: ${near.join(', ')}. `\n : '') +\n 'Use search_designs to find one - slugs are opaque and cannot be guessed.'\n );\n }\n\n const snippet = (template: string) =>\n template.replaceAll('<slug>', design.slug);\n\n // A design that cannot be vectorized gets a command that works.\n const extension = design.svgExport.supported ? 'svg' : 'png';\n\n return {\n content: [\n json({\n ...design,\n usage: {\n install: catalog.usage.install,\n import: snippet(catalog.usage.import),\n react: reactSnippet(design),\n core: snippet(catalog.usage.core),\n fit: catalog.usage.fit,\n cli: `npx tabbied render ${design.slug} --out ${design.slug}.${extension}`,\n cliSetup: CLI_SETUP,\n },\n // The number-one integration mistake, repeated here because an\n // agent that called get_design may never read llms-full.txt.\n sizing:\n 'A pattern has no intrinsic size - it fills its parent, and ' +\n 'collapses to nothing in a parent that sizes to content. Pass ' +\n 'height or aspectRatio when in doubt.',\n ...(design.svgExport.supported\n ? {}\n : {\n svgExportWarning:\n 'This design cannot be exported as vector SVG. Render it as PNG instead.',\n }),\n }),\n ],\n };\n },\n };\n}\n\n// ---- preview_design --------------------------------------------------------\n\nfunction previewTool(context: ToolContext): Tool | null {\n const { catalog, fetchPreview } = context;\n if (!fetchPreview) return null;\n\n const definition: ToolDefinition = {\n name: 'preview_design',\n title: 'Look at designs',\n description:\n `Return the rendered preview image for up to ${PREVIEW_MAX_SLUGS} designs, ` +\n 'so you can see them rather than infer them from tags. Previews use each ' +\n \"design's authored palette, default options, and a fixed seed. This is the \" +\n 'step that makes a choice reliable - do it before committing to a slug.',\n inputSchema: {\n type: 'object',\n properties: {\n slugs: {\n type: 'array',\n items: { type: 'string', minLength: 1 },\n minItems: 1,\n maxItems: PREVIEW_MAX_SLUGS,\n description: 'Design slugs to look at, e.g. [\"radius\", \"cleat\"].',\n },\n },\n required: ['slugs'],\n additionalProperties: false,\n },\n annotations: { readOnlyHint: true, openWorldHint: true },\n };\n\n return {\n definition,\n async run(args) {\n const slugs = asStringArray(args.slugs);\n if (!slugs) {\n return toolError('Pass \"slugs\" as a non-empty array of design slugs.');\n }\n\n const requested = slugs.slice(0, PREVIEW_MAX_SLUGS);\n const content: ToolContent[] = [];\n let spent = 0;\n let found = 0;\n\n for (const [index, slug] of requested.entries()) {\n const design = findDesign(catalog, slug);\n if (!design) {\n content.push(\n text(`${slug}: no such design. Use search_designs to find valid slugs.`)\n );\n continue;\n }\n found += 1;\n\n if (spent > PREVIEW_BYTE_BUDGET) {\n content.push(\n text(\n `Stopped after ${index} image(s) to stay within a sane response ` +\n `size. Ask again for the rest: ${requested.slice(index).join(', ')}.`\n )\n );\n break;\n }\n\n try {\n const { data, mimeType } = await fetchPreview(design);\n spent += data.length;\n content.push(\n text(\n `${design.slug} - ${design.name}` +\n (design.description ? `: ${design.description}` : '')\n ),\n { type: 'image', data, mimeType }\n );\n } catch (error) {\n content.push(\n text(\n `${design.slug}: preview unavailable (${\n error instanceof Error ? error.message : String(error)\n }). The image is also at ${design.preview}.`\n )\n );\n }\n }\n\n // One bad slug among good ones is a note beside the images; a call in\n // which nothing resolved has failed, and says so.\n return found > 0 ? { content } : { content, isError: true };\n },\n };\n}\n\n// ---- get_docs --------------------------------------------------------------\n\nfunction docsTool(context: ToolContext): Tool | null {\n const { fetchDocs } = context;\n if (!fetchDocs) return null;\n\n return {\n definition: {\n name: 'get_docs',\n title: 'Get the Tabbied reference',\n description:\n 'The complete agent-facing reference (llms-full.txt): entry points, the ' +\n 'React and vanilla APIs, sizing rules that compile but render wrong, ' +\n 'integration recipes, and the share-link URL scheme. Fetch this once ' +\n 'before writing integration code; the per-design tools do not repeat it.',\n inputSchema: { type: 'object', additionalProperties: false },\n annotations: { readOnlyHint: true, openWorldHint: true },\n },\n async run() {\n try {\n return { content: [text(await fetchDocs())] };\n } catch (error) {\n return toolError(\n `Could not load the reference (${\n error instanceof Error ? error.message : String(error)\n }). It is also served at https://tabbied.com/llms-full.txt.`\n );\n }\n },\n };\n}\n\n// ---- assembly --------------------------------------------------------------\n\n/**\n * The catalog-backed tools available in every runtime, template tools\n * included. A host opts into a tool by supplying its fetcher in the one\n * context, so the tool list follows from what the host can resolve.\n */\nexport function catalogTools(context: ToolContext): Tool[] {\n return [\n searchTool(context.catalog),\n getDesignTool(context.catalog),\n previewTool(context),\n docsTool(context),\n ...templateTools(context),\n ].filter((tool): tool is Tool => tool !== null);\n}\n\nexport type Toolset = {\n list(): ToolDefinition[];\n call(name: string, args: Record<string, unknown>): Promise<ToolResult>;\n has(name: string): boolean;\n};\n\n/**\n * Bundle tools into a name lookup. Handler throws become `isError` results\n * rather than JSON-RPC errors: the spec reserves protocol errors for malformed\n * requests and sends execution failures back to the model to retry.\n */\nexport function createToolset(tools: Tool[]): Toolset {\n const byName = new Map(tools.map((tool) => [tool.definition.name, tool]));\n\n return {\n list: () => tools.map((tool) => tool.definition),\n has: (name) => byName.has(name),\n async call(name, args) {\n const tool = byName.get(name);\n if (!tool) {\n return toolError(\n `Unknown tool \"${name}\". Available: ${[...byName.keys()].join(', ')}.`\n );\n }\n try {\n return await tool.run(args ?? {});\n } catch (error) {\n return toolError(\n error instanceof Error ? error.message : String(error)\n );\n }\n },\n };\n}\n"]}
1
+ {"version":3,"file":"tools.js","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"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","sourcesContent":["// The Tabbied toolset: four thin wrappers over catalog.json, the template tools\n// (templates.ts), and whatever the host adds (the stdio server adds\n// `render_design`).\n//\n// Nothing here touches node or the Worker runtime; the host injects what\n// differs via ToolContext, so both transports describe a design identically.\n//\n// The point is design *selection*. Slugs are opaque (\"cleat\", \"karst\") and\n// these are pictures, so search narrows on closed-vocabulary enums, then\n// preview_design puts the shortlist in front of the model before it commits.\nimport {\n SNIPPET_SETUPS,\n buildSnippet,\n buildSnippets,\n parseRatio,\n type SnippetInput,\n type SnippetSetup,\n} from 'tabbied/snippets';\n\nimport { templateTools } from './templates.js';\nimport type {\n Catalog,\n CatalogDesign,\n Tool,\n ToolContent,\n ToolContext,\n ToolDefinition,\n ToolResult,\n} from './types.js';\n\nconst SEARCH_LIMIT_DEFAULT = 20;\nconst SEARCH_LIMIT_MAX = 50;\nconst PREVIEW_MAX_SLUGS = 6;\n\n// Previews reach a few hundred KB and base64 adds a third, so six large ones\n// would spend megabytes of context. The batch stops early and says so rather\n// than silently truncating the list.\nconst PREVIEW_BYTE_BUDGET = 1_500_000;\n\n// ---- helpers ---------------------------------------------------------------\n\nconst text = (value: string): ToolContent => ({ type: 'text', text: value });\n\nconst json = (value: unknown): ToolContent =>\n text(JSON.stringify(value, null, 2));\n\nconst toolError = (message: string): ToolResult => ({\n content: [text(message)],\n isError: true,\n});\n\n/** Distinct values of a repeated field, sorted - the vocabulary actually in use. */\nfunction vocabulary(\n designs: CatalogDesign[],\n field: 'tags' | 'mood' | 'goodFor'\n): string[] {\n return [...new Set(designs.flatMap((design) => design[field]))].sort();\n}\n\nfunction densities(designs: CatalogDesign[]): string[] {\n return [...new Set(designs.map((design) => design.density))].sort();\n}\n\nfunction asStringArray(value: unknown): string[] | null {\n if (value == null) return null;\n const list = Array.isArray(value) ? value : [value];\n const strings = list.filter((entry): entry is string => typeof entry === 'string');\n return strings.length ? strings : null;\n}\n\n/** The compact form used in search hits - enough to shortlist, not the full record. */\nfunction summarize(design: CatalogDesign) {\n return {\n slug: design.slug,\n name: design.name,\n ...(design.description ? { description: design.description } : {}),\n tags: design.tags,\n mood: design.mood,\n density: design.density,\n goodFor: design.goodFor,\n svgExport: design.svgExport.supported,\n preview: design.preview,\n };\n}\n\n/**\n * What a free-text query is matched against: slug, name, the closed-vocabulary\n * tags, moods and uses, and the description. The site's gallery search\n * (lib/catalogSearch.ts) reads the same fields, so \"dots\" finds the designs\n * tagged dots in both, not only one whose name says it.\n */\nfunction designKeywords(design: CatalogDesign): string {\n return [\n design.slug,\n design.name,\n ...design.tags,\n ...design.mood,\n ...design.goodFor,\n design.description ?? '',\n ]\n .join(' ')\n .toLowerCase();\n}\n\nfunction findDesign(catalog: Catalog, slug: unknown): CatalogDesign | null {\n if (typeof slug !== 'string') return null;\n return catalog.designs.find((design) => design.slug === slug) ?? null;\n}\n\n/**\n * The snippets' input for one design as the catalog describes it: its own\n * ratio (the catalog's `2:3` id, which the builders write as CSS's `2 / 3`)\n * and its own ground color, with nothing else chosen, so each snippet draws\n * the design as authored. The builders are tabbied/snippets, the same ones\n * the site's editor copies from, so the two agree.\n */\nfunction snippetInput(catalog: Catalog, design: CatalogDesign): SnippetInput {\n return {\n slug: design.slug,\n ratio: parseRatio(design.defaultAspectRatio),\n ...(design.palette[0] ? { ground: design.palette[0] } : {}),\n version: catalog.version,\n };\n}\n\nconst isSetup = (value: unknown): value is SnippetSetup =>\n typeof value === 'string' && (SNIPPET_SETUPS as readonly string[]).includes(value);\n\n/** What the CLI command in `usage.cli` needs where it runs. */\nconst CLI_SETUP =\n 'Rendering needs Playwright, found from the current directory first: ' +\n '`npm i -D playwright && npx playwright install chromium`. With nothing ' +\n 'installed, run `npx -y -p tabbied -p playwright tabbied render ...` ' +\n 'instead (and `npx playwright install chromium` once).';\n\n/** Near misses for an unknown slug: a shared three-letter prefix, or a name match. */\nfunction suggestSlugs(catalog: Catalog, slug: string): string[] {\n const needle = slug.trim().toLowerCase();\n // An empty needle is a prefix of every slug, so it would \"suggest\" the first\n // eight in the catalog.\n if (!needle) return [];\n return catalog.designs\n .filter(\n (design) =>\n design.slug.startsWith(needle.slice(0, 3)) ||\n design.name.toLowerCase().includes(needle)\n )\n .slice(0, 8)\n .map((design) => design.slug);\n}\n\n// ---- search_designs --------------------------------------------------------\n\nfunction searchTool(catalog: Catalog): Tool {\n const tags = vocabulary(catalog.designs, 'tags');\n const moods = vocabulary(catalog.designs, 'mood');\n const goodFor = vocabulary(catalog.designs, 'goodFor');\n const densityValues = densities(catalog.designs);\n\n const definition: ToolDefinition = {\n name: 'search_designs',\n title: 'Search designs',\n description:\n `Find Tabbied designs by visible motif, feel, busyness, or intended use. ` +\n `Filters combine with AND - listing two tags returns only designs carrying ` +\n `both - so start broad and narrow. Returns compact entries including a ` +\n `preview image URL; follow up with preview_design to actually look at the ` +\n `shortlist before choosing, because these are pictures and the metadata ` +\n `only narrows the field. ${catalog.count} designs in total.`,\n inputSchema: {\n type: 'object',\n properties: {\n query: {\n type: 'string',\n description:\n 'Free text matched against slug, name, tags, mood, goodFor and ' +\n 'description. Every whitespace-separated word must appear ' +\n 'somewhere in the entry.',\n },\n tags: {\n type: 'array',\n items: { type: 'string', enum: tags },\n description: 'Visible motifs. A design must carry every tag listed.',\n },\n mood: {\n type: 'array',\n items: { type: 'string', enum: moods },\n description: 'The feel of the design at a glance.',\n },\n density: {\n type: 'string',\n enum: densityValues,\n description:\n 'How busy the surface is. sparse takes overlaid text well; dense is ' +\n 'ink-dominated.',\n },\n goodFor: {\n type: 'array',\n items: { type: 'string', enum: goodFor },\n description: 'Uses the design suits with no customization.',\n },\n svgExport: {\n type: 'boolean',\n description:\n 'Restrict to designs that can (true) or cannot (false) be exported ' +\n 'as true vector SVG. Some use CSS (smooth conic sweeps, double or ' +\n 'dashed borders, 3D transforms) that SVG cannot represent faithfully.',\n },\n limit: {\n type: 'integer',\n minimum: 1,\n maximum: SEARCH_LIMIT_MAX,\n description: `Maximum hits to return (default ${SEARCH_LIMIT_DEFAULT}).`,\n },\n },\n additionalProperties: false,\n },\n annotations: { readOnlyHint: true, openWorldHint: false },\n };\n\n return {\n definition,\n run(args) {\n const wantTags = asStringArray(args.tags);\n const wantMood = asStringArray(args.mood);\n const wantGoodFor = asStringArray(args.goodFor);\n const density = typeof args.density === 'string' ? args.density : null;\n const svgExport =\n typeof args.svgExport === 'boolean' ? args.svgExport : null;\n const terms =\n typeof args.query === 'string'\n ? args.query.toLowerCase().split(/\\s+/).filter(Boolean)\n : [];\n\n const limit = Math.min(\n Math.max(\n typeof args.limit === 'number' && Number.isFinite(args.limit)\n ? Math.trunc(args.limit)\n : SEARCH_LIMIT_DEFAULT,\n 1\n ),\n SEARCH_LIMIT_MAX\n );\n\n const matches = (design: CatalogDesign) => {\n const haystack = designKeywords(design);\n return (\n terms.every((term) => haystack.includes(term)) &&\n (!wantTags || wantTags.every((tag) => design.tags.includes(tag))) &&\n (!wantMood || wantMood.every((mood) => design.mood.includes(mood))) &&\n (!wantGoodFor ||\n wantGoodFor.every((use) => design.goodFor.includes(use))) &&\n (!density || design.density === density) &&\n (svgExport === null || design.svgExport.supported === svgExport)\n );\n };\n\n const hits = catalog.designs.filter(matches);\n\n // From an empty result an agent can't tell an over-narrow AND from a\n // wrongly guessed vocabulary, so report how each filter does on its own.\n if (hits.length === 0) {\n const alone = (label: string, predicate: (d: CatalogDesign) => boolean) => ({\n filter: label,\n matches: catalog.designs.filter(predicate).length,\n });\n const breakdown = [\n ...(terms.length\n ? [\n alone(`query \"${args.query}\"`, (design) =>\n terms.every((term) => designKeywords(design).includes(term))\n ),\n ]\n : []),\n ...(wantTags ?? []).map((tag) =>\n alone(`tag \"${tag}\"`, (design) => design.tags.includes(tag))\n ),\n ...(wantMood ?? []).map((mood) =>\n alone(`mood \"${mood}\"`, (design) => design.mood.includes(mood))\n ),\n ...(wantGoodFor ?? []).map((use) =>\n alone(`goodFor \"${use}\"`, (design) => design.goodFor.includes(use))\n ),\n ...(density\n ? [alone(`density \"${density}\"`, (design) => design.density === density)]\n : []),\n ...(svgExport !== null\n ? [alone(`svgExport ${svgExport}`, (design) => design.svgExport.supported === svgExport)]\n : []),\n ];\n\n return {\n content: [\n json({\n matched: 0,\n total: catalog.count,\n note:\n 'No design satisfies every filter at once. Each filter on its ' +\n 'own matches the counts below - drop the ones scoring 0 (likely ' +\n 'out of vocabulary) and relax the rest.',\n filtersIndependently: breakdown,\n vocabulary: {\n tags,\n mood: moods,\n density: densityValues,\n goodFor,\n },\n }),\n ],\n };\n }\n\n return {\n content: [\n json({\n matched: hits.length,\n total: catalog.count,\n returned: Math.min(hits.length, limit),\n designs: hits.slice(0, limit).map(summarize),\n }),\n ],\n };\n },\n };\n}\n\n// ---- get_design ------------------------------------------------------------\n\nfunction getDesignTool(catalog: Catalog): Tool {\n const definition: ToolDefinition = {\n name: 'get_design',\n title: 'Get design details',\n description:\n 'The full catalog record for one design - palette, every option with its ' +\n 'range and default, SVG-export support, preview URL - plus ready-to-paste ' +\n 'code for every setup: React, Vue, a Svelte action, the <tabbied-pattern> ' +\n 'web component, plain HTML with no build step, and framework-free ' +\n 'JavaScript (createPattern). Pass `framework` to get only the one the ' +\n 'project uses. Call this once a slug is chosen; search_designs already ' +\n 'returns enough to shortlist.',\n inputSchema: {\n type: 'object',\n properties: {\n slug: {\n type: 'string',\n minLength: 1,\n description: 'The design slug, e.g. \"radius\". Slugs are not guessable.',\n },\n framework: {\n type: 'string',\n enum: [...SNIPPET_SETUPS],\n description:\n 'Only this setup\\'s snippet: react, vue, svelte (the action, ' +\n 'SvelteKit included), element (the web component, for any page or ' +\n 'CMS), html (data attributes and one script, no build step) or core ' +\n '(createPattern on any element). Omit for all six.',\n },\n },\n required: ['slug'],\n additionalProperties: false,\n },\n annotations: { readOnlyHint: true, openWorldHint: false },\n };\n\n return {\n definition,\n run(args) {\n const design = findDesign(catalog, args.slug);\n if (!design) {\n const near = suggestSlugs(catalog, String(args.slug ?? ''));\n return toolError(\n `No design with slug \"${args.slug}\". ` +\n (near.length\n ? `Closest slugs: ${near.join(', ')}. `\n : '') +\n 'Use search_designs to find one - slugs are opaque and cannot be guessed.'\n );\n }\n\n // The schema rejects an unknown setup before this runs; this keeps a\n // direct call (the toolset, without the SDK in front) as strict.\n const framework = args.framework;\n if (framework != null && !isSetup(framework)) {\n return toolError(\n `Unknown framework \"${String(framework)}\". One of: ${SNIPPET_SETUPS.join(', ')}.`\n );\n }\n\n const input = snippetInput(catalog, design);\n const snippets = framework\n ? { [framework]: buildSnippet(framework, input) }\n : buildSnippets(input);\n\n // A design that cannot be vectorized gets a command that works.\n const extension = design.svgExport.supported ? 'svg' : 'png';\n\n return {\n content: [\n json({\n ...design,\n usage: {\n install: catalog.usage.install,\n import: `import { ${design.slug} } from 'tabbied/patterns';`,\n ...snippets,\n fit: catalog.usage.fit,\n cli: `npx tabbied render ${design.slug} --out ${design.slug}.${extension}`,\n cliSetup: CLI_SETUP,\n },\n // The number-one integration mistake, repeated here because an\n // agent that called get_design may never read llms-full.txt.\n sizing:\n 'A pattern has no intrinsic size - it fills its parent, and ' +\n 'collapses to nothing in a parent that sizes to content. Pass ' +\n 'height or aspectRatio when in doubt.',\n ...(design.svgExport.supported\n ? {}\n : {\n svgExportWarning:\n 'This design cannot be exported as vector SVG. Render it as PNG instead.',\n }),\n }),\n ],\n };\n },\n };\n}\n\n// ---- preview_design --------------------------------------------------------\n\nfunction previewTool(context: ToolContext): Tool | null {\n const { catalog, fetchPreview } = context;\n if (!fetchPreview) return null;\n\n const definition: ToolDefinition = {\n name: 'preview_design',\n title: 'Look at designs',\n description:\n `Return the rendered preview image for up to ${PREVIEW_MAX_SLUGS} designs, ` +\n 'so you can see them rather than infer them from tags. Previews use each ' +\n \"design's authored palette, default options, and a fixed seed. This is the \" +\n 'step that makes a choice reliable - do it before committing to a slug.',\n inputSchema: {\n type: 'object',\n properties: {\n slugs: {\n type: 'array',\n items: { type: 'string', minLength: 1 },\n minItems: 1,\n maxItems: PREVIEW_MAX_SLUGS,\n description: 'Design slugs to look at, e.g. [\"radius\", \"cleat\"].',\n },\n },\n required: ['slugs'],\n additionalProperties: false,\n },\n annotations: { readOnlyHint: true, openWorldHint: true },\n };\n\n return {\n definition,\n async run(args) {\n const slugs = asStringArray(args.slugs);\n if (!slugs) {\n return toolError('Pass \"slugs\" as a non-empty array of design slugs.');\n }\n\n const requested = slugs.slice(0, PREVIEW_MAX_SLUGS);\n const content: ToolContent[] = [];\n let spent = 0;\n let found = 0;\n\n for (const [index, slug] of requested.entries()) {\n const design = findDesign(catalog, slug);\n if (!design) {\n content.push(\n text(`${slug}: no such design. Use search_designs to find valid slugs.`)\n );\n continue;\n }\n found += 1;\n\n if (spent > PREVIEW_BYTE_BUDGET) {\n content.push(\n text(\n `Stopped after ${index} image(s) to stay within a sane response ` +\n `size. Ask again for the rest: ${requested.slice(index).join(', ')}.`\n )\n );\n break;\n }\n\n try {\n const { data, mimeType } = await fetchPreview(design);\n spent += data.length;\n content.push(\n text(\n `${design.slug} - ${design.name}` +\n (design.description ? `: ${design.description}` : '')\n ),\n { type: 'image', data, mimeType }\n );\n } catch (error) {\n content.push(\n text(\n `${design.slug}: preview unavailable (${\n error instanceof Error ? error.message : String(error)\n }). The image is also at ${design.preview}.`\n )\n );\n }\n }\n\n // One bad slug among good ones is a note beside the images; a call in\n // which nothing resolved has failed, and says so.\n return found > 0 ? { content } : { content, isError: true };\n },\n };\n}\n\n// ---- get_docs --------------------------------------------------------------\n\nfunction docsTool(context: ToolContext): Tool | null {\n const { fetchDocs } = context;\n if (!fetchDocs) return null;\n\n return {\n definition: {\n name: 'get_docs',\n title: 'Get the Tabbied reference',\n description:\n 'The complete agent-facing reference (llms-full.txt): every entry point ' +\n '(React, Vue, Svelte, the web component, plain HTML and the ' +\n 'framework-free core), sizing rules that compile but render wrong, ' +\n 'integration recipes, and the share-link URL scheme. Fetch this once ' +\n 'before writing integration code; the per-design tools do not repeat it.',\n inputSchema: { type: 'object', additionalProperties: false },\n annotations: { readOnlyHint: true, openWorldHint: true },\n },\n async run() {\n try {\n return { content: [text(await fetchDocs())] };\n } catch (error) {\n return toolError(\n `Could not load the reference (${\n error instanceof Error ? error.message : String(error)\n }). It is also served at https://tabbied.com/llms-full.txt.`\n );\n }\n },\n };\n}\n\n// ---- assembly --------------------------------------------------------------\n\n/**\n * The catalog-backed tools available in every runtime, template tools\n * included. A host opts into a tool by supplying its fetcher in the one\n * context, so the tool list follows from what the host can resolve.\n */\nexport function catalogTools(context: ToolContext): Tool[] {\n return [\n searchTool(context.catalog),\n getDesignTool(context.catalog),\n previewTool(context),\n docsTool(context),\n ...templateTools(context),\n ].filter((tool): tool is Tool => tool !== null);\n}\n\nexport type Toolset = {\n list(): ToolDefinition[];\n call(name: string, args: Record<string, unknown>): Promise<ToolResult>;\n has(name: string): boolean;\n};\n\n/**\n * Bundle tools into a name lookup. Handler throws become `isError` results\n * rather than JSON-RPC errors: the spec reserves protocol errors for malformed\n * requests and sends execution failures back to the model to retry.\n */\nexport function createToolset(tools: Tool[]): Toolset {\n const byName = new Map(tools.map((tool) => [tool.definition.name, tool]));\n\n return {\n list: () => tools.map((tool) => tool.definition),\n has: (name) => byName.has(name),\n async call(name, args) {\n const tool = byName.get(name);\n if (!tool) {\n return toolError(\n `Unknown tool \"${name}\". Available: ${[...byName.keys()].join(', ')}.`\n );\n }\n try {\n return await tool.run(args ?? {});\n } catch (error) {\n return toolError(\n error instanceof Error ? error.message : String(error)\n );\n }\n },\n };\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tabbied-mcp",
3
- "version": "0.2.4",
3
+ "version": "0.3.0",
4
4
  "description": "MCP server for Tabbied: search, look at, and render its generative pattern designs from any MCP client.",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -49,7 +49,7 @@
49
49
  },
50
50
  "dependencies": {
51
51
  "@modelcontextprotocol/server": "^2.2.0",
52
- "tabbied": "^0.8.0"
52
+ "tabbied": "^0.9.0"
53
53
  },
54
54
  "devDependencies": {
55
55
  "@types/node": "^26.6.3",