@viglet/viglet-design-system 2026.3.9 → 2026.3.11
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 +528 -44
- package/consumers.json +186 -0
- package/dist/badge-locale-CJkHDlPg.cjs +1 -0
- package/dist/badge-locale-DxDp8Q3S.js +397 -0
- package/dist/bento/bento-actions-menu.d.ts +8 -0
- package/dist/bento/bento-actions-menu.d.ts.map +1 -1
- package/dist/bento/bento-back-to-top.d.ts +9 -1
- package/dist/bento/bento-back-to-top.d.ts.map +1 -1
- package/dist/bento/bento-command-palette.d.ts +56 -9
- package/dist/bento/bento-command-palette.d.ts.map +1 -1
- package/dist/bento/bento-data-table.d.ts +81 -0
- package/dist/bento/bento-data-table.d.ts.map +1 -0
- package/dist/bento/bento-diff.d.ts +41 -0
- package/dist/bento/bento-diff.d.ts.map +1 -0
- package/dist/bento/bento-empty-state.d.ts +8 -1
- package/dist/bento/bento-empty-state.d.ts.map +1 -1
- package/dist/bento/bento-entity-shell.d.ts.map +1 -1
- package/dist/bento/bento-filter-bar.d.ts +60 -0
- package/dist/bento/bento-filter-bar.d.ts.map +1 -0
- package/dist/bento/bento-form-section.d.ts +14 -1
- package/dist/bento/bento-form-section.d.ts.map +1 -1
- package/dist/bento/bento-inline-edit.d.ts.map +1 -1
- package/dist/bento/bento-nav-rail.d.ts +13 -13
- package/dist/bento/bento-nav-rail.d.ts.map +1 -1
- package/dist/bento/bento-nav.d.ts +10 -2
- package/dist/bento/bento-nav.d.ts.map +1 -1
- package/dist/bento/bento-palette-trigger.d.ts +18 -0
- package/dist/bento/bento-palette-trigger.d.ts.map +1 -0
- package/dist/bento/bento-section-chrome.d.ts +19 -39
- package/dist/bento/bento-section-chrome.d.ts.map +1 -1
- package/dist/bento/bento-shell-shortcuts.d.ts +67 -0
- package/dist/bento/bento-shell-shortcuts.d.ts.map +1 -0
- package/dist/bento/bento-shell.d.ts +53 -0
- package/dist/bento/bento-shell.d.ts.map +1 -0
- package/dist/bento/bento-shortcuts-dialog.d.ts +9 -7
- package/dist/bento/bento-shortcuts-dialog.d.ts.map +1 -1
- package/dist/bento/bento-status-marker.d.ts +5 -2
- package/dist/bento/bento-status-marker.d.ts.map +1 -1
- package/dist/bento/bento-tile.d.ts.map +1 -1
- package/dist/bento/bento-user-menu.d.ts +9 -8
- package/dist/bento/bento-user-menu.d.ts.map +1 -1
- package/dist/bento/bento-version-rail.d.ts +31 -0
- package/dist/bento/bento-version-rail.d.ts.map +1 -0
- package/dist/bento/index.d.ts +15 -6
- package/dist/bento/index.d.ts.map +1 -1
- package/dist/bento.cjs +5 -1
- package/dist/bento.css +70 -4
- package/dist/bento.es.js +1778 -701
- package/dist/catalogue.json +5283 -0
- package/dist/components/app-footer.d.ts +7 -0
- package/dist/components/app-footer.d.ts.map +1 -1
- package/dist/components/app-switcher.d.ts.map +1 -1
- package/dist/components/backend-status.d.ts +19 -11
- package/dist/components/backend-status.d.ts.map +1 -1
- package/dist/components/badge-colorful.d.ts +13 -0
- package/dist/components/badge-colorful.d.ts.map +1 -1
- package/dist/components/badge-locale.d.ts +7 -0
- package/dist/components/badge-locale.d.ts.map +1 -1
- package/dist/components/error-boundary.d.ts +15 -13
- package/dist/components/error-boundary.d.ts.map +1 -1
- package/dist/components/language-select.d.ts +8 -0
- package/dist/components/language-select.d.ts.map +1 -1
- package/dist/components/login/login.d.ts +27 -0
- package/dist/components/login/login.d.ts.map +1 -1
- package/dist/components/mode-toggle.d.ts +9 -0
- package/dist/components/mode-toggle.d.ts.map +1 -1
- package/dist/components/nav-secondary.d.ts +7 -0
- package/dist/components/nav-secondary.d.ts.map +1 -1
- package/dist/components/router/dialog.delete.d.ts +8 -0
- package/dist/components/router/dialog.delete.d.ts.map +1 -1
- package/dist/components/router/gradient-button-link.d.ts +6 -0
- package/dist/components/router/gradient-button-link.d.ts.map +1 -1
- package/dist/components/router/index.d.ts +0 -11
- package/dist/components/router/index.d.ts.map +1 -1
- package/dist/components/router/loading-provider.d.ts +4 -0
- package/dist/components/router/loading-provider.d.ts.map +1 -1
- package/dist/components/startup-first/startup-first.d.ts +29 -0
- package/dist/components/startup-first/startup-first.d.ts.map +1 -1
- package/dist/components/ui/accordion.d.ts +17 -0
- package/dist/components/ui/accordion.d.ts.map +1 -1
- package/dist/components/ui/avatar.d.ts +14 -0
- package/dist/components/ui/avatar.d.ts.map +1 -1
- package/dist/components/ui/badge.d.ts +6 -0
- package/dist/components/ui/badge.d.ts.map +1 -1
- package/dist/components/ui/breadcrumb.d.ts +25 -0
- package/dist/components/ui/breadcrumb.d.ts.map +1 -1
- package/dist/components/ui/button.d.ts +15 -1
- package/dist/components/ui/button.d.ts.map +1 -1
- package/dist/components/ui/card.d.ts +27 -0
- package/dist/components/ui/card.d.ts.map +1 -1
- package/dist/components/ui/checkbox.d.ts +4 -0
- package/dist/components/ui/checkbox.d.ts.map +1 -1
- package/dist/components/ui/dialog.d.ts +36 -0
- package/dist/components/ui/dialog.d.ts.map +1 -1
- package/dist/components/ui/drawer.d.ts +35 -0
- package/dist/components/ui/drawer.d.ts.map +1 -1
- package/dist/components/ui/dropdown-menu.d.ts +53 -0
- package/dist/components/ui/dropdown-menu.d.ts.map +1 -1
- package/dist/components/ui/floating-formulas-bg.d.ts +8 -0
- package/dist/components/ui/floating-formulas-bg.d.ts.map +1 -1
- package/dist/components/ui/form-actions.d.ts +7 -0
- package/dist/components/ui/form-actions.d.ts.map +1 -1
- package/dist/components/ui/form-item-two-columns.d.ts +7 -0
- package/dist/components/ui/form-item-two-columns.d.ts.map +1 -1
- package/dist/components/ui/form.d.ts +25 -0
- package/dist/components/ui/form.d.ts.map +1 -1
- package/dist/components/ui/glass-card.d.ts +18 -14
- package/dist/components/ui/glass-card.d.ts.map +1 -1
- package/dist/components/ui/gradient-button.d.ts +15 -1
- package/dist/components/ui/gradient-button.d.ts.map +1 -1
- package/dist/components/ui/gradient-switch.d.ts +6 -0
- package/dist/components/ui/gradient-switch.d.ts.map +1 -1
- package/dist/components/ui/hover-card.d.ts +14 -0
- package/dist/components/ui/hover-card.d.ts.map +1 -1
- package/dist/components/ui/icon-picker-dialog.d.ts.map +1 -1
- package/dist/components/ui/index.d.ts +6 -4
- package/dist/components/ui/index.d.ts.map +1 -1
- package/dist/components/ui/input.d.ts +6 -0
- package/dist/components/ui/input.d.ts.map +1 -1
- package/dist/components/ui/label.d.ts +4 -0
- package/dist/components/ui/label.d.ts.map +1 -1
- package/dist/components/ui/navigation-menu.d.ts +41 -0
- package/dist/components/ui/navigation-menu.d.ts.map +1 -1
- package/dist/components/ui/pagination.d.ts +25 -0
- package/dist/components/ui/pagination.d.ts.map +1 -1
- package/dist/components/ui/popover.d.ts +24 -0
- package/dist/components/ui/popover.d.ts.map +1 -1
- package/dist/components/ui/progress.d.ts +4 -0
- package/dist/components/ui/progress.d.ts.map +1 -1
- package/dist/components/ui/pulse-ring.d.ts +9 -11
- package/dist/components/ui/pulse-ring.d.ts.map +1 -1
- package/dist/components/ui/resizable.d.ts +11 -0
- package/dist/components/ui/resizable.d.ts.map +1 -1
- package/dist/components/ui/section-card.d.ts +9 -0
- package/dist/components/ui/section-card.d.ts.map +1 -1
- package/dist/components/ui/select.d.ts +36 -0
- package/dist/components/ui/select.d.ts.map +1 -1
- package/dist/components/ui/separator.d.ts +4 -0
- package/dist/components/ui/separator.d.ts.map +1 -1
- package/dist/components/ui/sheet.d.ts +29 -0
- package/dist/components/ui/sheet.d.ts.map +1 -1
- package/dist/components/ui/sidebar.d.ts +83 -0
- package/dist/components/ui/sidebar.d.ts.map +1 -1
- package/dist/components/ui/skeleton.d.ts +4 -0
- package/dist/components/ui/skeleton.d.ts.map +1 -1
- package/dist/components/ui/slider.d.ts +4 -0
- package/dist/components/ui/slider.d.ts.map +1 -1
- package/dist/components/ui/sonner.d.ts +16 -0
- package/dist/components/ui/sonner.d.ts.map +1 -1
- package/dist/components/ui/stepper.d.ts +8 -0
- package/dist/components/ui/stepper.d.ts.map +1 -1
- package/dist/components/ui/sticky-save-bar.d.ts +7 -0
- package/dist/components/ui/sticky-save-bar.d.ts.map +1 -1
- package/dist/components/ui/switch.d.ts +4 -0
- package/dist/components/ui/switch.d.ts.map +1 -1
- package/dist/components/ui/table.d.ts +31 -0
- package/dist/components/ui/table.d.ts.map +1 -1
- package/dist/components/ui/tabs.d.ts +16 -0
- package/dist/components/ui/tabs.d.ts.map +1 -1
- package/dist/components/ui/textarea.d.ts +4 -0
- package/dist/components/ui/textarea.d.ts.map +1 -1
- package/dist/components/ui/toggle-group.d.ts +7 -0
- package/dist/components/ui/toggle-group.d.ts.map +1 -1
- package/dist/components/ui/toggle.d.ts +4 -0
- package/dist/components/ui/toggle.d.ts.map +1 -1
- package/dist/components/ui/tooltip.d.ts +18 -0
- package/dist/components/ui/tooltip.d.ts.map +1 -1
- package/dist/components/ui/user-avatar.d.ts +2 -1
- package/dist/components/ui/user-avatar.d.ts.map +1 -1
- package/dist/components/ui/viglet-assistant.d.ts +103 -0
- package/dist/components/ui/viglet-assistant.d.ts.map +1 -0
- package/dist/components/ui/viglet-avatar.d.ts +44 -0
- package/dist/components/ui/viglet-avatar.d.ts.map +1 -0
- package/dist/contexts/breadcrumb.context.d.ts +7 -0
- package/dist/contexts/breadcrumb.context.d.ts.map +1 -1
- package/dist/contexts/user.context.d.ts +8 -0
- package/dist/contexts/user.context.d.ts.map +1 -1
- package/dist/exports.json +359 -30
- package/dist/floating-formulas-bg.cjs +1 -1
- package/dist/floating-formulas-bg.es.js +56 -55
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/use-assistant-notifications.d.ts +15 -0
- package/dist/hooks/use-assistant-notifications.d.ts.map +1 -0
- package/dist/i18n/index.d.ts +168 -0
- package/dist/i18n/index.d.ts.map +1 -1
- package/dist/i18n/locales/en/assistant.json.d.ts +25 -0
- package/dist/i18n/locales/en/bento.json.d.ts +48 -2
- package/dist/i18n/locales/en/common.json.d.ts +6 -1
- package/dist/i18n/locales/en/language.json.d.ts +8 -0
- package/dist/i18n/locales/pt/assistant.json.d.ts +25 -0
- package/dist/i18n/locales/pt/bento.json.d.ts +48 -2
- package/dist/i18n/locales/pt/common.json.d.ts +6 -1
- package/dist/i18n/locales/pt/language.json.d.ts +8 -0
- package/dist/i18n.cjs +1 -1
- package/dist/i18n.es.js +572 -2
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.es.js +2280 -733
- package/dist/lib/busy.d.ts +26 -0
- package/dist/lib/busy.d.ts.map +1 -0
- package/dist/lib/corner-slot.d.ts +15 -0
- package/dist/lib/corner-slot.d.ts.map +1 -0
- package/dist/{loading-provider-BWWhhfEn.js → loading-provider-ClDkFPuv.js} +84 -81
- package/dist/loading-provider-DGuCfsl9.cjs +1 -0
- package/dist/preset.css +7 -10
- package/dist/router.cjs +1 -1
- package/dist/router.es.js +2 -776
- package/dist/user.context-Cr3GAQ_r.js +762 -0
- package/dist/user.context-hbdvmXOn.cjs +1 -0
- package/dist/utils-Fk5jmzzb.js +41 -0
- package/dist/utils-Oagwe_oa.cjs +1 -0
- package/dist/viglet-design-system.css +1 -1
- package/dist/vite/boot-loader.d.ts +33 -2
- package/dist/vite/boot-loader.d.ts.map +1 -1
- package/dist/vite.cjs +16 -5
- package/dist/vite.es.js +27 -14
- package/docs/BENTO-AUTHORING.md +81 -11
- package/docs/reference/grounds.dc.html +9 -9
- package/package.json +16 -4
- package/scripts/consumer-entries.mjs +209 -0
- package/scripts/lib/contrast.mjs +301 -0
- package/scripts/mcp.mjs +300 -0
- package/scripts/page-lint.mjs +428 -0
- package/scripts/page-reference.mjs +54 -10
- package/dist/badge-locale-CoEEv7s5.js +0 -581
- package/dist/badge-locale-hQyWhAKe.cjs +0 -7
- package/dist/breadcrumb.context-KQut7j8U.js +0 -917
- package/dist/breadcrumb.context-Vwc3lAlf.cjs +0 -1
- package/dist/components/router/blank-slate.d.ts +0 -21
- package/dist/components/router/blank-slate.d.ts.map +0 -1
- package/dist/components/router/grid.list.d.ts +0 -39
- package/dist/components/router/grid.list.d.ts.map +0 -1
- package/dist/components/router/internal.sidebar.d.ts +0 -61
- package/dist/components/router/internal.sidebar.d.ts.map +0 -1
- package/dist/components/router/nav-main.d.ts +0 -25
- package/dist/components/router/nav-main.d.ts.map +0 -1
- package/dist/components/router/nav-user.d.ts +0 -24
- package/dist/components/router/nav-user.d.ts.map +0 -1
- package/dist/components/router/page-content.d.ts +0 -12
- package/dist/components/router/page-content.d.ts.map +0 -1
- package/dist/components/router/page-header.d.ts +0 -23
- package/dist/components/router/page-header.d.ts.map +0 -1
- package/dist/components/router/page.d.ts +0 -22
- package/dist/components/router/page.d.ts.map +0 -1
- package/dist/components/router/sticky.page.header.d.ts +0 -85
- package/dist/components/router/sticky.page.header.d.ts.map +0 -1
- package/dist/components/router/sub.page.d.ts +0 -50
- package/dist/components/router/sub.page.d.ts.map +0 -1
- package/dist/components/router/sub.page.header.d.ts +0 -37
- package/dist/components/router/sub.page.header.d.ts.map +0 -1
- package/dist/i18n-DD3rQOWi.js +0 -426
- package/dist/i18n-DrBq-qJJ.cjs +0 -1
- package/dist/lib/react-markers.d.ts +0 -17
- package/dist/lib/react-markers.d.ts.map +0 -1
- package/dist/loading-provider-CmeMqLGk.cjs +0 -1
- package/dist/user.context-B9vIBzY5.cjs +0 -1
- package/dist/user.context-D1PxP4D4.js +0 -512
package/scripts/mcp.mjs
ADDED
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// VDS136 — the component catalogue, served to an agent over MCP (stdio).
|
|
3
|
+
//
|
|
4
|
+
// viglet-ds-mcp # serve the installed package's catalogue
|
|
5
|
+
// viglet-ds-mcp --catalogue <file> # serve another catalogue.json
|
|
6
|
+
// viglet-ds-mcp --package-root <dir> # read dist/ and docs/ from another copy
|
|
7
|
+
//
|
|
8
|
+
// Two tools, because a tool list is paid on every turn of every session:
|
|
9
|
+
//
|
|
10
|
+
// find_component which components do a job, ranked, one line each
|
|
11
|
+
// read_component one component's purpose, props, the rules that govern it
|
|
12
|
+
// and an import to start from
|
|
13
|
+
//
|
|
14
|
+
// The long text is a resource, read when a session asks for it: the authoring
|
|
15
|
+
// contract, the boundary, and the token reference. Everything is read from the
|
|
16
|
+
// installed package, so the answers describe the release the product has, and
|
|
17
|
+
// nothing here is written by hand: the catalogue is generated at build time from
|
|
18
|
+
// the declarations the product compiles against.
|
|
19
|
+
//
|
|
20
|
+
// The protocol is JSON-RPC 2.0, one message per line, with no SDK: initialize,
|
|
21
|
+
// ping, tools/list, tools/call, resources/list and resources/read are the whole
|
|
22
|
+
// of what a client asks this server.
|
|
23
|
+
|
|
24
|
+
import { existsSync, readFileSync } from "node:fs"
|
|
25
|
+
import { dirname, join, resolve } from "node:path"
|
|
26
|
+
import { createInterface } from "node:readline"
|
|
27
|
+
import { fileURLToPath } from "node:url"
|
|
28
|
+
|
|
29
|
+
const args = process.argv.slice(2)
|
|
30
|
+
function option(flag) {
|
|
31
|
+
const at = args.indexOf(flag)
|
|
32
|
+
return at === -1 ? null : (args[at + 1] ?? null)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const packageRoot = resolve(option("--package-root") ?? join(dirname(fileURLToPath(import.meta.url)), ".."))
|
|
36
|
+
const cataloguePath = resolve(option("--catalogue") ?? join(packageRoot, "dist", "catalogue.json"))
|
|
37
|
+
|
|
38
|
+
const PROTOCOL = "2025-06-18"
|
|
39
|
+
const FIND_LIMIT = 5
|
|
40
|
+
|
|
41
|
+
// ---------------------------------------------------------------------------
|
|
42
|
+
// The surface. Descriptions are short on purpose: each word here is in every
|
|
43
|
+
// turn's context, and the per-call answers carry the detail.
|
|
44
|
+
|
|
45
|
+
export const TOOLS = [
|
|
46
|
+
{
|
|
47
|
+
name: "find_component",
|
|
48
|
+
description:
|
|
49
|
+
"Find Viglet Design System components for a job, e.g. 'frosted container with no heading' or 'confirm a delete'. Returns ranked names, imports and one-line purposes.",
|
|
50
|
+
inputSchema: {
|
|
51
|
+
type: "object",
|
|
52
|
+
properties: {
|
|
53
|
+
job: { type: "string", description: "What the component should do, in plain words." },
|
|
54
|
+
limit: { type: "integer", minimum: 1, maximum: 10, description: "How many to return (default 5)." },
|
|
55
|
+
},
|
|
56
|
+
required: ["job"],
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
name: "read_component",
|
|
61
|
+
description:
|
|
62
|
+
"Read one component: what it is for, its props, the contract rules that govern it, and an import to start from.",
|
|
63
|
+
inputSchema: {
|
|
64
|
+
type: "object",
|
|
65
|
+
properties: { name: { type: "string", description: "The exported name, e.g. BentoPanel." } },
|
|
66
|
+
required: ["name"],
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
]
|
|
70
|
+
|
|
71
|
+
export const RESOURCES = [
|
|
72
|
+
{
|
|
73
|
+
uri: "viglet-ds://authoring",
|
|
74
|
+
name: "authoring",
|
|
75
|
+
title: "Authoring a bento page",
|
|
76
|
+
description: "The page contract: the shell and who owns each region, page shapes, colour, i18n, accessibility.",
|
|
77
|
+
mimeType: "text/markdown",
|
|
78
|
+
file: "docs/BENTO-AUTHORING.md",
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
uri: "viglet-ds://boundary",
|
|
82
|
+
name: "boundary",
|
|
83
|
+
title: "What the bento layer holds",
|
|
84
|
+
description: "Which components are the shared layer and which stay in a product, and why.",
|
|
85
|
+
mimeType: "text/markdown",
|
|
86
|
+
file: "docs/BENTO-BOUNDARY.md",
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
uri: "viglet-ds://tokens",
|
|
90
|
+
name: "tokens",
|
|
91
|
+
title: "Design tokens",
|
|
92
|
+
description: "Every --vg-* custom property the preset declares, on the light and the dark ground.",
|
|
93
|
+
mimeType: "text/markdown",
|
|
94
|
+
file: "dist/preset.css",
|
|
95
|
+
},
|
|
96
|
+
]
|
|
97
|
+
|
|
98
|
+
// ---------------------------------------------------------------------------
|
|
99
|
+
// The answers.
|
|
100
|
+
|
|
101
|
+
const STOP = new Set(["a", "an", "the", "to", "of", "for", "with", "and", "or", "in", "on", "that", "which", "is", "it", "my", "i", "want", "need", "component"])
|
|
102
|
+
|
|
103
|
+
/** `BentoPanel` -> ["bento", "panel"], `aria-label` -> ["aria", "label"]. */
|
|
104
|
+
const words = (text) =>
|
|
105
|
+
(text ?? "")
|
|
106
|
+
.replace(/([a-z0-9])([A-Z])/g, "$1 $2")
|
|
107
|
+
.toLowerCase()
|
|
108
|
+
.split(/[^a-z0-9]+/)
|
|
109
|
+
.filter((w) => w.length > 1 && !STOP.has(w))
|
|
110
|
+
|
|
111
|
+
/** A crude stem, so "deleting" and "delete" meet at "delet". */
|
|
112
|
+
const stem = (word) => (word.length > 4 ? word.replace(/(ing|ion|ed|es|s|e)$/, "") : word)
|
|
113
|
+
|
|
114
|
+
/** A word counts when it starts a word of the text, so "confirm" finds "confirmation". */
|
|
115
|
+
function hits(query, text) {
|
|
116
|
+
const haystack = words(text).map(stem)
|
|
117
|
+
return query.filter((q) => haystack.some((w) => w.startsWith(q))).length
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export function findComponents(catalogue, job, limit = FIND_LIMIT) {
|
|
121
|
+
const query = [...new Set(words(job).map(stem))]
|
|
122
|
+
if (query.length === 0) return []
|
|
123
|
+
return catalogue.components
|
|
124
|
+
.map((component) => ({
|
|
125
|
+
component,
|
|
126
|
+
score:
|
|
127
|
+
hits(query, component.name) * 5 +
|
|
128
|
+
hits(query, component.summary) * 3 +
|
|
129
|
+
hits(query, component.description) +
|
|
130
|
+
hits(query, component.props.map((p) => p.name).join(" ")) +
|
|
131
|
+
hits(query, component.rules.join(" ")) -
|
|
132
|
+
(component.deprecated ? 4 : 0),
|
|
133
|
+
}))
|
|
134
|
+
.filter((ranked) => ranked.score > 0)
|
|
135
|
+
.sort((a, b) => b.score - a.score || a.component.name.localeCompare(b.component.name))
|
|
136
|
+
.slice(0, Math.max(1, Math.min(10, limit)))
|
|
137
|
+
.map(({ component }) => component)
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export function renderFound(found, job) {
|
|
141
|
+
if (found.length === 0) {
|
|
142
|
+
return `No component matches "${job}". Try other words for the job, or read viglet-ds://boundary for what the layer holds.`
|
|
143
|
+
}
|
|
144
|
+
return found
|
|
145
|
+
.map((c) => {
|
|
146
|
+
const purpose = c.summary || "(no description in its declaration)"
|
|
147
|
+
const deprecated = c.deprecated ? ` DEPRECATED: ${c.deprecated}` : ""
|
|
148
|
+
return `${c.name} (${c.specifier}): ${purpose}${deprecated}`
|
|
149
|
+
})
|
|
150
|
+
.join("\n")
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/** An import and the smallest element that type-checks: the required props, as placeholders. */
|
|
154
|
+
function starter(component) {
|
|
155
|
+
if (component.example && component.example !== "yes") return component.example
|
|
156
|
+
const required = component.props.filter((p) => !p.optional && p.name !== "children")
|
|
157
|
+
const attributes = required.map((p) => ` ${p.name}={…}`).join("")
|
|
158
|
+
return `import { ${component.name} } from "${component.specifier}"\n\n<${component.name}${attributes} />`
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export function renderComponent(component) {
|
|
162
|
+
const lines = [`# ${component.name}`, `import from ${component.specifier}`, ""]
|
|
163
|
+
if (component.deprecated) lines.push(`DEPRECATED: ${component.deprecated}`, "")
|
|
164
|
+
lines.push(component.description || "No description in its declaration.", "")
|
|
165
|
+
|
|
166
|
+
lines.push("## Props")
|
|
167
|
+
if (component.props.length === 0) lines.push("none of its own")
|
|
168
|
+
for (const p of component.props) {
|
|
169
|
+
lines.push(`- ${p.name}${p.optional ? "?" : ""}: ${p.type}${p.summary ? ` — ${p.summary}` : ""}`)
|
|
170
|
+
}
|
|
171
|
+
if (component.inheritedProps > 0) {
|
|
172
|
+
lines.push(`- and ${component.inheritedProps} attributes of the element it renders, passed through`)
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
lines.push("", "## Governed by")
|
|
176
|
+
lines.push(...(component.rules.length > 0 ? component.rules.map((r) => `- ${r}`) : ["no section of the contract names it"]))
|
|
177
|
+
|
|
178
|
+
lines.push("", "## Start from", "```tsx", starter(component), "```")
|
|
179
|
+
return lines.join("\n")
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/** The preset's tokens, by ground, as `--name: value` lines. */
|
|
183
|
+
export function renderTokens(css) {
|
|
184
|
+
const text = css.replace(/\/\*[\s\S]*?\*\//g, "")
|
|
185
|
+
const block = (selector) => {
|
|
186
|
+
const at = text.search(selector)
|
|
187
|
+
if (at === -1) return []
|
|
188
|
+
const open = text.indexOf("{", at)
|
|
189
|
+
const close = text.indexOf("\n}", open)
|
|
190
|
+
return [...text.slice(open + 1, close).matchAll(/(--vg-[\w-]+)\s*:\s*([^;]+);/g)].map(
|
|
191
|
+
([, name, value]) => `${name}: ${value.replace(/\s+/g, " ").trim()}`,
|
|
192
|
+
)
|
|
193
|
+
}
|
|
194
|
+
return [
|
|
195
|
+
"# Design tokens",
|
|
196
|
+
"",
|
|
197
|
+
"Claim a token at `:root` in the product's stylesheet. `--primary` is claimed through the `--vg-primary-*-base` inputs, never by setting `--vg-primary` (see viglet-ds://authoring).",
|
|
198
|
+
"",
|
|
199
|
+
"## Light ground (:root)",
|
|
200
|
+
...block(/^:root\s*\{/m),
|
|
201
|
+
"",
|
|
202
|
+
"## Dark ground (.dark)",
|
|
203
|
+
...block(/^\.dark,?/m),
|
|
204
|
+
].join("\n")
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// ---------------------------------------------------------------------------
|
|
208
|
+
// The server.
|
|
209
|
+
|
|
210
|
+
function loadCatalogue() {
|
|
211
|
+
if (!existsSync(cataloguePath)) return null
|
|
212
|
+
return JSON.parse(readFileSync(cataloguePath, "utf8"))
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function textResult(text, isError = false) {
|
|
216
|
+
return { content: [{ type: "text", text }], ...(isError ? { isError: true } : {}) }
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
export function handle(message, catalogue) {
|
|
220
|
+
const { method, params = {} } = message
|
|
221
|
+
switch (method) {
|
|
222
|
+
case "initialize":
|
|
223
|
+
return {
|
|
224
|
+
protocolVersion: params.protocolVersion ?? PROTOCOL,
|
|
225
|
+
capabilities: { tools: { listChanged: false }, resources: { listChanged: false } },
|
|
226
|
+
serverInfo: { name: "viglet-ds", version: catalogue?.version ?? "unknown" },
|
|
227
|
+
}
|
|
228
|
+
case "ping":
|
|
229
|
+
return {}
|
|
230
|
+
case "tools/list":
|
|
231
|
+
return { tools: TOOLS }
|
|
232
|
+
case "resources/list":
|
|
233
|
+
return { resources: RESOURCES.map(({ file: _file, ...resource }) => resource) }
|
|
234
|
+
case "resources/read": {
|
|
235
|
+
const resource = RESOURCES.find((r) => r.uri === params.uri)
|
|
236
|
+
if (!resource) throw rpcError(-32602, `no resource ${params.uri}`)
|
|
237
|
+
const path = join(packageRoot, resource.file)
|
|
238
|
+
if (!existsSync(path)) throw rpcError(-32002, `${resource.file} is not in this copy of the package`)
|
|
239
|
+
const raw = readFileSync(path, "utf8")
|
|
240
|
+
const text = resource.name === "tokens" ? renderTokens(raw) : raw
|
|
241
|
+
return { contents: [{ uri: resource.uri, mimeType: resource.mimeType, text }] }
|
|
242
|
+
}
|
|
243
|
+
case "tools/call": {
|
|
244
|
+
if (!catalogue) {
|
|
245
|
+
return textResult(`No catalogue at ${cataloguePath}: this release of the package does not ship one.`, true)
|
|
246
|
+
}
|
|
247
|
+
const input = params.arguments ?? {}
|
|
248
|
+
if (params.name === "find_component") {
|
|
249
|
+
if (typeof input.job !== "string" || !input.job.trim()) return textResult("find_component needs a job.", true)
|
|
250
|
+
return textResult(renderFound(findComponents(catalogue, input.job, input.limit), input.job))
|
|
251
|
+
}
|
|
252
|
+
if (params.name === "read_component") {
|
|
253
|
+
const wanted = String(input.name ?? "").trim()
|
|
254
|
+
const component =
|
|
255
|
+
catalogue.components.find((c) => c.name === wanted) ??
|
|
256
|
+
catalogue.components.find((c) => c.name.toLowerCase() === wanted.toLowerCase())
|
|
257
|
+
if (!component) {
|
|
258
|
+
const near = findComponents(catalogue, wanted, 3).map((c) => c.name)
|
|
259
|
+
return textResult(`No component named "${wanted}".${near.length ? ` Did you mean ${near.join(", ")}?` : ""}`, true)
|
|
260
|
+
}
|
|
261
|
+
return textResult(renderComponent(component))
|
|
262
|
+
}
|
|
263
|
+
throw rpcError(-32602, `no tool ${params.name}`)
|
|
264
|
+
}
|
|
265
|
+
default:
|
|
266
|
+
throw rpcError(-32601, `method not found: ${method}`)
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function rpcError(code, message) {
|
|
271
|
+
return Object.assign(new Error(message), { rpc: { code, message } })
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
function serve() {
|
|
275
|
+
const catalogue = loadCatalogue()
|
|
276
|
+
const reply = (payload) => process.stdout.write(`${JSON.stringify({ jsonrpc: "2.0", ...payload })}\n`)
|
|
277
|
+
|
|
278
|
+
createInterface({ input: process.stdin }).on("line", (line) => {
|
|
279
|
+
if (!line.trim()) return
|
|
280
|
+
let message
|
|
281
|
+
try {
|
|
282
|
+
// A client on Windows can open the stream with a byte-order mark.
|
|
283
|
+
message = JSON.parse(line.startsWith("\uFEFF") ? line.slice(1) : line)
|
|
284
|
+
} catch {
|
|
285
|
+
reply({ id: null, error: { code: -32700, message: "parse error" } })
|
|
286
|
+
return
|
|
287
|
+
}
|
|
288
|
+
// A notification has no id and wants no answer.
|
|
289
|
+
if (message.id === undefined || message.id === null) return
|
|
290
|
+
try {
|
|
291
|
+
reply({ id: message.id, result: handle(message, catalogue) })
|
|
292
|
+
} catch (error) {
|
|
293
|
+
reply({ id: message.id, error: error.rpc ?? { code: -32603, message: String(error.message ?? error) } })
|
|
294
|
+
}
|
|
295
|
+
})
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
if (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
|
|
299
|
+
serve()
|
|
300
|
+
}
|