@plitzi/sdk-mcp 0.38.7 → 0.38.9
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 +204 -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 +37 -21
- 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 +64 -50
- 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 +229 -180
- 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/interactions/upsertInteractionFlow.d.ts +1 -1
- package/dist/modules/mcp/tools/operations/schema/operations.d.ts +2 -2
- package/dist/modules/mcp/tools/operations/schema/shared.d.ts +2 -2
- package/dist/modules/mcp/tools/operations/schema/shared.js +7 -6
- package/dist/modules/mcp/tools/operations/schemaIds.js +4 -4
- package/dist/modules/mcp/tools/render.d.ts +40 -40
- 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/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 -1423
- package/dist/modules/mcp/tools/preview.js +0 -37
- package/dist/modules/mcp/tools/screenshot.d.ts +0 -1708
- package/dist/modules/mcp/tools/screenshot.js +0 -127
- package/dist/modules/mcp/tools/validate.d.ts +0 -1699
- package/dist/modules/mcp/tools/validate.js +0 -32
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,209 @@
|
|
|
1
1
|
# @plitzi/sdk-mcp
|
|
2
2
|
|
|
3
|
+
## 0.38.9
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [64f4cd6]
|
|
8
|
+
- @plitzi/sdk-server@0.38.9
|
|
9
|
+
- @plitzi/sdk-shared@0.38.9
|
|
10
|
+
- @plitzi/sdk-authoring@0.38.9
|
|
11
|
+
- @plitzi/plitzi-sdk@0.38.9
|
|
12
|
+
- @plitzi/sdk-schema@0.38.9
|
|
13
|
+
- @plitzi/sdk-style@0.38.9
|
|
14
|
+
|
|
15
|
+
## 0.38.8
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- 1b45aae: ## The CLI's commands are named after what they act on
|
|
20
|
+
|
|
21
|
+
Every command sits under the thing it acts on — `plitzi element move`, never a bare `move` that could mean anything —
|
|
22
|
+
and only what acts on the project as a whole or the account stays at the top:
|
|
23
|
+
|
|
24
|
+
| Before | Now |
|
|
25
|
+
| -------------------------------------------- | ------------------------------------------------------------------ |
|
|
26
|
+
| `where`, `edit`, `remove`, `move` | `element where`, `element edit`, `element remove`, `element move` |
|
|
27
|
+
| `check`, `shot`, `import` | `page check`, `page shot`, `page import` |
|
|
28
|
+
| `space`, `pull`, `push`, `lint`, `fix` | `space use`, `space pull`, `space push`, `space lint`, `space fix` |
|
|
29
|
+
| `add plugin`, `pack plugin`, `upload plugin` | `plugin add`, `plugin pack`, `plugin upload` |
|
|
30
|
+
| `add runtime` | `runtime add` |
|
|
31
|
+
| `pack source` | `source pack` |
|
|
32
|
+
| `update` (alias of `upgrade`) | `upgrade` |
|
|
33
|
+
|
|
34
|
+
`create`, `verify`, `doctor`, `upgrade`, `explain`, `feedback`, `login`, `logout` and `whoami` stay at the top, beside
|
|
35
|
+
`functions`, `runtime`, `data` and `skills`. There are no aliases: a name asked for at the top that is a group's command
|
|
36
|
+
answers where it is — `There is no plitzi push: it is one of plitzi space push, plitzi runtime push, plitzi functions
|
|
37
|
+
push` — read off the commands themselves. A project's scripts (`lint:space`, `check`, `shot`) call the new names;
|
|
38
|
+
`plitzi upgrade --write` updates the ones the CLI wrote.
|
|
39
|
+
|
|
40
|
+
## Agents load less to do the same (RFC 0025)
|
|
41
|
+
- **The MCP lists the operations vocabulary once.** A connection with a space listed ~69k tokens of tools before an
|
|
42
|
+
agent did anything — the operations schema five times. `plitzi_apply` carries it; `plitzi_render` lists only its
|
|
43
|
+
operations' types beside it (and keeps the whole schema on a guest connection, where it is alone). The listing is
|
|
44
|
+
now ~18k tokens.
|
|
45
|
+
- **`plitzi_validate` is `plitzi_apply`'s `dryRun`**, which already answered the same; the `validate` function, its
|
|
46
|
+
`validateShape` and `ValidateInput` are gone from `@plitzi/sdk-mcp`.
|
|
47
|
+
- **`plitzi_apply` looks at the page it would leave**: `look: 'html' | 'image' | 'accessibility' | 'both'` (with
|
|
48
|
+
`pageRef`, `viewport`, `fullPage`) renders it — with `dryRun`, as the batch would leave it, nothing saved; without, as
|
|
49
|
+
saved. Check, look and save with the operations written twice, not four times.
|
|
50
|
+
- **`plitzi_look` is the one way to see a saved page** — its accessibility outline (the default: text, cheap), its HTML
|
|
51
|
+
or a PNG; `plitzi_preview` and `plitzi_screenshot` are gone. It is always offered: without a browser service it answers
|
|
52
|
+
the HTML and says so.
|
|
53
|
+
- **`plitzi_describe_operation { type }`** answers one operation's schema, or every type there is; a type that does not
|
|
54
|
+
exist is answered with the nearest one.
|
|
55
|
+
- `closest` is exported from `@plitzi/sdk-authoring`: the nearest of a closed list of names.
|
|
56
|
+
- **`plitzi element where <id | class | words>`** answers where the project's code writes an element — the file, the line and
|
|
57
|
+
the call itself — asked of the code as it is now, so it follows an element wherever somebody moved it. A class is
|
|
58
|
+
found by its name or by the variable that holds it (`nav-link`, `navLink`).
|
|
59
|
+
- **`plitzi element edit <id> --set key=value --remove key`** writes attributes in that call (`content` where the factory takes
|
|
60
|
+
it first), keeping each one's kind, formatted as the project formats, and keeps the change only if the space still
|
|
61
|
+
authors with every value there. Behind both, `locateElements` in `@plitzi/sdk-authoring`: every element with the call
|
|
62
|
+
that wrote it.
|
|
63
|
+
- A generated project's `AGENTS.md` says to ask `where` instead of keeping a note of where things are.
|
|
64
|
+
- **`plitzi doctor` says one fact once**: packages installed from the same place, and packages behind the same version,
|
|
65
|
+
are one line each — on a project installed from local tarballs, ~1,050 tokens of output became ~330.
|
|
66
|
+
- **A mistake costs one line.** An operation type that does not exist is answered with the nearest one; a field an
|
|
67
|
+
operation, an element, a binding or a flow step does not have is refused naming the one meant — it used to be dropped,
|
|
68
|
+
and `prop` for `props` answered success having applied nothing. An element type spelt with other capitals
|
|
69
|
+
(`Heading`) is read as the catalog spells it and said in `warnings`.
|
|
70
|
+
- **The same batch refused twice is not run a third time** (`REPEATED_BATCH`), and the second refusal says so; `plitzi
|
|
71
|
+
edit` does the same, kept in the project's `tmp/refusals.json`.
|
|
72
|
+
- **`plitzi_apply`'s `look` renders a batch through the path a save takes** (`draftBatch`): a
|
|
73
|
+
`repeatElement` expanded, what has one reading read, the same refusals.
|
|
74
|
+
- **Each skill is a core an agent reads every time, and references it opens when the task names one.** The core —
|
|
75
|
+
what it is for, the rules that go wrong most, a table routing each task to its one file — is held to 1,500 tokens:
|
|
76
|
+
`plitzi-authoring` went from ~4,000 to ~920 (every rule kept in `reference/rules.md`, the recipes indexed in
|
|
77
|
+
`reference/recipes.md`, every reference in `reference/index.md`), `plitzi-cli` from ~4,000 to ~820 (projects,
|
|
78
|
+
plugins and troubleshooting are references of their own), `plitzi-render` from ~3,100 to ~1,050.
|
|
79
|
+
- **Intent tools on the MCP**: `plitzi_set_attributes`, `plitzi_set_classes` (classes added or removed, the rest
|
|
80
|
+
kept), `plitzi_bind_attribute`, `plitzi_place_component`, `plitzi_add_page` — a few parameters, the element by its ref alone (the
|
|
81
|
+
page is found, a ref that does not exist answered with the nearest), checked and saved as `plitzi_apply` saves, and
|
|
82
|
+
answered in a line with the next step.
|
|
83
|
+
- **An element may only wear a class the space has, or the batch declares**: `plitzi_apply` used to save one nothing
|
|
84
|
+
defines — rendered unstyled, said by nobody. It is refused naming the nearest class.
|
|
85
|
+
- **`plitzi explain` answers any export of `@plitzi/sdk-authoring`** — `pageFamily`, `styles`, `SpaceSpec` — with its
|
|
86
|
+
signature and the first paragraph of its doc, read from the `.d.ts` the project installed: a few dozen tokens where an
|
|
87
|
+
agent used to search ~180k of published types.
|
|
88
|
+
- **`plitzi element where --by id|class|text`** reads a query one way; without it, the first reading that matches is answered
|
|
89
|
+
and every other one that matched is said with its count and the command for it — a query that means two things is
|
|
90
|
+
never answered as one. `plitzi element edit` reads its element by id alone.
|
|
91
|
+
- **A helper written once and called for many elements** is told apart: `locateElements` answers each element's
|
|
92
|
+
`through` — the calls of the author's code that led to the one that wrote it — so `plitzi element where` says which other
|
|
93
|
+
elements the same call writes and the call that leads to this one alone, and `plitzi element edit` changes a value the helper
|
|
94
|
+
is handed where it is handed (`pageHead('about-head', 'About us')`), refuses an edit of a call that writes several
|
|
95
|
+
elements unless `--every` says so, and never writes `content` beside words given as the factory's first argument.
|
|
96
|
+
- `plitzi explain` of a name that is the project's own says where to read it.
|
|
97
|
+
- **Nothing a write does is silent.** `plitzi_apply` answers `effects`: every change the batch made, read off the space
|
|
98
|
+
before and after it (elements added or removed by subtree, attributes, classes, moves, styles, settings, connectors,
|
|
99
|
+
actions), with a note where a changed attribute is one a binding computes; a batch that changed nothing says so, and
|
|
100
|
+
a store with no persister leads the warnings as `NOT saved: …`. The intent tools answer those `effects`, whether it
|
|
101
|
+
was `saved` and what was already so, refuse to take off a class the element does not wear and to write a value under
|
|
102
|
+
a binding. `plitzi element edit` reads the whole space before and after the edit (`plitzi element readings`, in a fresh process),
|
|
103
|
+
prints every change, and puts the files back when anything changed that was not asked, naming it; it refuses an
|
|
104
|
+
attribute a binding computes, and `plitzi element where` marks those `Bound`. `canonicalJson` (`@plitzi/sdk-shared`) is
|
|
105
|
+
what every before-and-after comparison is made with. Authoring keeps deep enough a call stack (64 frames) that a
|
|
106
|
+
helper inside a helper is still told apart.
|
|
107
|
+
- `locateElements` answers the parts of every component too, in the component (`rootId` is its id): `plitzi element where`
|
|
108
|
+
and `plitzi element edit` reach an element inside a component as they reach one on a page or a layout.
|
|
109
|
+
|
|
110
|
+
## Fixed
|
|
111
|
+
- **A layout no longer mounts twice when the page hydrates.** An element with `runtime: 'server'` was wrapped in its
|
|
112
|
+
static shell while hydrating and handed back without it — under another key — on the next render, so React tore
|
|
113
|
+
down everything under it and built it again. With a server provider around a layout (an `apiContainer` that draws
|
|
114
|
+
no markup of its own), the whole layout's DOM was replaced on every page, and every `motion` arrival in it played
|
|
115
|
+
twice: a visible flicker on load. The shell now stays around the element on both sides of hydration, under the same
|
|
116
|
+
key, and only stops freezing (`frozen`).
|
|
117
|
+
- **A component's instance is written somewhere.** `component(…)` — and each child it places in a slot — rebuilt its
|
|
118
|
+
spec with a spread and lost the marker of where the author wrote it: `plitzi element where` could not place an instance and
|
|
119
|
+
`plitzi element edit` refused it. The original marker is carried (`carryWrittenAt`); `where` finds the words an instance
|
|
120
|
+
hands its component, and `edit` writes an instance's props.
|
|
121
|
+
- `plitzi element edit` follows a value read off a list the call is repeated for (`item.question` in
|
|
122
|
+
`QUESTIONS.flatMap(item => …)`) to the one entry that holds it, in the file the list is written in; when the shared
|
|
123
|
+
value is not a literal it says where it comes from instead of offering `--every`.
|
|
124
|
+
- **`plitzi page check --element` says which class wins.** Each property more than one of the element's classes sets, at
|
|
125
|
+
rest: the value shown, the class it comes from and what the others say — or that they all set it so. Which wins is
|
|
126
|
+
asked of the page, each class taken off for a moment; a style change is verified in text, not with a picture.
|
|
127
|
+
- **`plitzi element where` reads more.** By words it finds every word an element says (`words` on `WrittenElement`: content,
|
|
128
|
+
`label`, `title`, `alt`, `placeholder`, binding templates, an instance's props); by class it says where the class
|
|
129
|
+
is declared (`locateClasses` in `@plitzi/sdk-authoring`); an element repeated over a list says which list, and its
|
|
130
|
+
file; a page or a layout is placed at the object it is declared as.
|
|
131
|
+
- **`plitzi element edit` edits a page** by the attributes `where` shows (`seoPageTitle` written as `seoTitle`;
|
|
132
|
+
`PAGE_SPEC_FIELDS` in `@plitzi/sdk-authoring`), refusing `layout` and `seoEnabled`, which are no field of their own;
|
|
133
|
+
and a value read in more than one place (a list entry a nav and a menu both draw) changes them all only with
|
|
134
|
+
`--every`, each named.
|
|
135
|
+
- **A component prop of a type that does not exist is refused** (`prop-type-unknown`, with the types there are):
|
|
136
|
+
`type: 'string'` was accepted at run time, offered by no editor and checked against nothing. `BUILTIN_PARAM_TYPES`
|
|
137
|
+
in `@plitzi/sdk-shared` is the list, and `BuiltinParamType` is derived from it.
|
|
138
|
+
- **`plitzi element remove <id>` and `plitzi element move <id> --before|--after <id>`** take an element out of the code that writes
|
|
139
|
+
it, or reorder it among its siblings — following a section a helper returns to the helper's call — checked as
|
|
140
|
+
`edit` is: a removal may take only the element and what it holds, a move only reorder its parent, or the file goes
|
|
141
|
+
back. Styles and imports only the removed call used go with it, named; a helper left unread is said.
|
|
142
|
+
- **`plitzi verify`** runs the project's checks — author (no warning), lint:space, typecheck, lint, format — and every
|
|
143
|
+
page with no parameter, and prints only what fails; a page it could not open is said as not checked. Generated
|
|
144
|
+
projects get `npm run verify`, and their `AGENTS.md` names it as the way to leave the project passing.
|
|
145
|
+
- **A component's refusal says where it is written** (by its root's call).
|
|
146
|
+
- **`check --element`** says a class changes nothing on the element only when every property it sets stays without
|
|
147
|
+
it, and names the other elements the class is on: changing the class changes them; taking it off this element does
|
|
148
|
+
not.
|
|
149
|
+
- **An element's generated selector and binding ids are named after its id**, under its parent's place, not after its
|
|
150
|
+
position among its siblings: a move renames nothing. Every space written in code gets new generated names once —
|
|
151
|
+
the same rules, so nothing a visitor sees changes.
|
|
152
|
+
- A change of an element's children is said as what came, went or moved (`faq moved — now after hero, before pricing`).
|
|
153
|
+
- **`plitzi page check --click <id>`** clicks one element and says what changed — flows run and how each step ended, the
|
|
154
|
+
page it went to, what scrolled, what is shown now and what no longer is, the state — or that nothing did, in those words; a flow that
|
|
155
|
+
succeeded while nothing on the page changed is said as that. A click that could not be made, or a flow that failed,
|
|
156
|
+
fails the check.
|
|
157
|
+
- **A refusal of the authored space's gate says where**: each of the validator's errors (`UNRESOLVED_INTERACTION_TARGET`,
|
|
158
|
+
`UNRESOLVED_BINDING_SOURCE`, …) carries the file and line of the element it is about, and a name nothing answers to is
|
|
159
|
+
offered the nearest element that answers the step it was for (`openModal('search')` → `search-modal`, not the
|
|
160
|
+
`search-q` field), or the few that do. `SchemaValidationError` gains `missing` and `wantedBy` (`@plitzi/sdk-schema`).
|
|
161
|
+
- **`plitzi element where` finds the words a list's rows show** when the list is handed them as data (`items:
|
|
162
|
+
[...PLANS]`), and says the list they are the entries of and its file (`Its rows are the entries of PLANS
|
|
163
|
+
(src/space/enterprise/content.ts)`).
|
|
164
|
+
- `plitzi page check --click` says what is **shown** now and what no longer is (drawn, wherever the page is scrolled),
|
|
165
|
+
not "on screen".
|
|
166
|
+
- `plitzi upgrade` says packages installed locally in one line past three, and a skill rewritten within the same
|
|
167
|
+
version as that, not `0.38.7 → 0.38.7`.
|
|
168
|
+
- **What `element edit`, `remove` and `move` read back goes through the gate `npm run author` does**: a change that
|
|
169
|
+
leaves the space refused — a flow still opening a modal that was removed — is put back, the refusal said with where.
|
|
170
|
+
`element remove` refuses before writing when another element's flows act on what it takes away, and says what it
|
|
171
|
+
took once, by the outermost element (`search-modal removed, with 18 inside`). Moving an element beside itself is
|
|
172
|
+
refused as nothing to do.
|
|
173
|
+
- **An id, a plugin folder or a data file written a letter off is offered the nearest one** (`element where`, `edit`,
|
|
174
|
+
`remove`, `move`, `plugin pack`, `data describe`).
|
|
175
|
+
- **A project file that does not load is said at its file and line** — `src/space/hero.ts:139: Expected ','` — by the
|
|
176
|
+
server, `npm run author` and every CLI command, never as a stack (`ProjectModuleError` and `moduleProblem` in
|
|
177
|
+
`@plitzi/sdk-authoring/node`).
|
|
178
|
+
- **`plitzi verify` stops at the first failure** — one broken file fails every later step the same way — and says the
|
|
179
|
+
rest as not run (`--keep-going` runs them anyway); `--no-pages` no longer fails a run that passed.
|
|
180
|
+
- **`plitzi space fix` no longer drops attributes written one level too deep**: `attributes: { value: 5 }` where
|
|
181
|
+
`value: 5` was meant is put in its place (a new `unwrap` fix), not removed with what it said.
|
|
182
|
+
- **`plitzi explain <type>` explains the project's own elements** (`src/plugins/`), and `plugin add` prints how to place
|
|
183
|
+
one with the attributes it was declared with.
|
|
184
|
+
- **`plitzi data describe` says an object keyed by data once**, as a map of one shape with how many keys, so a file of
|
|
185
|
+
five hundred articles reads as one.
|
|
186
|
+
- **`plitzi page check` says a path no page answers before opening it**, with the paths the pages do answer — never a
|
|
187
|
+
redirect home read as a page for signed-in visitors.
|
|
188
|
+
- **`copyToClipboard(text)`**, a utility step (`@plitzi/sdk-interactions`, built with `copyToClipboard` in
|
|
189
|
+
`@plitzi/sdk-authoring`): a "Copy link" button had no step to write with. A browser that gives the page no clipboard
|
|
190
|
+
fails the step, so a toast after it is never said of a copy that was not made.
|
|
191
|
+
- **`plitzi explain` lists the values a param takes only when it is a choice** (`select`): `setState`'s `value` read
|
|
192
|
+
as `'true' | 'false'`, the examples of a free value taken for its only ones.
|
|
193
|
+
- **`plitzi page check --click` says what the page said** — a toast or an alert, `said: "Link copied"` — and **a form
|
|
194
|
+
the browser held back**, with the field and the browser's reason, never as a click that changed nothing.
|
|
195
|
+
- **`plitzi page check --click <id> --fill <id>=<value>`** fills fields before the click as a visitor does (typed, an
|
|
196
|
+
option chosen, a box ticked), so a form's success flow is checked, not only its refusal when empty. A container of
|
|
197
|
+
several fields is refused with their ids; a field filled inside another element says whose it is.
|
|
198
|
+
|
|
199
|
+
- Updated dependencies [1b45aae]
|
|
200
|
+
- @plitzi/sdk-authoring@0.38.8
|
|
201
|
+
- @plitzi/sdk-schema@0.38.8
|
|
202
|
+
- @plitzi/sdk-shared@0.38.8
|
|
203
|
+
- @plitzi/plitzi-sdk@0.38.8
|
|
204
|
+
- @plitzi/sdk-server@0.38.8
|
|
205
|
+
- @plitzi/sdk-style@0.38.8
|
|
206
|
+
|
|
3
207
|
## 0.38.7
|
|
4
208
|
|
|
5
209
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -69,7 +69,7 @@ The server is stateless: it resolves the space per request and reads and writes
|
|
|
69
69
|
| `getGrant(req)` | yes | The space this request operates on **and whether the caller may change it** (`{ spaceId, scope, userId?, canWrite }`), decoded from the verified `Authorization` bearer. You own the JWT secret and the authorization model, so both are decided on your side. Return `undefined` for a missing or invalid token. |
|
|
70
70
|
| `getSchema(spaceId, env)` | yes | The element schema the tools read and mutate. |
|
|
71
71
|
| `getStyle(spaceId, env)` | yes | The full style document, including `platform`/`mode`. |
|
|
72
|
-
| `saveSchema(spaceId, env, schema)` | for writes | Persist a mutated schema. Without it, `plitzi_apply` reports `persisted: false
|
|
72
|
+
| `saveSchema(spaceId, env, schema)` | for writes | Persist a mutated schema. Without it, `plitzi_apply` reports `persisted: false` and leads its warnings with what was NOT saved. |
|
|
73
73
|
| `saveStyle(spaceId, env, style)` | for writes | Persist a mutated style document. |
|
|
74
74
|
| `getChanges(spaceId, env, query)` | no | The space's change history, for the `plitzi://changes` resources. Writes arrive with an `SSRWriteContext` (`userId`, one `batch` per tool call) so a consumer can record them. |
|
|
75
75
|
| `getOfflineData(spaceId, env, rev)` | for preview | Read side of draft-preview. Only the preview endpoint calls it. |
|
|
@@ -103,8 +103,8 @@ types its renderer with.
|
|
|
103
103
|
| `path` | `/mcp` | Where MCP answers inside a server that also serves pages. A dedicated MCP server owns its whole origin and ignores it. |
|
|
104
104
|
| `renderStreaming` | `true` | Whether the `plitzi_render` view paints from the tool arguments while the host still streams them. `false` keeps the view blank until the finished widget arrives. |
|
|
105
105
|
| `proxy` | off | `McpProxyOptions`: with a `secret`, every external URL a render authored is rewritten to this server's signed endpoint (`path`, default `/__proxy`) and fetched here — the origins a widget needs cannot be declared ahead. `baseUrl`, `maxBytes` (8 MiB), `ttl` (7 days), `tools` (`['plitzi_render']`), `enabled`. |
|
|
106
|
-
| `previewClient` | off | `{ url, secret? }`: the SSR `/preview` endpoint, for an MCP server that runs apart from the renderer. Without it
|
|
107
|
-
| `screenshot` | off | `{ serviceUrl, renderBaseUrl }`: the browser service
|
|
106
|
+
| `previewClient` | off | `{ url, secret? }`: the SSR `/preview` endpoint, for an MCP server that runs apart from the renderer. Without it `plitzi_look` and `plitzi_apply`'s `look` report `PREVIEW_UNAVAILABLE`. |
|
|
107
|
+
| `screenshot` | off | `{ serviceUrl, renderBaseUrl }`: the browser service a look renders an image or an accessibility outline through, and the SSR base it navigates to. Without it a look answers the HTML, and says so. |
|
|
108
108
|
| `oauth` | off | OAuth 2.1 for remote connectors — see [OAuth](#oauth). |
|
|
109
109
|
|
|
110
110
|
```ts
|
|
@@ -117,10 +117,10 @@ createServer({ adapters }, { screenshot: { serviceUrl, renderBaseUrl }, proxy: {
|
|
|
117
117
|
|---|---|---|
|
|
118
118
|
| `plitzi_search` | read | Find elements, pages, styles and bindings; returns ready-made URIs |
|
|
119
119
|
| `plitzi_read` | read | Read one or more resources in detail by URI |
|
|
120
|
-
| `
|
|
121
|
-
| `
|
|
122
|
-
| `
|
|
123
|
-
| `
|
|
120
|
+
| `plitzi_apply` | write | Apply a batch of operations and persist; answers with its `effects` — every change it made, read off the space before and after — and its suggestions. `dryRun` checks it without saving, and `look` renders the page as the batch leaves it (HTML, a PNG or the accessibility outline) |
|
|
121
|
+
| `plitzi_set_attributes`, `plitzi_set_classes`, `plitzi_bind_attribute`, `plitzi_place_component`, `plitzi_add_page` | write | One change by its intention — an element's attributes, classes added or removed, a binding, a component placed, a page — by the element's ref alone, saved as `plitzi_apply` saves it, answered with its `effects`, whether it was `saved`, and what was already so |
|
|
122
|
+
| `plitzi_describe_operation` | read | One operation's schema by its type, or the list of every type |
|
|
123
|
+
| `plitzi_look` | read | See a saved page: its accessibility outline (default), its HTML, or a PNG (desktop, mobile or both) |
|
|
124
124
|
| `plitzi_render` | read | Render a self-contained UI widget, offline, with no space |
|
|
125
125
|
| `plitzi_try_function` | write | Run one task of the space's functions against the draft, in the sandbox: its value, logs and error |
|
|
126
126
|
|
|
@@ -164,8 +164,8 @@ This package ships an [Agent Skill](https://agentskills.io/) for `plitzi_render`
|
|
|
164
164
|
a widget instead of writing prose, the shape of a good call, the layout and theme traps that make a widget look
|
|
165
165
|
wrong in a chat panel, and how to iterate on one it already rendered.
|
|
166
166
|
|
|
167
|
-
It lives in [`skills/plitzi-render`](./skills/plitzi-render/SKILL.md)
|
|
168
|
-
copying that folder into your agent's skills directory (Claude Code, VS Code / Copilot, Codex, Gemini CLI, Cline,
|
|
167
|
+
It lives in [`skills/plitzi-render`](./skills/plitzi-render/SKILL.md): a short `SKILL.md` an agent reads every time,
|
|
168
|
+
and a `reference/` it opens when the task names one. It installs by copying that folder into your agent's skills directory (Claude Code, VS Code / Copilot, Codex, Gemini CLI, Cline,
|
|
169
169
|
Goose…):
|
|
170
170
|
|
|
171
171
|
```bash
|
package/dist/index.d.ts
CHANGED
|
@@ -11,9 +11,9 @@ export { previewStage } from './stages/preview';
|
|
|
11
11
|
export { createWidgetProxyStage } from './stages/proxy';
|
|
12
12
|
export { createPreview } from './preview/createPreview';
|
|
13
13
|
export { createMcpServer, handleMcp, serveMcp, readMcpBody, createHttpPreviewClient, createHttpScreenshotClient, createLocalScreenshotClient, resolveLocalBrowser, outlineOfSnapshot, outlineOfTree, unnamedControls } from './modules/mcp';
|
|
14
|
-
export { apply, search, read,
|
|
14
|
+
export { apply, search, read, applyShape, searchShape, readShape, operation, tools } from './modules/mcp/tools';
|
|
15
15
|
export type { McpServerContext, McpRequestOptions, PreviewClient, PreviewRequestBody, PreviewResult, HttpPreviewClientConfig, ScreenshotClient, ScreenshotImage, ScreenshotResult, AccessibilityNode, AccessibilityOutline, CaptureView, UnnamedControl, Viewport, HttpScreenshotClientConfig } from './modules/mcp';
|
|
16
|
-
export type { ApplyInput, SearchInput, SearchResponse, SearchHit, ReadInput, ReadResponse, ReadHit,
|
|
16
|
+
export type { ApplyInput, SearchInput, SearchResponse, SearchHit, ReadInput, ReadResponse, ReadHit, WriteResponse, WriteElement, Persisters, Operation, ToolDef, ToolContext } from './modules/mcp/tools';
|
|
17
17
|
export type { Space } from './modules/mcp/helpers';
|
|
18
18
|
export type { Env } from './modules/mcp/types';
|
|
19
19
|
export type { McpOptions, McpProxyOptions } from './options';
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { operation } from "./modules/mcp/tools/operations/index.js";
|
|
2
|
+
import { outlineOfSnapshot, outlineOfTree, unnamedControls } from "./modules/mcp/accessibilityOutline.js";
|
|
2
3
|
import { apply, applyShape } from "./modules/mcp/tools/apply/index.js";
|
|
3
4
|
import { read, readShape } from "./modules/mcp/tools/read.js";
|
|
4
|
-
import { outlineOfSnapshot, outlineOfTree, unnamedControls } from "./modules/mcp/accessibilityOutline.js";
|
|
5
5
|
import { search, searchShape } from "./modules/mcp/tools/search.js";
|
|
6
|
-
import { validate, validateShape } from "./modules/mcp/tools/validate.js";
|
|
7
6
|
import { tools } from "./modules/mcp/tools/index.js";
|
|
8
7
|
import { createMcpServer } from "./modules/mcp/server.js";
|
|
9
8
|
import { handleMcp, readMcpBody, serveMcp } from "./modules/mcp/handler.js";
|
|
@@ -17,4 +16,4 @@ import { buildMCPPipeline, mcpExtensions } from "./pipeline.js";
|
|
|
17
16
|
import { createServer } from "./createServer.js";
|
|
18
17
|
import { createLocalScreenshotClient, resolveLocalBrowser } from "./modules/mcp/localScreenshotClient.js";
|
|
19
18
|
import { createOAuthGuardStage, createOAuthStage } from "@plitzi/sdk-server/oauth";
|
|
20
|
-
export { apply, applyShape, buildMCPPipeline, createHttpPreviewClient, createHttpScreenshotClient, createLocalScreenshotClient, createMcpOnlyStage, createMcpServer, createMcpStage, createOAuthGuardStage, createOAuthStage, createPreview, createServer, createWidgetProxyStage, handleMcp, mcpExtensions, operation, outlineOfSnapshot, outlineOfTree, previewStage, read, readMcpBody, readShape, resolveLocalBrowser, search, searchShape, serveMcp, tools, unnamedControls
|
|
19
|
+
export { apply, applyShape, buildMCPPipeline, createHttpPreviewClient, createHttpScreenshotClient, createLocalScreenshotClient, createMcpOnlyStage, createMcpServer, createMcpStage, createOAuthGuardStage, createOAuthStage, createPreview, createServer, createWidgetProxyStage, handleMcp, mcpExtensions, operation, outlineOfSnapshot, outlineOfTree, previewStage, read, readMcpBody, readShape, resolveLocalBrowser, search, searchShape, serveMcp, tools, unnamedControls };
|
|
@@ -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
|
|
@@ -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
|
|
@@ -457,7 +472,7 @@ that apiContainer; inside a \`list\`, the repeated \`listItem\` and its children
|
|
|
457
472
|
(\`list_<name>.item.<field>\`). The global sources — ${GLOBALS} — have no \`<type>_<name>\` head and are
|
|
458
473
|
bindable anywhere. Binding an element to an element source outside its
|
|
459
474
|
provider's subtree is schema-valid but **broken at runtime** (the source is not in scope), so
|
|
460
|
-
\`
|
|
475
|
+
\`plitzi_apply\` treats it as an **error and rejects the batch** — move the element under the
|
|
461
476
|
provider, or bind a source that is in scope.
|
|
462
477
|
|
|
463
478
|
**mockData is builder-only.** An \`apiContainer\`'s \`mockData\` prop feeds sample data **while editing in the
|
|
@@ -537,7 +552,8 @@ mounted, ignored while someone types in a field; the flow reads the key pressed
|
|
|
537
552
|
nothing outside the element needs to know it is open; pick the state one when something else binds to it.
|
|
538
553
|
- \`utility\` — a built-in utility action (no element/source module); nodeType \`utility\`. Use the **exact** param
|
|
539
554
|
names: \`delayTime\` waits \`time\` milliseconds (**not** \`delay\`), \`twigTemplate\` (\`returnMode\`, \`template\`),
|
|
540
|
-
\`webHook\` (\`url\`, \`method\`, …). See \`utilities\` in
|
|
555
|
+
\`webHook\` (\`url\`, \`method\`, …), \`copyToClipboard\` (\`text\`). See \`utilities\` in
|
|
556
|
+
\`plitzi://interactions/{env}\`.
|
|
541
557
|
|
|
542
558
|
**A param value can be a data binding.** Any interaction param may hold a \`{{ source }}\` token instead of a literal —
|
|
543
559
|
it resolves at runtime exactly like a prop binding, using the same source grammar (\`<type>_<name>.<path>\`, or a
|
|
@@ -901,14 +917,14 @@ the component reads \`{{ props.item.name }}\`.
|
|
|
901
917
|
"children": [ { "ref": "lamp-buy", "type": "button", "props": { "content": "Buy", "slot": "product-card-actions" } } ] } }
|
|
902
918
|
\`\`\`
|
|
903
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
|
|
904
|
-
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.
|
|
905
921
|
|
|
906
922
|
## Pages & folders
|
|
907
923
|
- **A page behind a feature flag**: \`upsertPage { flag: "labs" }\` answers 404 while the flag is off (see **Feature
|
|
908
924
|
flags**); \`flag: null\` removes it.
|
|
909
925
|
- **Always set a \`slug\` when creating a page** (\`upsertPage\`) — it is the page's URL path and good practice for a
|
|
910
926
|
clean, stable route (e.g. \`"pricing"\` or \`"posts/:postId"\`). Omit it and the page ref is used as the slug,
|
|
911
|
-
and \`
|
|
927
|
+
and \`plitzi_apply\` warns so you remember to set a meaningful one.
|
|
912
928
|
- **A page slug is RELATIVE — do NOT start it with \`/\`.** The runtime prepends the leading slash (and any folder
|
|
913
929
|
path) itself, so a leading slash doubles it. Write \`"pricing"\`, not \`"/pricing"\`. (upsertPage strips a leading
|
|
914
930
|
slash for you, but write it relative.)
|
|
@@ -1057,7 +1073,7 @@ tree names nothing is invisible to both, however it looks. So build every page t
|
|
|
1057
1073
|
The linter warns about these (\`control-without-name\`, \`image-without-alt\`, \`click-on-static-element\`,
|
|
1058
1074
|
\`dropdown-without-control\`, \`heading-level-skipped\`, \`label-ignored\`, \`control-in-decorative\`) on every element
|
|
1059
1075
|
you touch; fix them in the same batch. Then look:
|
|
1060
|
-
\`
|
|
1076
|
+
\`plitzi_look\` shows the page as those readers get it, and lists what has no name.
|
|
1061
1077
|
|
|
1062
1078
|
## Semantics
|
|
1063
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.9"
|
|
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 {};
|