@cascivo/mcp 0.1.0 → 0.1.1
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 +32 -9
- package/dist/index.d.mts +48 -2
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +144 -11
- package/dist/index.mjs.map +1 -1
- package/dist/registry.json +1244 -103
- package/package.json +3 -3
- package/readme.body.md +31 -8
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
# @cascivo/mcp
|
|
4
4
|
|
|
5
|
-
> MCP server exposing the
|
|
5
|
+
> MCP server exposing the cascivo component registry to AI agents
|
|
6
6
|
|
|
7
7
|
[cascivo.com](https://cascivo.com) · [Docs](https://docs.cascivo.com) · [Storybook](https://storybook.cascivo.com) · [GitHub](https://github.com/urbanisierung/cascivo)
|
|
8
8
|
|
|
@@ -25,17 +25,40 @@ The server speaks the MCP stdio transport. By default it reads the `registry.jso
|
|
|
25
25
|
|
|
26
26
|
## Tools
|
|
27
27
|
|
|
28
|
-
| Tool | Input | Returns
|
|
29
|
-
| ------------------- | ------------------------------------- |
|
|
30
|
-
| `list_components` | `{ category? }` | All component manifests, optionally filtered by category
|
|
31
|
-
| `get_component` | `{ name }` | The full manifest for one component
|
|
32
|
-
| `search_components` | `{ query }` | Components matching name, tags, or description
|
|
33
|
-
| `add_to_project` | `{ name, outputDir? }` | Runs `cascivo add <name>` as a child process
|
|
34
|
-
| `create_theme` | `{ primary, neutral, accent, name? }` | A custom theme as CSS (semantic token layer)
|
|
35
|
-
| `scaffold_page` | `{ description, components? }` | A JSX page layout string
|
|
28
|
+
| Tool | Input | Returns |
|
|
29
|
+
| ------------------- | ------------------------------------- | ------------------------------------------------------------------------------------ |
|
|
30
|
+
| `list_components` | `{ category? }` | All component manifests, optionally filtered by category |
|
|
31
|
+
| `get_component` | `{ name }` | The full manifest for one component |
|
|
32
|
+
| `search_components` | `{ query }` | Components matching name, tags, or description |
|
|
33
|
+
| `add_to_project` | `{ name, outputDir? }` | Runs `cascivo add <name>` as a child process |
|
|
34
|
+
| `create_theme` | `{ primary, neutral, accent, name? }` | A custom theme as CSS (semantic token layer) |
|
|
35
|
+
| `scaffold_page` | `{ description, components? }` | A JSX page layout string |
|
|
36
|
+
| `scaffold_view` | `{ description, components? }` | A validated starter `ViewConfig` + the bound-vocabulary `grammar` for its components |
|
|
37
|
+
| `validate_view` | `{ config }` | Validation errors (component, prop type/enum, refs) with exact paths |
|
|
38
|
+
| `get_view_grammar` | `{ components? }` | Bound-vocabulary grammar + generation prompt for valid `ViewConfig` JSON |
|
|
36
39
|
|
|
37
40
|
`category` is one of `inputs`, `display`, `overlay`, `navigation`, `feedback`.
|
|
38
41
|
|
|
42
|
+
### Bound-vocabulary generation (anti-hallucination)
|
|
43
|
+
|
|
44
|
+
`get_view_grammar` derives — from the `component.meta.ts` manifests — a **system
|
|
45
|
+
prompt** plus a compact **allowed-vocabulary grammar** (each component → its
|
|
46
|
+
props → enum/size/variant values) for emitting valid `ViewConfig` JSON rendered
|
|
47
|
+
by `@cascivo/render` `<CascadeView />`. This is [OpenUI](https://openui.com)'s
|
|
48
|
+
"generate the system prompt from the component library" mechanism (see
|
|
49
|
+
[`docs/ROADMAP-V40.md`](../../docs/ROADMAP-V40.md)): because the grammar is
|
|
50
|
+
**derived**, not authored, an LLM is structurally prevented from inventing
|
|
51
|
+
components, props, or enum values, and the grammar can never drift from the
|
|
52
|
+
components. Pair it with `validate_view` (which now also checks prop types/enums)
|
|
53
|
+
as the enforcement backstop.
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
import { buildGenerationPrompt, loadRegistry } from '@cascivo/mcp'
|
|
57
|
+
|
|
58
|
+
const prompt = buildGenerationPrompt(loadRegistry(), { components: ['Badge', 'Button'] })
|
|
59
|
+
// → use as the system prompt; the model can only emit Badge/Button with their real props.
|
|
60
|
+
```
|
|
61
|
+
|
|
39
62
|
## Programmatic use
|
|
40
63
|
|
|
41
64
|
```ts
|
package/dist/index.d.mts
CHANGED
|
@@ -21,7 +21,7 @@ interface ThemeColors {
|
|
|
21
21
|
accent: string;
|
|
22
22
|
}
|
|
23
23
|
/**
|
|
24
|
-
* Generate a custom
|
|
24
|
+
* Generate a custom cascivo theme as CSS. Maps the three input colors onto the
|
|
25
25
|
* semantic token layer; component tokens inherit automatically.
|
|
26
26
|
*/
|
|
27
27
|
declare function generateThemeCss(colors: ThemeColors, name?: string): string;
|
|
@@ -91,10 +91,56 @@ declare function getComponent(registry: Registry, name: string): ComponentManife
|
|
|
91
91
|
/** Fuzzy search over name, tags, and description. */
|
|
92
92
|
declare function searchComponents(registry: Registry, query: string): ComponentManifest[];
|
|
93
93
|
//#endregion
|
|
94
|
+
//#region src/grammar.d.ts
|
|
95
|
+
interface GrammarProp {
|
|
96
|
+
name: string;
|
|
97
|
+
required: boolean;
|
|
98
|
+
/** Raw TypeScript type string from the manifest. */
|
|
99
|
+
type: string;
|
|
100
|
+
/** Allowed values, when `type` is a string-literal union (e.g. `'sm' | 'md'`). */
|
|
101
|
+
enum?: string[];
|
|
102
|
+
}
|
|
103
|
+
interface GrammarComponent {
|
|
104
|
+
name: string;
|
|
105
|
+
category: string;
|
|
106
|
+
props: GrammarProp[];
|
|
107
|
+
variants: string[];
|
|
108
|
+
sizes: string[];
|
|
109
|
+
}
|
|
110
|
+
interface ViewGrammar {
|
|
111
|
+
components: GrammarComponent[];
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Parse a string-literal union type (`'a' | 'b' | "c"`) into its allowed
|
|
115
|
+
* values. Returns `undefined` for any non-enum type (primitives, functions,
|
|
116
|
+
* named types, object shapes) so the grammar only constrains what it can.
|
|
117
|
+
*/
|
|
118
|
+
declare function parseEnum(type: string): string[] | undefined;
|
|
119
|
+
declare function buildGrammar(registry: Registry, subset?: string[]): ViewGrammar;
|
|
120
|
+
/**
|
|
121
|
+
* Render the grammar as a compact, model-friendly table: one line per
|
|
122
|
+
* component. Terser than verbose JSON; a `*` marks a required prop.
|
|
123
|
+
*
|
|
124
|
+
* Badge(size: sm|md, variant: default|secondary|success|warning|destructive|outline)
|
|
125
|
+
*/
|
|
126
|
+
declare function formatGrammar(grammar: ViewGrammar): string;
|
|
127
|
+
//#endregion
|
|
128
|
+
//#region src/prompt.d.ts
|
|
129
|
+
interface GenerationPromptOptions {
|
|
130
|
+
/** Scope the vocabulary to a subset of component names. Defaults to all. */
|
|
131
|
+
components?: string[];
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Build the bound-vocabulary system prompt for emitting `ViewConfig` JSON.
|
|
135
|
+
* Parameterizable by an optional component subset (defaults to the full
|
|
136
|
+
* registry).
|
|
137
|
+
*/
|
|
138
|
+
declare function buildGenerationPrompt(registry: Registry, options?: GenerationPromptOptions): string;
|
|
139
|
+
//#endregion
|
|
94
140
|
//#region src/index.d.ts
|
|
95
141
|
declare const VERSION = "0.0.0";
|
|
96
142
|
/** Start the MCP server over stdio. */
|
|
97
143
|
declare function main(): Promise<void>;
|
|
98
144
|
//#endregion
|
|
99
|
-
export { type ComponentManifest, type Registry, type RegistryComponent, type ScaffoldOptions, type ServerOptions, type ThemeColors, VERSION, createServer, generateThemeCss, getComponent, listComponents, loadRegistry, main, scaffoldPage, searchComponents };
|
|
145
|
+
export { type ComponentManifest, type GenerationPromptOptions, type GrammarComponent, type GrammarProp, type Registry, type RegistryComponent, type ScaffoldOptions, type ServerOptions, type ThemeColors, VERSION, type ViewGrammar, buildGenerationPrompt, buildGrammar, createServer, formatGrammar, generateThemeCss, getComponent, listComponents, loadRegistry, main, parseEnum, scaffoldPage, searchComponents };
|
|
100
146
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/server.ts","../src/theme.ts","../src/scaffold.ts","../src/registry.ts","../src/index.ts"],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/server.ts","../src/theme.ts","../src/scaffold.ts","../src/registry.ts","../src/grammar.ts","../src/prompt.ts","../src/index.ts"],"mappings":";;;KAwBK,OAAA,IAAW,GAAA,UAAa,IAAA,GAAO,WAAA,KAAgB,OAAA,CAAQ,QAAA;AAAA,UAE3C,aAAA;EACf,YAAA;EACA,OAAA;;EAEA,OAAA,GAAU,OAAO;AAAA;;iBAeH,YAAA,CAAa,OAAA,GAAS,aAAA,GAAqB,SAAS;;;UC7CnD,WAAA;;EAEf,OAAA;EDsBG;ECpBH,OAAA;;EAEA,MAAA;AAAA;;;;;iBAiBc,gBAAA,CAAiB,MAAA,EAAQ,WAAW,EAAE,IAAA;;;UCvBrC,eAAA;EACf,WAAA;EACA,UAAU;AAAA;;;;;iBAgCI,YAAA,CAAa,OAAwB,EAAf,eAAe;;;UC9BpC,YAAA;EACf,IAAA;EACA,IAAA;EACA,QAAA;EACA,OAAA;EACA,WAAA;AAAA;AAAA,UAGe,iBAAA;EACf,IAAA;EACA,WAAA;EACA,QAAA;EACA,MAAA;EACA,QAAA;EACA,KAAA;EACA,KAAA,EAAO,YAAY;EACnB,MAAA;EACA,aAAA;IAAiB,IAAA;IAAc,IAAA;IAAc,QAAA;EAAA;EAC7C,QAAA;IAAY,KAAA;IAAe,IAAA;IAAc,WAAA;EAAA;EACzC,YAAA;EACA,IAAA;AAAA;AAAA,UAGe,iBAAA;EACf,IAAA;EACA,IAAA;EACA,WAAA;EACA,QAAA;EACA,OAAA;EACA,KAAA;EACA,YAAA;EACA,IAAA;EACA,IAAA,EAAM,iBAAiB;AAAA;AAAA,UAGR,QAAA;EACf,OAAA;EACA,WAAA;EACA,UAAA,EAAY,iBAAiB;AAAA;AAAA,iBAwBf,YAAA,CAAa,IAAA,YAAgB,QAAQ;;iBAUrC,cAAA,CACd,QAAA,EAAU,QAAA,EACV,QAAA,WACA,IAAA,YACC,iBAAiB;;iBAQJ,YAAA,CAAa,QAAA,EAAU,QAAA,EAAU,IAAA,WAAe,iBAAiB;;iBAoGjE,gBAAA,CAAiB,QAAA,EAAU,QAAA,EAAU,KAAA,WAAgB,iBAAiB;;;UChLrE,WAAA;EACf,IAAA;EACA,QAAA;EJUU;EIRV,IAAA;EJQkC;EINlC,IAAA;AAAA;AAAA,UAGe,gBAAA;EACf,IAAA;EACA,QAAA;EACA,KAAA,EAAO,WAAW;EAClB,QAAA;EACA,KAAA;AAAA;AAAA,UAGe,WAAA;EACf,UAAA,EAAY,gBAAgB;AAAA;;;;;;iBAQd,SAAA,CAAU,IAAY;AAAA,iBA8BtB,YAAA,CAAa,QAAA,EAAU,QAAA,EAAU,MAAA,cAAoB,WAAW;;AJtC7D;AAenB;;;;iBI8EgB,aAAA,CAAc,OAAoB,EAAX,WAAW;;;UChHjC,uBAAA;;EAEf,UAAU;AAAA;;;;;;iBAsCI,qBAAA,CACd,QAAA,EAAU,QAAA,EACV,OAAA,GAAS,uBAA4B;;;cChD1B,OAAA;;iBA0BS,IAAA,IAAQ,OAAO"}
|
package/dist/index.mjs
CHANGED
|
@@ -120,14 +120,14 @@ function lighten(color, amount) {
|
|
|
120
120
|
return `color-mix(in oklab, ${color}, white ${amount}%)`;
|
|
121
121
|
}
|
|
122
122
|
/**
|
|
123
|
-
* Generate a custom
|
|
123
|
+
* Generate a custom cascivo theme as CSS. Maps the three input colors onto the
|
|
124
124
|
* semantic token layer; component tokens inherit automatically.
|
|
125
125
|
*/
|
|
126
126
|
function generateThemeCss(colors, name = "custom") {
|
|
127
127
|
const { primary, neutral, accent } = colors;
|
|
128
|
-
return `/*
|
|
128
|
+
return `/* cascivo — Generated theme: ${name} */
|
|
129
129
|
|
|
130
|
-
@layer
|
|
130
|
+
@layer cascivo.theme {
|
|
131
131
|
[data-theme='${name}'] {
|
|
132
132
|
color-scheme: light;
|
|
133
133
|
|
|
@@ -323,6 +323,78 @@ function validateView(config, componentNames) {
|
|
|
323
323
|
};
|
|
324
324
|
}
|
|
325
325
|
//#endregion
|
|
326
|
+
//#region src/grammar.ts
|
|
327
|
+
/**
|
|
328
|
+
* Parse a string-literal union type (`'a' | 'b' | "c"`) into its allowed
|
|
329
|
+
* values. Returns `undefined` for any non-enum type (primitives, functions,
|
|
330
|
+
* named types, object shapes) so the grammar only constrains what it can.
|
|
331
|
+
*/
|
|
332
|
+
function parseEnum(type) {
|
|
333
|
+
const branches = type.split("|").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
334
|
+
if (branches.length === 0) return void 0;
|
|
335
|
+
const values = [];
|
|
336
|
+
for (const branch of branches) {
|
|
337
|
+
const quoted = branch.match(/^['"](.+)['"]$/);
|
|
338
|
+
if (!quoted?.[1]) return void 0;
|
|
339
|
+
values.push(quoted[1]);
|
|
340
|
+
}
|
|
341
|
+
return values;
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* Build the bound-vocabulary descriptor from the registry, optionally scoped to
|
|
345
|
+
* a subset of component names (case-insensitive). Output is deterministic
|
|
346
|
+
* (components and props sorted by name) for reproducible prompts and tests.
|
|
347
|
+
*/
|
|
348
|
+
const TYPE_RANK = {
|
|
349
|
+
component: 0,
|
|
350
|
+
block: 1,
|
|
351
|
+
chart: 2,
|
|
352
|
+
section: 3,
|
|
353
|
+
layout: 4
|
|
354
|
+
};
|
|
355
|
+
function buildGrammar(registry, subset) {
|
|
356
|
+
const wanted = subset && subset.length > 0 ? new Set(subset.map((n) => n.toLowerCase())) : null;
|
|
357
|
+
const canonical = /* @__PURE__ */ new Map();
|
|
358
|
+
for (const c of registry.components) {
|
|
359
|
+
const key = c.meta.name.toLowerCase();
|
|
360
|
+
const current = canonical.get(key);
|
|
361
|
+
if (!current || (TYPE_RANK[c.type ?? ""] ?? 9) < (TYPE_RANK[current.type ?? ""] ?? 9)) canonical.set(key, c);
|
|
362
|
+
}
|
|
363
|
+
return { components: [...canonical.values()].filter((c) => !wanted || wanted.has(c.meta.name.toLowerCase()) || wanted.has(c.name.toLowerCase())).map((c) => {
|
|
364
|
+
const props = (c.meta.props ?? []).map((p) => {
|
|
365
|
+
const values = parseEnum(p.type);
|
|
366
|
+
return {
|
|
367
|
+
name: p.name,
|
|
368
|
+
required: p.required === true,
|
|
369
|
+
type: p.type,
|
|
370
|
+
...values ? { enum: values } : {}
|
|
371
|
+
};
|
|
372
|
+
}).sort((a, b) => a.name.localeCompare(b.name));
|
|
373
|
+
return {
|
|
374
|
+
name: c.meta.name,
|
|
375
|
+
category: c.category,
|
|
376
|
+
props,
|
|
377
|
+
variants: c.meta.variants ?? [],
|
|
378
|
+
sizes: c.meta.sizes ?? []
|
|
379
|
+
};
|
|
380
|
+
}).sort((a, b) => a.name.localeCompare(b.name)) };
|
|
381
|
+
}
|
|
382
|
+
/** Render one prop as `name`, `name*` (required), with enum choices or its type. */
|
|
383
|
+
function formatProp(prop) {
|
|
384
|
+
const mark = prop.required ? "*" : "";
|
|
385
|
+
const value = prop.enum ? prop.enum.join("|") : prop.type;
|
|
386
|
+
return `${prop.name}${mark}: ${value}`;
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
389
|
+
* Render the grammar as a compact, model-friendly table: one line per
|
|
390
|
+
* component. Terser than verbose JSON; a `*` marks a required prop.
|
|
391
|
+
*
|
|
392
|
+
* Badge(size: sm|md, variant: default|secondary|success|warning|destructive|outline)
|
|
393
|
+
*/
|
|
394
|
+
function formatGrammar(grammar) {
|
|
395
|
+
return grammar.components.map((c) => `${c.name}(${c.props.map(formatProp).join(", ")})`).join("\n");
|
|
396
|
+
}
|
|
397
|
+
//#endregion
|
|
326
398
|
//#region src/scaffold-view.ts
|
|
327
399
|
/** Simple keyword matcher — returns region layout name based on description keywords. */
|
|
328
400
|
function pickLayout(description) {
|
|
@@ -374,10 +446,55 @@ function scaffoldView(input, registry) {
|
|
|
374
446
|
const { errors } = validateView(config, new Set(registry.components.map((c) => c.meta.name)));
|
|
375
447
|
return {
|
|
376
448
|
config,
|
|
377
|
-
errors
|
|
449
|
+
errors,
|
|
450
|
+
grammar: formatGrammar(buildGrammar(registry, componentNames))
|
|
378
451
|
};
|
|
379
452
|
}
|
|
380
453
|
//#endregion
|
|
454
|
+
//#region src/prompt.ts
|
|
455
|
+
const SCHEMA_DOC = `A ViewConfig is a JSON object:
|
|
456
|
+
|
|
457
|
+
{
|
|
458
|
+
"version": 1,
|
|
459
|
+
"view": {
|
|
460
|
+
"layout": "<optional layout name, e.g. dashboard | settings | auth>",
|
|
461
|
+
"regions": {
|
|
462
|
+
"<regionName>": [ <ComponentNode>, ... ]
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
A ComponentNode is:
|
|
468
|
+
|
|
469
|
+
{
|
|
470
|
+
"component": "<one of the registered component names below>",
|
|
471
|
+
"props": { "<propName>": <value> },
|
|
472
|
+
"bind": { "<propName>": "$data.<path>" },
|
|
473
|
+
"events": { "<eventPropName>": "$actions.<name>" },
|
|
474
|
+
"children": <ComponentNode[] | string | { "$t": "<i18n.key>" }>
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
Rules:
|
|
478
|
+
- "component" MUST be one of the registered components listed below — never invent one.
|
|
479
|
+
- Only use props listed for that component; enum props MUST use one of the listed values.
|
|
480
|
+
- "bind" values are host-data references and MUST start with "$data.".
|
|
481
|
+
- "events" values are host-action references and MUST start with "$actions.".
|
|
482
|
+
- "children" is an array of nodes, a plain string, or an i18n ref { "$t": "key" }.
|
|
483
|
+
- Output ONLY the JSON ViewConfig — no prose, no markdown fences.`;
|
|
484
|
+
/**
|
|
485
|
+
* Build the bound-vocabulary system prompt for emitting `ViewConfig` JSON.
|
|
486
|
+
* Parameterizable by an optional component subset (defaults to the full
|
|
487
|
+
* registry).
|
|
488
|
+
*/
|
|
489
|
+
function buildGenerationPrompt(registry, options = {}) {
|
|
490
|
+
return [
|
|
491
|
+
"You generate UI as a cascivo ViewConfig — a JSON description rendered by @cascivo/render <CascadeView />.",
|
|
492
|
+
SCHEMA_DOC,
|
|
493
|
+
"Registered components (allowed vocabulary — `name*` marks a required prop):",
|
|
494
|
+
formatGrammar(buildGrammar(registry, options.components))
|
|
495
|
+
].join("\n\n");
|
|
496
|
+
}
|
|
497
|
+
//#endregion
|
|
381
498
|
//#region src/tokens.ts
|
|
382
499
|
const HERE$1 = dirname(fileURLToPath(import.meta.url));
|
|
383
500
|
const CATALOG_BASE_URL = "https://cascivo.com";
|
|
@@ -445,6 +562,7 @@ function selectComponent(need, components) {
|
|
|
445
562
|
name: c.name,
|
|
446
563
|
score,
|
|
447
564
|
why,
|
|
565
|
+
whenNotToUse: c.intent.whenNotToUse ?? [],
|
|
448
566
|
related: c.intent.related ?? []
|
|
449
567
|
};
|
|
450
568
|
});
|
|
@@ -457,7 +575,9 @@ function selectComponent(need, components) {
|
|
|
457
575
|
return scored.map((r) => ({
|
|
458
576
|
name: r.name,
|
|
459
577
|
score: r.score + (relatedBonus.get(r.name) ?? 0),
|
|
460
|
-
why: r.why
|
|
578
|
+
why: r.why,
|
|
579
|
+
whenNotToUse: r.whenNotToUse,
|
|
580
|
+
related: r.related
|
|
461
581
|
})).filter((r) => r.score >= 0).sort((a, b) => b.score - a.score || a.name.localeCompare(b.name)).slice(0, 5);
|
|
462
582
|
}
|
|
463
583
|
//#endregion
|
|
@@ -490,8 +610,7 @@ function createServer(options = {}) {
|
|
|
490
610
|
description: "List available component registries: the cascade directory plus any configured via CASCADE_REGISTRIES env.",
|
|
491
611
|
inputSchema: {}
|
|
492
612
|
}, async () => {
|
|
493
|
-
|
|
494
|
-
return json(mergeRegistries(directory, getEnvRegistries()).map(({ namespace, name, description, verified, homepage }) => ({
|
|
613
|
+
return json(mergeRegistries(await fetchDirectory(fetchFn), getEnvRegistries()).map(({ namespace, name, description, verified, homepage }) => ({
|
|
495
614
|
namespace,
|
|
496
615
|
name,
|
|
497
616
|
description,
|
|
@@ -627,18 +746,32 @@ function createServer(options = {}) {
|
|
|
627
746
|
components: z.array(z.string()).optional().describe("Component names to include")
|
|
628
747
|
}
|
|
629
748
|
}, ({ description, components }) => {
|
|
630
|
-
const { config, errors } = scaffoldView({
|
|
749
|
+
const { config, errors, grammar } = scaffoldView({
|
|
631
750
|
description,
|
|
632
751
|
...components ? { components } : {}
|
|
633
752
|
}, registry);
|
|
634
753
|
if (errors.length > 0) return json({
|
|
635
754
|
valid: false,
|
|
636
755
|
errors,
|
|
637
|
-
config
|
|
756
|
+
config,
|
|
757
|
+
grammar
|
|
638
758
|
});
|
|
639
759
|
return json({
|
|
640
760
|
valid: true,
|
|
641
|
-
config
|
|
761
|
+
config,
|
|
762
|
+
grammar
|
|
763
|
+
});
|
|
764
|
+
});
|
|
765
|
+
server.registerTool("get_view_grammar", {
|
|
766
|
+
title: "Get view grammar",
|
|
767
|
+
description: "Get the bound-vocabulary grammar + system prompt for generating valid ViewConfig JSON, derived from the component manifests. Use this to constrain an LLM to cascivo's real components, props, and enum values (anti-hallucination). Optionally scope to a subset of components.",
|
|
768
|
+
inputSchema: { components: z.array(z.string()).optional().describe("Scope the vocabulary to these component names. Omit for the full registry.") }
|
|
769
|
+
}, ({ components }) => {
|
|
770
|
+
const grammar = buildGrammar(registry, components);
|
|
771
|
+
return json({
|
|
772
|
+
grammar: formatGrammar(grammar),
|
|
773
|
+
prompt: buildGenerationPrompt(registry, components ? { components } : {}),
|
|
774
|
+
components: grammar.components
|
|
642
775
|
});
|
|
643
776
|
});
|
|
644
777
|
server.registerTool("get_tokens", {
|
|
@@ -716,6 +849,6 @@ if (argv[1] !== void 0 && import.meta.url === pathToFileURL(argv[1]).href) main(
|
|
|
716
849
|
process.exitCode = 1;
|
|
717
850
|
});
|
|
718
851
|
//#endregion
|
|
719
|
-
export { VERSION, createServer, generateThemeCss, getComponent, listComponents, loadRegistry, main, scaffoldPage, searchComponents };
|
|
852
|
+
export { VERSION, buildGenerationPrompt, buildGrammar, createServer, formatGrammar, generateThemeCss, getComponent, listComponents, loadRegistry, main, parseEnum, scaffoldPage, searchComponents };
|
|
720
853
|
|
|
721
854
|
//# sourceMappingURL=index.mjs.map
|