@plitzi/sdk-mcp 0.38.6 → 0.38.8
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/CHANGELOG.md +397 -0
- package/README.md +9 -9
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -3
- package/dist/modules/mcp/helpers/guide.js +74 -35
- package/dist/modules/mcp/index.d.ts +2 -2
- package/dist/modules/mcp/server.d.ts +4 -4
- package/dist/modules/mcp/server.js +10 -5
- package/dist/modules/mcp/tests/cheapMistakes.test.d.ts +1 -0
- package/dist/modules/mcp/tests/helpers.d.ts +9 -2
- package/dist/modules/mcp/tests/intents.test.d.ts +1 -0
- package/dist/modules/mcp/tests/look.test.d.ts +1 -0
- package/dist/modules/mcp/tools/apply/index.d.ts +706 -62
- package/dist/modules/mcp/tools/apply/index.js +70 -20
- package/dist/modules/mcp/tools/describeOperation.d.ts +11 -0
- package/dist/modules/mcp/tools/describeOperation.js +40 -0
- package/dist/modules/mcp/tools/describeOperation.test.d.ts +1 -0
- package/dist/modules/mcp/tools/index.d.ts +1 -6
- package/dist/modules/mcp/tools/index.js +12 -9
- package/dist/modules/mcp/tools/intents.d.ts +5 -0
- package/dist/modules/mcp/tools/intents.js +201 -0
- package/dist/modules/mcp/tools/look.d.ts +17 -0
- package/dist/modules/mcp/tools/look.js +32 -0
- package/dist/modules/mcp/tools/operations/closed.d.ts +7 -0
- package/dist/modules/mcp/tools/operations/closed.js +29 -0
- package/dist/modules/mcp/tools/operations/index.d.ts +2928 -359
- package/dist/modules/mcp/tools/operations/index.js +72 -51
- package/dist/modules/mcp/tools/operations/schema/bindings/upsertBinding.d.ts +1 -1
- package/dist/modules/mcp/tools/operations/schema/elements/moveElement.d.ts +1 -1
- package/dist/modules/mcp/tools/operations/schema/elements/repeatElement.d.ts +1 -1
- package/dist/modules/mcp/tools/operations/schema/elements/upsertElement.d.ts +1 -1
- package/dist/modules/mcp/tools/operations/schema/interactions/upsertInteractionFlow.d.ts +1 -1
- package/dist/modules/mcp/tools/operations/schema/operations.d.ts +5 -5
- package/dist/modules/mcp/tools/operations/schema/shared.d.ts +3 -3
- package/dist/modules/mcp/tools/operations/schema/shared.js +7 -6
- package/dist/modules/mcp/tools/operations/schemaIds.js +11 -5
- package/dist/modules/mcp/tools/operations/style/definitions/patchDefinition.d.ts +90 -0
- package/dist/modules/mcp/tools/operations/style/definitions/patchDefinition.js +2 -1
- package/dist/modules/mcp/tools/operations/style/definitions/upsertDefinition.d.ts +90 -0
- package/dist/modules/mcp/tools/operations/style/definitions/upsertDefinition.js +2 -1
- package/dist/modules/mcp/tools/operations/style/definitions/upsertDefinitions.d.ts +90 -0
- package/dist/modules/mcp/tools/operations/style/definitions/upsertDefinitions.js +8 -1
- package/dist/modules/mcp/tools/operations/style/globalStyles/patchGlobalStyle.d.ts +90 -0
- package/dist/modules/mcp/tools/operations/style/globalStyles/patchGlobalStyle.js +2 -1
- package/dist/modules/mcp/tools/operations/style/globalStyles/upsertGlobalStyle.d.ts +90 -0
- package/dist/modules/mcp/tools/operations/style/globalStyles/upsertGlobalStyle.js +2 -1
- package/dist/modules/mcp/tools/operations/style/idStyles/patchIdStyle.d.ts +90 -0
- package/dist/modules/mcp/tools/operations/style/idStyles/patchIdStyle.js +2 -1
- package/dist/modules/mcp/tools/operations/style/idStyles/upsertIdStyle.d.ts +90 -0
- package/dist/modules/mcp/tools/operations/style/idStyles/upsertIdStyle.js +2 -1
- package/dist/modules/mcp/tools/operations/style/operations.d.ts +639 -9
- package/dist/modules/mcp/tools/operations/style/shared.d.ts +394 -0
- package/dist/modules/mcp/tools/operations/style/shared.js +26 -8
- package/dist/modules/mcp/tools/operations/style/translator.js +26 -1
- package/dist/modules/mcp/tools/operations/style/validate.d.ts +4 -0
- package/dist/modules/mcp/tools/operations/style/validate.js +63 -0
- package/dist/modules/mcp/tools/operations/style/write.d.ts +1 -1
- package/dist/modules/mcp/tools/operations/style/write.js +88 -2
- package/dist/modules/mcp/tools/render.d.ts +675 -45
- package/dist/modules/mcp/tools/render.js +5 -1
- package/dist/modules/mcp/tools/shared/draftBatch.d.ts +3 -2
- package/dist/modules/mcp/tools/shared/draftBatch.js +16 -5
- package/dist/modules/mcp/tools/shared/effects.d.ts +2 -0
- package/dist/modules/mcp/tools/shared/effects.js +155 -0
- package/dist/modules/mcp/tools/shared/effects.test.d.ts +1 -0
- package/dist/modules/mcp/tools/shared/look.d.ts +32 -0
- package/dist/modules/mcp/tools/shared/look.js +128 -0
- package/dist/modules/mcp/tools/shared/normalizeOperations.d.ts +6 -0
- package/dist/modules/mcp/tools/shared/normalizeOperations.js +37 -0
- package/dist/modules/mcp/tools/shared/repeats.d.ts +13 -0
- package/dist/modules/mcp/tools/shared/repeats.js +38 -0
- package/dist/modules/mcp/tools/shared/tool.d.ts +9 -6
- package/dist/modules/mcp/tools/shared/tool.js +2 -1
- package/dist/modules/mcp/tools/shared/validator/context.d.ts +0 -1
- package/dist/modules/mcp/tools/shared/validator/elements.js +0 -1
- package/dist/modules/mcp/tools/shared/validator/index.js +25 -2
- package/dist/modules/mcp/types/aiSchema.d.ts +13 -1
- package/dist/modules/mcp/types/screenshotTypes.d.ts +3 -3
- package/dist/modules/mcp/types/toolTypes.d.ts +2 -4
- package/dist/options.d.ts +4 -5
- package/dist/preview/createPreview.js +9 -18
- package/package.json +7 -7
- package/skills/plitzi-render/SKILL.md +8 -184
- package/skills/plitzi-render/reference/good-call.md +88 -0
- package/skills/plitzi-render/reference/interactive.md +64 -0
- package/skills/plitzi-render/reference/looks.md +29 -0
- package/dist/modules/mcp/tools/preview.d.ts +0 -793
- package/dist/modules/mcp/tools/preview.js +0 -37
- package/dist/modules/mcp/tools/screenshot.d.ts +0 -1078
- package/dist/modules/mcp/tools/screenshot.js +0 -127
- package/dist/modules/mcp/tools/validate.d.ts +0 -1069
- package/dist/modules/mcp/tools/validate.js +0 -32
|
@@ -2,7 +2,7 @@ import { BUILTIN_TRANSFORMERS, GLOBAL_SOURCES, MOTION_ENTERS, MOTION_LOOPS } fro
|
|
|
2
2
|
//#region src/modules/mcp/helpers/guide.ts
|
|
3
3
|
var GLOBALS = GLOBAL_SOURCES.map((source) => `\`${source}\``).join(", ");
|
|
4
4
|
var OTHER_TRANSFORMERS = Object.keys(BUILTIN_TRANSFORMERS).filter((action) => action !== "twigTemplate").map((action) => `\`${action}\``).join(", ");
|
|
5
|
-
var serverInstructions = "Plitzi AI server: read-then-write editing of a Plitzi space. Reads follow a filesystem model — list cheap, read one item in detail on demand; never fetch a whole tree you do not need. Workflow: (1) read plitzi://primer/{env} once — it bundles a quickstart of the guide, types, css-properties and page/definition/variable summaries in a single call; (2) plitzi_search with include:\"detail\" to jump to elements — each hit then carries its uri, stateVersion AND full style/resolvedStyle, so an edit needs no per-element read; open a page skeleton or element only when you need its tree/detail (the skeleton already lists the style classes of each node, and plitzi_read fetches many uris at once); (3) plitzi_apply with dryRun to preview a batch; (4) plitzi_apply to persist, passing expectedResourceVersions to guard against concurrent edits — apply and search both hand back the versions you need for the next edit. Use patchElement / patchDefinition to change only some props / CSS (the upsert variants replace them all). An element read (and search include:\"detail\") inlines the CSS of the definitions it attaches under resolvedStyle, so you rarely need a separate definition read. Every element has ONE name and it IS its id ([A-Za-z0-9_-] starting with a letter, unique, chosen by you) — the same name is the runtime wiring key, so a provider source is `<type>_<name>.<field>`, visible to the provider’s DESCENDANTS only (bind inside its subtree). CSS is plain kebab-case — write shorthands freely (`border: 1px solid red`, `padding: 8px 16px`, `font: bold 16px/1.5 Arial`), they are expanded to longhands for you and STORED that way, so read-back shows the longhands; style vars are var(--name), schema vars are {{name}}. READERS — do not confuse them: MCP *resources* are the browsable catalog (list them, or open one by URI); plitzi_search FINDS elements by label/type/attribute and hands you the name to write ops against; plitzi_read BATCH-fetches URIs you already hold. Reach for search/read to work; browse resources to discover. CMS / API integrations (Strapi, WordPress, Contentful, any REST service) go through a CONNECTOR: a manifest you author declaring the base URL, endpoints and auth template, which the SERVER executes — read plitzi://connector-presets for working ones and plitzi://connectors/{env} for this space’s. You never see or create the credential; the space owner attaches it, and the connector saves without one. An apiContainer reads through it only with runtime:\"server\". Elements also carry applied style variants + visibility (initialState), data bindings and interaction flows: edit them with patchElement (initialState), upsertBinding/patchBinding/deleteBinding, and upsertInteractionFlow/patchInteractionNode/deleteInteraction. An element read shows all three plus availableVariants (which variant each of its classes offers). Build pages people can use without sight: screen readers and browser agents (Claude in Chrome) work a page through its accessibility tree, so every control needs words and clicks go on buttons and links — see Accessibility in plitzi://guide, and
|
|
5
|
+
var serverInstructions = "Plitzi AI server: read-then-write editing of a Plitzi space. Reads follow a filesystem model — list cheap, read one item in detail on demand; never fetch a whole tree you do not need. Workflow: (1) read plitzi://primer/{env} once — it bundles a quickstart of the guide, types, css-properties and page/definition/variable summaries in a single call; (2) plitzi_search with include:\"detail\" to jump to elements — each hit then carries its uri, stateVersion AND full style/resolvedStyle, so an edit needs no per-element read; open a page skeleton or element only when you need its tree/detail (the skeleton already lists the style classes of each node, and plitzi_read fetches many uris at once); (3) plitzi_apply with dryRun to preview a batch; (4) plitzi_apply to persist, passing expectedResourceVersions to guard against concurrent edits — apply and search both hand back the versions you need for the next edit. Use patchElement / patchDefinition to change only some props / CSS (the upsert variants replace them all). An element read (and search include:\"detail\") inlines the CSS of the definitions it attaches under resolvedStyle, so you rarely need a separate definition read. Every element has ONE name and it IS its id ([A-Za-z0-9_-] starting with a letter, unique, chosen by you) — the same name is the runtime wiring key, so a provider source is `<type>_<name>.<field>`, visible to the provider’s DESCENDANTS only (bind inside its subtree). CSS is plain kebab-case — write shorthands freely (`border: 1px solid red`, `padding: 8px 16px`, `font: bold 16px/1.5 Arial`), they are expanded to longhands for you and STORED that way, so read-back shows the longhands; style vars are var(--name), schema vars are {{name}}. READERS — do not confuse them: MCP *resources* are the browsable catalog (list them, or open one by URI); plitzi_search FINDS elements by label/type/attribute and hands you the name to write ops against; plitzi_read BATCH-fetches URIs you already hold. Reach for search/read to work; browse resources to discover. CMS / API integrations (Strapi, WordPress, Contentful, any REST service) go through a CONNECTOR: a manifest you author declaring the base URL, endpoints and auth template, which the SERVER executes — read plitzi://connector-presets for working ones and plitzi://connectors/{env} for this space’s. You never see or create the credential; the space owner attaches it, and the connector saves without one. An apiContainer reads through it only with runtime:\"server\". Elements also carry applied style variants + visibility (initialState), data bindings and interaction flows: edit them with patchElement (initialState), upsertBinding/patchBinding/deleteBinding, and upsertInteractionFlow/patchInteractionNode/deleteInteraction. An element read shows all three plus availableVariants (which variant each of its classes offers). Build pages people can use without sight: screen readers and browser agents (Claude in Chrome) work a page through its accessibility tree, so every control needs words and clicks go on buttons and links — see Accessibility in plitzi://guide, and plitzi_look (its accessibility outline, the default view) to check. Separately, to SHOW the user a small self-contained widget (offline, no space or backend) instead of editing the space — a card, hero, pricing table, a visual answer — use plitzi_render; read plitzi://render/guide for it.";
|
|
6
6
|
var widgetsOnlyInstructions = "Plitzi widget server (widgets-only connection). This connection carries NO Plitzi space: nothing can be read or edited in one, and the space tools are not offered here — do not look for them. What it does do is build self-contained UI widgets fully offline, with no backend, account or setup: call plitzi_render to SHOW the user a real rendered layout (card, hero, pricing table, checklist, form, gallery) instead of describing one. Read plitzi://render/guide first — the element/prop table, the style model and a worked example; plitzi://render/types lists every element type you can author (plitzi_read fetches both). To change a widget you already rendered, call plitzi_render again with patch:true and its renderId. If the user wants to edit their real Plitzi space from here, that is a reconnection they make: the integration must be re-authorized and granted a space (the consent screen lists theirs) — you cannot do it from this connection, and no retry will change it.";
|
|
7
7
|
var guideQuickstart = `# Plitzi AI MCP — quickstart
|
|
8
8
|
This is the condensed guide; read \`plitzi://guide\` for the full reference (every resource, op and example).
|
|
@@ -51,8 +51,8 @@ a QueryBuilder RuleGroup gating the binding.
|
|
|
51
51
|
as \`icon\` (\`iconPlacement\` before/after, its class on the \`icon\` slot) — never a \`text\` or \`fontAwesome\` child;
|
|
52
52
|
a text child also ignores the box's colour and hover. Chrome on several pages is a **layout**; the nav item of the page being shown is marked by the
|
|
53
53
|
\`current\` state of its class, not by a copy of the header per page. Sibling rows of data are one \`repeatElement\`; a
|
|
54
|
-
block repeated with other words is a **component** (\`upsertComponent { fromRef }\`). \`
|
|
55
|
-
\`
|
|
54
|
+
block repeated with other words is a **component** (\`upsertComponent { fromRef }\`). \`plitzi_apply\` (with or
|
|
55
|
+
without \`dryRun\`) answers with **\`suggestions\`** for what the batch could have written shorter, each with the elements
|
|
56
56
|
it saves — never blocking; take them unless the copies are about to diverge.
|
|
57
57
|
|
|
58
58
|
**Interactions** (\`upsertInteractionFlow\`): a \`trigger\` node first, then callbacks/utilities **in order** (links
|
|
@@ -87,7 +87,7 @@ element or page — not \`visible\`. Read anywhere as \`{{ flags.x }}\`.
|
|
|
87
87
|
**Accessible by default:** screen readers and browser agents (Claude in Chrome) read the accessibility tree, so every
|
|
88
88
|
button/link needs words (an icon-only button a \`title\`), every field a \`label\` (\`hideLabel: true\` hides it), every
|
|
89
89
|
image an \`alt\` or \`decorative: true\`; clicks go on a \`button\`/\`link\`, never a container; headings step down one
|
|
90
|
-
level at a time. \`
|
|
90
|
+
level at a time. \`plitzi_look\` shows the tree and what has no name.
|
|
91
91
|
|
|
92
92
|
**Everything the space holds is public.** Its pages, variables, attributes, flow params and mock data ship to every
|
|
93
93
|
visitor's browser, and a file on a public bucket of its CDN is served to anyone who has its address. A key, a token or
|
|
@@ -135,8 +135,8 @@ Never download a whole tree you do not need.
|
|
|
135
135
|
\`link\` navigates between pages, \`list\` repeats a template over a data array. \`plugin\` types are custom elements.
|
|
136
136
|
- \`plitzi://css-properties\` — valid kebab-case CSS property keys.
|
|
137
137
|
- \`plitzi://explain/{name}\` — what a name means: an element type's attributes, triggers and callbacks; a step's
|
|
138
|
-
params; what a trigger hands its flow; a problem code's fix. \`plitzi://explain/steps\` (or
|
|
139
|
-
codes, transformers) lists every one of a kind.
|
|
138
|
+
params and what it publishes; what a trigger hands its flow; a problem code's fix. \`plitzi://explain/steps\` (or
|
|
139
|
+
elements, triggers, codes, transformers) lists every one of a kind.
|
|
140
140
|
- \`plitzi://schema/{env}/pages\` — page **summaries** (ref, label, elementCount, folder). No element trees.
|
|
141
141
|
- \`plitzi://schema/{env}/layouts\` — the shared **layout shells** (header/sidebar/footer) and the pages rendered
|
|
142
142
|
inside each. Read one like a page. See *Shared layouts* below.
|
|
@@ -217,25 +217,40 @@ stateVersion) and returns any **style definitions** whose name matches the query
|
|
|
217
217
|
When you do hold several refs to open (e.g. from a skeleton), read them together with \`plitzi_read\` rather than one at a time.
|
|
218
218
|
|
|
219
219
|
## Tools
|
|
220
|
-
- \`
|
|
221
|
-
malformations** in any resource the batch touches (see below)
|
|
222
|
-
|
|
223
|
-
\`
|
|
224
|
-
|
|
220
|
+
- \`plitzi_apply\` — validate → apply → persist atomically. Rejects the whole batch on any error or conflict, and
|
|
221
|
+
reports **pre-existing malformations** in any resource the batch touches (see below) and \`suggestions\` (see
|
|
222
|
+
*Suggestions*). Pass \`dryRun: true\` to check and apply in memory only — the same answer, nothing persisted — and
|
|
223
|
+
\`look\` (\`"html"\`, \`"image"\`, \`"accessibility"\` or \`"both"\`, with \`pageRef\` and \`viewport\`) to see the page
|
|
224
|
+
as the batch leaves it in the same call. Check and look with \`dryRun\`, then send the same operations without it.
|
|
225
|
+
\`effects\` is what the batch did, read off the space before and after it — every element, attribute, class and
|
|
226
|
+
setting it changed, one line each: read it, not your batch, for what is now so. \`Nothing changed\` and \`NOT saved\`
|
|
227
|
+
lead the warnings when they are so.
|
|
228
|
+
- **By intention**, a few parameters and the element named by its ref alone — the page is found, the operations
|
|
229
|
+
written, the batch checked and saved as \`plitzi_apply\` saves it, and the answer its \`effects\`, whether it was
|
|
230
|
+
\`saved\`, and what was already so:
|
|
231
|
+
\`plitzi_set_attributes { ref, set, unset }\`, \`plitzi_set_classes { ref, add, remove }\` (the classes it wears and
|
|
232
|
+
you do not name stay), \`plitzi_bind_attribute { ref, to, source }\`, \`plitzi_place_component { component, ref, into,
|
|
233
|
+
props }\`, \`plitzi_add_page { ref, slug, layout }\`. One of them when it says the whole change; anything else is one
|
|
234
|
+
batch of \`plitzi_apply\`.
|
|
235
|
+
- \`plitzi_describe_operation\` — one operation's schema by its \`type\` (every field, which are required); without a
|
|
236
|
+
type, every operation type there is. Ask for the one you are writing instead of guessing a field: a field an
|
|
237
|
+
operation does not have is refused naming the one meant (\`"prop" (did you mean "props"?)\`), and a type spelt with
|
|
238
|
+
other capitals is read as the catalog spells it and said in \`warnings\`. The same batch refused twice is not run a
|
|
239
|
+
third time (\`REPEATED_BATCH\`) — change what the errors name, or ask the person.
|
|
225
240
|
- \`plitzi_search\` — find elements (and pages/definitions) across the space.
|
|
226
241
|
- \`plitzi_read\` — read many resource **uris in one batch** (pages, elements, definitions, variables). Pass the
|
|
227
242
|
ready-made uris from search / a write response; each result is \`{ uri, stateVersion, data }\` or a teachable error,
|
|
228
243
|
so one bad uri never fails the batch. Use it instead of N single reads whenever you already hold several refs.
|
|
229
|
-
- \`
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
(\`
|
|
244
|
+
- \`plitzi_look { pageRef, view, viewport }\` — see a saved page. \`view\`: \`"accessibility"\` (default) reads it as a
|
|
245
|
+
screen reader and a browser agent (Claude in Chrome) do — an outline of roles and names, every control and picture
|
|
246
|
+
with no name listed in \`unnamed\`, as text and far cheaper than an image; \`"html"\` its markup; \`"image"\` a PNG,
|
|
247
|
+
the way to SEE overflow and misalignment (desktop, mobile or \`both\`); \`"both"\` image and outline. A change not
|
|
248
|
+
saved yet is seen with \`plitzi_apply\`'s \`dryRun\` and \`look\`, the same views. It needs the SSR render service
|
|
249
|
+
(\`PREVIEW_UNAVAILABLE\` without it); without a browser, an image or an outline falls back to the HTML, said.
|
|
235
250
|
- \`plitzi_render\` — a different job: show the user a self-contained widget built offline. It never touches the space.
|
|
236
251
|
|
|
237
252
|
## Suggestions — the same page with fewer elements
|
|
238
|
-
\`
|
|
253
|
+
\`plitzi_apply\` (with or without \`dryRun\`) answers with \`suggestions\`: lines like \`[content-attribute] … (saves 4
|
|
239
254
|
elements)\`, each naming a shorter way to what the batch just wrote. Only what THIS batch opened up is said — what the
|
|
240
255
|
space already had is not repeated on every batch — and none of them blocks anything: the page renders as written.
|
|
241
256
|
- \`repeated-on-pages\` — the same block at the edge of several pages: put it in a **layout** once (a block only some
|
|
@@ -357,7 +372,11 @@ You do not have to rewrite them.
|
|
|
357
372
|
\`justify-content\` as separate properties.
|
|
358
373
|
- CSS is grouped by breakpoint: \`desktop\`, \`tablet\`, \`mobile\`.
|
|
359
374
|
- Reference a style variable in CSS as \`var(--name)\`; a schema variable in a prop as \`{{name}}\`.
|
|
360
|
-
- \`element.style.base\` is a **list** of definition refs; other slots go under \`element.style.slots
|
|
375
|
+
- \`element.style.base\` is a **list** of definition refs; other slots go under \`element.style.slots\` — the slots
|
|
376
|
+
\`plitzi://explain/{type}\` lists, never custom CSS on the SDK's own class names. A \`markdown\` or a \`richText\`
|
|
377
|
+
has a slot per part of the document it writes (\`heading\`, \`heading2\`, \`paragraph\`, \`link\`, \`code\`,
|
|
378
|
+
\`codeBlockFrame\`…); a \`formControl\` its \`input\` box, the \`field\` inside it, \`label\`, \`requiredMark\`, \`error\`;
|
|
379
|
+
a \`pagination\` its \`previous\`, \`page\`, \`next\` (the page shown is the class's \`current\` state).
|
|
361
380
|
- **An element can attach SEVERAL classes at once, and they all apply.** \`style.base\` holds a list, and each
|
|
362
381
|
non-base slot holds its own — every attached definition contributes CSS, and they **cascade** (a later class, then a
|
|
363
382
|
global/id rule, overrides an earlier one on the same property). So when a style looks wrong, the culprit may be
|
|
@@ -403,6 +422,15 @@ hovered or in a variant (\`.card:hover .icon\`, a collapsed sidebar hiding its l
|
|
|
403
422
|
keyed by a class the ancestor wears: \`ancestors: { "toolbar": { "desktop": { … } }, "card": { "states": { "hover":
|
|
404
423
|
{ "desktop": { … } } } }, "sidebar": { "variants": { "collapsed": … } } }\`.
|
|
405
424
|
Any ancestor counts, not only the parent; the class's own states and variants win over these. Never customCss for it.
|
|
425
|
+
\`">"\` keys the parent, whatever it wears — a component's part reacting to what it sits in.
|
|
426
|
+
|
|
427
|
+
**Pseudo-elements and conditions** sit beside \`states\` in a definition and in each of its variants:
|
|
428
|
+
\`pseudos: { "after": { "desktop": { "content": "\\"→\\"" }, "states": { "hover": { "desktop": { … } } } } }\`
|
|
429
|
+
(\`before\`/\`after\` are drawn only with a quoted \`content\`; also \`selection\`, \`marker\`, \`placeholder\`,
|
|
430
|
+
\`first-letter\`, \`first-line\`), and \`conditions: { "motion-reduce": { "desktop": { … } }, "container (max-width:
|
|
431
|
+
30rem)": { … } }\` (the nearest ancestor whose class sets \`container-type\`). A patch keeps the ones it does not name;
|
|
432
|
+
\`null\` removes one. A state beyond \`hover\`/\`focus-visible\`/\`current\`: \`expanded\` (an open trigger), \`first\`,
|
|
433
|
+
\`last\`, \`odd\`, \`even\`.
|
|
406
434
|
|
|
407
435
|
## Variables, design tokens and fonts
|
|
408
436
|
- **Schema variables** are space-wide values a prop reads as \`{{name}}\`: \`upsertVariable { name, variableType,
|
|
@@ -444,7 +472,7 @@ that apiContainer; inside a \`list\`, the repeated \`listItem\` and its children
|
|
|
444
472
|
(\`list_<name>.item.<field>\`). The global sources — ${GLOBALS} — have no \`<type>_<name>\` head and are
|
|
445
473
|
bindable anywhere. Binding an element to an element source outside its
|
|
446
474
|
provider's subtree is schema-valid but **broken at runtime** (the source is not in scope), so
|
|
447
|
-
\`
|
|
475
|
+
\`plitzi_apply\` treats it as an **error and rejects the batch** — move the element under the
|
|
448
476
|
provider, or bind a source that is in scope.
|
|
449
477
|
|
|
450
478
|
**mockData is builder-only.** An \`apiContainer\`'s \`mockData\` prop feeds sample data **while editing in the
|
|
@@ -479,9 +507,11 @@ you — never wire them by hand. Each step also has an \`enabled\` flag (see dis
|
|
|
479
507
|
|
|
480
508
|
**Each step reads the page as it is when it runs**: a \`when\` or a \`{{ state.x }}\` after a \`setState\` sees the new
|
|
481
509
|
value, and one after a \`delay\` sees what changed meanwhile. To act on the value from BEFORE a write, put the reading
|
|
482
|
-
step first.
|
|
483
|
-
|
|
484
|
-
\`
|
|
510
|
+
step first. A step's \`when\` asks an earlier step only for what it publishes (\`plitzi://explain/<action>\` lists it):
|
|
511
|
+
a run's \`<step>.status\` (\`runServerAction\` only), a sign-in's \`<step>.ok\` — any other key is refused
|
|
512
|
+
(\`condition-field-unpublished\`). **A trigger fired again while its flow runs is ignored** (no double submit); set
|
|
513
|
+
\`"whileRunning": "queue"\` on the trigger node for a stream of events that must each run in order (\`"parallel"\` runs
|
|
514
|
+
them at once, \`"latest"\` stops the running flow — its server action or request too — for a search as you type).
|
|
485
515
|
**Keyboard shortcuts** are a trigger every element has: \`onKey\` with param \`keys\` — \`"f"\`, \`"shift+f"\`,
|
|
486
516
|
\`"mod+k"\` (⌘ on a Mac, Ctrl elsewhere), \`"plus, ="\`, \`"escape"\`. Heard on the whole page while the element is
|
|
487
517
|
mounted, ignored while someone types in a field; the flow reads the key pressed as \`{{ <trigger id>.key }}\`.
|
|
@@ -522,7 +552,8 @@ mounted, ignored while someone types in a field; the flow reads the key pressed
|
|
|
522
552
|
nothing outside the element needs to know it is open; pick the state one when something else binds to it.
|
|
523
553
|
- \`utility\` — a built-in utility action (no element/source module); nodeType \`utility\`. Use the **exact** param
|
|
524
554
|
names: \`delayTime\` waits \`time\` milliseconds (**not** \`delay\`), \`twigTemplate\` (\`returnMode\`, \`template\`),
|
|
525
|
-
\`webHook\` (\`url\`, \`method\`, …). See \`utilities\` in
|
|
555
|
+
\`webHook\` (\`url\`, \`method\`, …), \`copyToClipboard\` (\`text\`). See \`utilities\` in
|
|
556
|
+
\`plitzi://interactions/{env}\`.
|
|
526
557
|
|
|
527
558
|
**A param value can be a data binding.** Any interaction param may hold a \`{{ source }}\` token instead of a literal —
|
|
528
559
|
it resolves at runtime exactly like a prop binding, using the same source grammar (\`<type>_<name>.<path>\`, or a
|
|
@@ -727,8 +758,9 @@ any other (\`<namespace>.<action>\`), listed in \`plitzi://actions/{env}/tasks\`
|
|
|
727
758
|
\`defineFunctions\` from \`@plitzi/sdk-server/functions\`. Files import each other by relative path — no package,
|
|
728
759
|
no Node built-in.
|
|
729
760
|
- **\`ctx\` is all a function reaches:** \`ctx.kv\` (the space's store), \`ctx.fetch(url, init)\` to the hosts
|
|
730
|
-
\`allow.hosts\` names (\`*.example.com\` for subdomains), \`ctx.publish/grant/revoke\` (channels),
|
|
731
|
-
\`ctx.
|
|
761
|
+
\`allow.hosts\` names (\`*.example.com\` for subdomains), \`ctx.publish/grant/revoke\` (channels),
|
|
762
|
+
\`ctx.data("products.json")\` (one file of the space's data, parsed — never imported), \`ctx.log\`, \`ctx.user\` (who
|
|
763
|
+
asked, never their session). A secret is NAMED, never read: \`ctx.fetch(url, { credential: "stripe",
|
|
732
764
|
headers: { authorization: "Bearer {{ credential.apiKey }}" } })\`.
|
|
733
765
|
- **Stateless:** nothing a function keeps in memory outlives the call — a module-level cache or counter starts empty
|
|
734
766
|
every time, on whichever instance runs it. What must last goes in \`ctx.kv\`. A call gets 100 ms of CPU and 10 s;
|
|
@@ -885,14 +917,14 @@ the component reads \`{{ props.item.name }}\`.
|
|
|
885
917
|
"children": [ { "ref": "lamp-buy", "type": "button", "props": { "content": "Buy", "slot": "product-card-actions" } } ] } }
|
|
886
918
|
\`\`\`
|
|
887
919
|
A required prop left out, a prop the component does not declare, a value of the wrong kind or a child naming a slot
|
|
888
|
-
the component does not have is reported by \`
|
|
920
|
+
the component does not have is reported by \`plitzi_apply\`'s \`dryRun\` — fix it before applying.
|
|
889
921
|
|
|
890
922
|
## Pages & folders
|
|
891
923
|
- **A page behind a feature flag**: \`upsertPage { flag: "labs" }\` answers 404 while the flag is off (see **Feature
|
|
892
924
|
flags**); \`flag: null\` removes it.
|
|
893
925
|
- **Always set a \`slug\` when creating a page** (\`upsertPage\`) — it is the page's URL path and good practice for a
|
|
894
926
|
clean, stable route (e.g. \`"pricing"\` or \`"posts/:postId"\`). Omit it and the page ref is used as the slug,
|
|
895
|
-
and \`
|
|
927
|
+
and \`plitzi_apply\` warns so you remember to set a meaningful one.
|
|
896
928
|
- **A page slug is RELATIVE — do NOT start it with \`/\`.** The runtime prepends the leading slash (and any folder
|
|
897
929
|
path) itself, so a leading slash doubles it. Write \`"pricing"\`, not \`"/pricing"\`. (upsertPage strips a leading
|
|
898
930
|
slash for you, but write it relative.)
|
|
@@ -917,7 +949,10 @@ the component does not have is reported by \`plitzi_validate\` — fix it before
|
|
|
917
949
|
- **The link to the page being shown marks itself**: it carries \`aria-current="page"\`, and its class's \`current\`
|
|
918
950
|
state says how it looks — \`{ "type": "patchDefinition", "ref": "nav-link", "states": { "current": { "desktop": {
|
|
919
951
|
"color": "var(--primary)" } } } }\`. So a header written once in a layout lights the right item on every page; never
|
|
920
|
-
copy the header per page to style one item.
|
|
952
|
+
copy the header per page to style one item. A link for a section — a journal and its articles — takes
|
|
953
|
+
\`"current": "section"\` in its props: current on every page under its path too (\`aria-current="true"\`), the same
|
|
954
|
+
state dressing it. The same state dresses any chosen one of a set: a pressed toggle (\`aria-pressed\` — a theme
|
|
955
|
+
toggle's option slot) and a selected tab.
|
|
921
956
|
- **A section of a page** is an element with an \`anchor\` (its \`id\` in the DOM: lowercase, digits, \`-\`; one per
|
|
922
957
|
page, layouts included; not inside a list row or a component). A link lands on it with \`hash\`:
|
|
923
958
|
\`{ "mode": "page", "href": "home", "hash": "plans" }\` goes to \`/#plans\` and scrolls there, from any page.
|
|
@@ -946,10 +981,12 @@ Space-level configuration lives in \`plitzi://settings/{env}\` and is edited wit
|
|
|
946
981
|
- \`customCss\` — **raw global CSS** injected for the whole space. Use it only for genuinely site-wide rules
|
|
947
982
|
(\`@keyframes\`, \`@font-face\`, resets). To style an element, write a **definition** and attach it — never customCss.
|
|
948
983
|
- \`notifications\` — how the toasts an \`addNotification\` step shows look: colours (\`background\`, \`text\`,
|
|
949
|
-
\`success\`, \`danger\`, \`warning\`, \`info\`)
|
|
950
|
-
\`padding\`)
|
|
951
|
-
|
|
952
|
-
|
|
984
|
+
\`success\`, \`danger\`, \`warning\`, \`info\`), shape (\`radius\`, \`font\`, \`fontSize\`, \`fontWeight\`, \`lineHeight\`,
|
|
985
|
+
\`minHeight\`, \`border\`, \`shadow\`, \`padding\`) and the parts inside (\`iconSize\`, \`iconGap\`, \`closeColor\`,
|
|
986
|
+
\`closeOpacity\`, \`progressHeight\`), one CSS value each — a token follows the theme: \`{ "type": "patchSettings",
|
|
987
|
+
"notifications": { "background": "var(--card)", "iconSize": "18px" } }\`. Merged field by field, \`null\` removes one.
|
|
988
|
+
It is stored as rules inside \`customCss\` but reads and changes apart from it: never write a \`.Toastify__*\` rule
|
|
989
|
+
yourself.
|
|
953
990
|
- \`keepState\` / \`stateStorage\` — keep the runtime state (\`state.<key>\`, what \`setState\` writes) across reloads,
|
|
954
991
|
in \`localStorage\`/\`sessionStorage\`, filed under whoever is signed in. It is the space's setting — pages do not
|
|
955
992
|
take one. \`transientState\` lists the top-level keys never kept (a filter, a demo, a panel left open); do not
|
|
@@ -957,10 +994,12 @@ Space-level configuration lives in \`plitzi://settings/{env}\` and is edited wit
|
|
|
957
994
|
\`paintedState\` lists the kept keys the FIRST PAINT shows (the tool a toolbar shows, a name in an avatar): they go
|
|
958
995
|
in a cookie too, so the server draws with them instead of the page swapping them in after load. Small values only.
|
|
959
996
|
- **User provider / auth**: \`userProvider\` — \`basic\` for any HTTP+JSON backend, the name of a provider registered
|
|
960
|
-
in the page, or \`""\`
|
|
997
|
+
in the page, or \`""\` for none — plus \`tokenStorage\`, the \`loginUrl\`/\`userUrl\`/\`refreshUrl\`/\`logoutUrl\`
|
|
961
998
|
endpoints and the \`detailsPath\`/\`tokenPath\`/\`refreshTokenPath\`/\`expirationTimePath\` mapping that says where the
|
|
962
999
|
values sit in their responses. \`sessionHintCookie\` is worth setting whenever the backend can: it names a readable
|
|
963
1000
|
cookie carrying only expiries, which is what lets a page answer "nobody is signed in" without a request.
|
|
1001
|
+
A space served by a self-hosted \`createServer({ auth })\` declares none of these: that server tells its pages where
|
|
1002
|
+
they sign in, and only what the space declares overrides it.
|
|
964
1003
|
On the Plitzi platform, \`userProvider: "server"\` signs visitors in with their Plitzi account on the space's own
|
|
965
1004
|
host: a \`link\` with \`mode: "external"\` to \`/auth/sign-in?return=/\` starts it, \`authLogout\` ends it.
|
|
966
1005
|
- \`visitorRoles\` — what each visitor role gives, \`{ "author": ["postPublish"] }\`: the permissions an action's
|
|
@@ -1034,7 +1073,7 @@ tree names nothing is invisible to both, however it looks. So build every page t
|
|
|
1034
1073
|
The linter warns about these (\`control-without-name\`, \`image-without-alt\`, \`click-on-static-element\`,
|
|
1035
1074
|
\`dropdown-without-control\`, \`heading-level-skipped\`, \`label-ignored\`, \`control-in-decorative\`) on every element
|
|
1036
1075
|
you touch; fix them in the same batch. Then look:
|
|
1037
|
-
\`
|
|
1076
|
+
\`plitzi_look\` shows the page as those readers get it, and lists what has no name.
|
|
1038
1077
|
|
|
1039
1078
|
## Semantics
|
|
1040
1079
|
- **props are fully replaced** on \`upsertElement\`: send every prop you want to keep. To change only some props,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { createMcpServer, handleMcp, serveMcp, readMcpBody } from './handler';
|
|
2
2
|
export { readResource, resourceVersion, registerResources, buildTypeRegistry, cssProperties } from './resources';
|
|
3
|
-
export { apply,
|
|
3
|
+
export { apply, search, read, validateOperations, operation, tools } from './tools';
|
|
4
4
|
export { computeVersion } from './helpers';
|
|
5
5
|
export { createHttpPreviewClient } from './previewClient';
|
|
6
6
|
export { createLocalScreenshotClient, resolveLocalBrowser } from './localScreenshotClient';
|
|
@@ -12,6 +12,6 @@ export type { LocalScreenshotClientConfig } from './localScreenshotClient';
|
|
|
12
12
|
export type { HttpScreenshotClientConfig } from './screenshotClient';
|
|
13
13
|
export type { AccessibilityNode, UnnamedControl } from './accessibilityOutline';
|
|
14
14
|
export type { McpServerContext } from './server';
|
|
15
|
-
export type { ApplyInput, WriteResponse, Persisters, SearchInput, ReadInput, ReadResponse,
|
|
15
|
+
export type { ApplyInput, WriteResponse, Persisters, SearchInput, ReadInput, ReadResponse, Operation, ToolDef, ToolContext } from './tools';
|
|
16
16
|
export type { Space } from './helpers';
|
|
17
17
|
export type * from './types';
|
|
@@ -11,11 +11,11 @@ import { SSRAdapters, ServerLogger, SSRGrant } from '@plitzi/sdk-shared';
|
|
|
11
11
|
export interface McpServerContext {
|
|
12
12
|
adapters: SSRAdapters;
|
|
13
13
|
getGrant: () => Promise<SSRGrant | undefined>;
|
|
14
|
-
/** How
|
|
15
|
-
*
|
|
14
|
+
/** How a look (plitzi_look, plitzi_apply's `look`) reaches the renderer. Absent → it reports PREVIEW_UNAVAILABLE, so an
|
|
15
|
+
* MCP-only deployment without a renderer still runs every other tool. */
|
|
16
16
|
preview?: PreviewClient;
|
|
17
|
-
/** The dedicated browser service
|
|
18
|
-
*
|
|
17
|
+
/** The dedicated browser service a look takes an image or an accessibility outline with. Absent → a look answers
|
|
18
|
+
* the HTML, and says so. */
|
|
19
19
|
screenshot?: ScreenshotClient;
|
|
20
20
|
/** Structured request-log sink. When set, every tool call and resource read emits an McpLogEvent to it (the
|
|
21
21
|
* consumer renders them); otherwise logging falls back to the console when MCP_DEBUG=1. */
|
|
@@ -72,7 +72,7 @@ var createMcpServer = async ({ adapters, getGrant, preview, screenshot, logger,
|
|
|
72
72
|
const getSpace = () => spacePromise ??= loadSpace();
|
|
73
73
|
const server = new McpServer({
|
|
74
74
|
name: "plitzi-mcp",
|
|
75
|
-
version: "0.38.
|
|
75
|
+
version: "0.38.8"
|
|
76
76
|
}, { instructions: hasSpace ? serverInstructions : widgetsOnlyInstructions });
|
|
77
77
|
const { getChanges } = adapters;
|
|
78
78
|
registerResources(server, getSpace, MCP_ENV, log, hasSpace, getChanges ? (query) => getChanges(requireSpaceId(), MCP_ENV, query) : void 0);
|
|
@@ -103,10 +103,15 @@ var createMcpServer = async ({ adapters, getGrant, preview, screenshot, logger,
|
|
|
103
103
|
if (hasSpace) return async (args) => tool.execute(args, await toolContext(tool.name));
|
|
104
104
|
return tool.executePublic ? (args) => tool.executePublic?.(args, MCP_ENV) : void 0;
|
|
105
105
|
};
|
|
106
|
-
|
|
107
|
-
if (tool.requires === "screenshot" && !screenshot) continue;
|
|
106
|
+
const listed = tools.flatMap((tool) => {
|
|
108
107
|
const behavior = behaviorOf(tool);
|
|
109
|
-
|
|
108
|
+
return behavior ? [{
|
|
109
|
+
tool,
|
|
110
|
+
behavior
|
|
111
|
+
}] : [];
|
|
112
|
+
});
|
|
113
|
+
const operationsCarried = listed.some(({ tool }) => tool.carriesOperations);
|
|
114
|
+
for (const { tool, behavior } of listed) {
|
|
110
115
|
const run = async (args) => {
|
|
111
116
|
const start = performance.now();
|
|
112
117
|
try {
|
|
@@ -129,7 +134,7 @@ var createMcpServer = async ({ adapters, getGrant, preview, screenshot, logger,
|
|
|
129
134
|
const config = {
|
|
130
135
|
title: tool.title,
|
|
131
136
|
description: tool.description,
|
|
132
|
-
inputSchema: tool.inputShape,
|
|
137
|
+
inputSchema: operationsCarried && tool.compactInputShape ? tool.compactInputShape : tool.inputShape,
|
|
133
138
|
annotations: { readOnlyHint: tool.access === "read" }
|
|
134
139
|
};
|
|
135
140
|
if (tool.ui) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Space } from '../helpers';
|
|
2
2
|
import { Operation } from '../tools';
|
|
3
|
-
import { Persisters } from '../types';
|
|
3
|
+
import { Persisters, ValidationResult } from '../types';
|
|
4
4
|
declare const buildSpace: () => Space;
|
|
5
5
|
declare const capturing: (space: Space) => {
|
|
6
6
|
persisters: Persisters;
|
|
@@ -10,4 +10,11 @@ declare const spaceWithRoute: () => Space;
|
|
|
10
10
|
declare const varOp: (pageRef: string, type: string, value: string) => Operation;
|
|
11
11
|
declare const scopeSpace: () => Space;
|
|
12
12
|
declare const malformedSpace: () => Space;
|
|
13
|
-
|
|
13
|
+
/**
|
|
14
|
+
* What `plitzi_apply`'s dryRun answers of a batch, as one result to assert on: the same `draftBatch` it runs before
|
|
15
|
+
* anything is saved, so a refusal here is the one an agent meets.
|
|
16
|
+
*/
|
|
17
|
+
declare const checkBatch: (input: {
|
|
18
|
+
operations: Operation[];
|
|
19
|
+
}, space: Space) => ValidationResult;
|
|
20
|
+
export { buildSpace, capturing, checkBatch, spaceWithRoute, varOp, scopeSpace, malformedSpace };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|