@plitzi/cli 0.38.5 → 0.38.7

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 CHANGED
@@ -1,5 +1,221 @@
1
1
  # @plitzi/cli
2
2
 
3
+ ## 0.38.7
4
+
5
+ ### Patch Changes
6
+
7
+ - c7bbc2b: ## A server project's `src/main.ts` is a few lines
8
+
9
+ - **`serveProject` from `@plitzi/sdk-server/project`**: the generated `src/main.ts` hands the space, its actions and
10
+ its options to the server, and the rest comes with the package — the port, the plugins of `src/plugins` and
11
+ `vendor/plugins`, the functions and runtime, `public/`, `src/data/`, the `kv` in `state/kv.json`, `/health`,
12
+ `tmp/dev-server.json` and the reloads while developing. A fix there arrives with `npm update`, not `plitzi upgrade`.
13
+ - **No more `tmp/space.json` while developing**: a saved space is authored again in its own process and handed to the
14
+ server over IPC (`plitzi/author.ts --ipc`, in place of `--out`); the server swaps it in memory and the open pages
15
+ reload, and a refused space keeps the last one that authored. `plitzi doctor` reports a leftover `tmp/space.json`.
16
+ - **`projectAuthoring()` in `@plitzi/sdk-authoring/node`**: what a project's space is checked against — its plugins'
17
+ declarations, its built plugins, its data files — once, for the server and `npm run author` alike. Neither it nor
18
+ `serveProject` takes a root: it is the working directory, where every script runs (`projectAuthoringAt(root)` for a
19
+ tool working on another folder).
20
+ - **`authorProjectSpace` and `projectSpace()` in `@plitzi/sdk-authoring/node`**: the project's space read from
21
+ `src/space/index.ts` — `dist/space/index.js` when the server runs built — once its root and layout are checked, and
22
+ authored. `src/main.ts` is `serveProject({ space: authorProjectSpace, actions, connectors, serverOptions })`, with no
23
+ import of the space; `plitzi/author.ts`, the visual tests and the CLI's checks read it the same way. A module that
24
+ exports no `space` is refused saying what to export (`ProjectSpaceError`).
25
+ - **`.env` lives at the root and Node reads it** as each script starts (`--env-file-if-exists=.env`; `start:dev`
26
+ preloads `@plitzi/sdk-server/env`, since a watched process would restart on every change beside the file). Settings
27
+ read at the top level of `src/config/serverOptions.ts` or the actions are set. Every project gets `.env` and
28
+ `.env.example`; `plitzi upgrade` removes the old `src/env.ts`.
29
+ - **One check of a project's layout** (`@plitzi/sdk-shared/project/layout`): a plugin folder with no entry, a
30
+ JavaScript entry, `src/plugin/` for `src/plugins/`, a `.env` inside `src/`, a space exported by default, a broken
31
+ `vendor/` plugin… The server refuses to boot listing every error with its fix, `npm run author` and the CLI's checks
32
+ refuse with the same words, `plitzi doctor` lists them under `layout` and `--fix` makes the ones with a single fix,
33
+ and `plitzi lint` points at doctor. A plugin folder added broken while developing is reported in the terminal
34
+ instead of failing in esbuild. Plugins may start at `index.tsx`.
35
+ - **`createJsonAdapters` serves documents held in memory**: `offlineData` may be a function returning them, not only a
36
+ path.
37
+ - **One source for a project's layout**, `@plitzi/sdk-shared/project/paths`; `src/config/serverOptions.ts` is typed
38
+ `ProjectServerOptions`. `plitzi upgrade files --write` brings an existing project's `main.ts` and `author.ts` up.
39
+ - **`npm run build` no longer fails on a plugin's stylesheet**: `tsconfig.build.json` includes `plitzi/assets.d.ts`,
40
+ which a space importing a plugin's declaration reaches through its component.
41
+
42
+ ## A write refreshes what shows it
43
+ - **Writes now refresh server-driven providers.** `runServerAction`, `webHook`, `writeRecord` and the
44
+ `invalidateQueries` step reach `runtime: 'server'` api containers by id, by `query` URL, or all of them, just as
45
+ they reach cached browser requests. Before, they reached only the browser's query cache, so a saved write left the
46
+ page showing the old value until a reload. Hidden providers refresh when they are shown.
47
+ - **A refresh because something changed asks around every cache.** `performQuery`, writes and invalidations send
48
+ `Cache-Control: no-cache`; `/_rsc` resolves such a request again instead of serving its cached slice, and keeps the
49
+ new answer. A `refreshSeconds` timer and a "load more" page still go through the caches.
50
+ - **`refreshRsc`'s fourth argument is an options object**, `{ location?, fresh? }`.
51
+
52
+ ## A space's functions read its data
53
+ - **`ctx.data('products.json')`** reads one file of the space's data (a project's `src/data/`), parsed and read-only,
54
+ as of the run's version. Plugins' functions are refused it.
55
+ - **Self-hosted servers read `dataDir` through the same lookup as the platform**, so `/data/<file>` providers and
56
+ `ctx.data` read the same files; `plitzi functions dev` reads `src/data`. `/data/../x.json` is now the provider's
57
+ error state instead of falling through to `publicDir`.
58
+ - **Importing a file outside `functions/` names the boundary and the fix**: read the space's data with
59
+ `ctx.data('<file>')`.
60
+
61
+ ## Signing in on a self-hosted server
62
+ - **`createServer({ auth })` tells the pages it renders where to sign in** (`server.auth`: provider, endpoints and
63
+ the session hint cookie), so a space signs in with no auth settings declared. Settings a space does declare still
64
+ win, and a space that names another provider ignores the server's description. New `pageAuth` server option, for a
65
+ deployment whose `/auth` flows are served by another host.
66
+ - **A page with no auth provider no longer offers `auth.login` / `auth.logout`**, and a sign-in that cannot work says
67
+ why in the console (`[plitzi] auth.login: …`) instead of failing silently. What a visitor keeps there
68
+ (`keepState`, `paintedState`) is the browser's, as on any space without accounts: what was kept as a guest's on such
69
+ a page before is let go once, on the first visit after the upgrade.
70
+ - **Renewal verifies the refresh token itself.** `findByRefreshToken` no longer has to report `refreshExpiresAt`; when
71
+ it does, it overrides the token's own expiry.
72
+ - **New authoring reference `auth.md`**: providers, `authLogin` and its result, `authLogout`, `{{ auth.* }}`,
73
+ `accessLevel`, visitor roles, action `access` and `ctx.user`.
74
+
75
+ ## Flows
76
+ - **Authoring refuses a `when` that asks a step for a key it never publishes** (`condition-field-unpublished`).
77
+ `whenSucceeded` / `whenFailed` after `authLogin` always ran the failure branch: they read a server action's
78
+ `status`. The message names what the step publishes and suggests testing `signedIn.ok` with `when`.
79
+ - **`explain` lists what a step publishes** (`Reads:`) and finds the auth steps by their builders (`authLogin`,
80
+ `authLogout`, `authRefreshDetails`). `authLogin({ username, password })` no longer needs `mode`.
81
+
82
+ ## Elements
83
+ - **Images no longer default to a 140×140 square**: they are 140px wide and as tall as their ratio, so `width` or
84
+ `aspect-ratio` on a class just works. `object-fit` shows in the builder too.
85
+ - **`formControl` with `subType: 'switch'` renders an on/off switch** (`role="switch"`) — it rendered only its label.
86
+ Checkboxes and switches show a `true` default or binding as ticked.
87
+ - **The theme toggle drops the native button look**, and the **`current` style state covers the chosen item of any
88
+ set**: the link to the page shown, a pressed toggle, a selected tab. The exported `CURRENT_PAGE_SELECTOR` is now
89
+ `CURRENT_SELECTOR`.
90
+ - **Element defaults in the style inspector and the MCP catalogue match what the SDK renders**, held by a test. The
91
+ dialog's `bodyContainer` and `headerCloseButton` slots now reach the page; pagination lays out as declared.
92
+ - **Markdown takes a class for each part of the document** through its own slot (`heading`, `paragraph`, `link`,
93
+ `list`, `listItem`, `quote`, `code`, `codeBlock`, `image`, `table`, `anchor`), and `headingLinks: false` drops the
94
+ link each heading offers to itself while keeping its id, so `/page#anchor` links still work. Its description spells
95
+ out the HTML it outputs.
96
+ - **Tabs show every trigger.** The SDK hid every inactive tab item, the header's included, so a set of tabs showed
97
+ one tab and no way to the others; only the body's panels take turns now.
98
+ - **A link that names a query is current only on that query**: of `/?window=6h` and `/?window=24h`, the one shown
99
+ carries `aria-current` — with the path alone, every one of them did. A link with no query is still current on its
100
+ page whatever the query.
101
+
102
+ ## The style language says what `customCss` used to
103
+ - **Pseudo-elements on a class**: `pseudos: { after: { css: { content: '"→"' }, states: { hover: { … } } } }` —
104
+ `before`, `after`, `marker`, `placeholder`, `first-letter`, `first-line`, `selection`, each in the class's states and
105
+ variants. Authoring refuses what draws nothing: a `before`/`after` with no `content`, a `content` without its quotes,
106
+ a property the browser drops on that pseudo-element.
107
+ - **Conditions on a class**: `conditions: { 'motion-reduce': { … }, 'container card (max-width: 30rem)': { … } }` —
108
+ reduced or allowed motion, and container widths, each with its states and pseudo-elements.
109
+ - **The space's `keyframes`**, validated and written at the top of `customCss`; an `animation-name` no keyframes declare
110
+ is warned (`animation-name-unknown`).
111
+ - **New states**: `expanded` (`aria-expanded`), `first`, `last`, `odd`, `even`; the tab panel on show is `current`, and
112
+ the theme toggle's icon of the scheme in use is `current` on its `icon` slot.
113
+ - **`ancestors['>']`** is the parent, whatever it wears — a closed component's part reacting to the element around it.
114
+ - The builder's style inspector, the MCP's definition ops (`pseudos`, `conditions`, and variants with their states) and
115
+ the export to code read and write all of it; an MCP `patchDefinition` no longer drops what it did not name. Rules in
116
+ `customCss` a class can hold now — `.link::after`, one under `@media (prefers-reduced-motion: reduce)`, `.row:first-child`,
117
+ `.row:nth-child(even)`, `.toggle[aria-expanded='true']` — are folded into the class on export and suggested by
118
+ `custom-css-class`.
119
+
120
+ ## Elements take a class for each part
121
+ - **`formControl`**: `field` (the `<input>` itself), `icon` (the show-password button) and `requiredMark` slots; a switch's
122
+ knob reads in dark mode and takes `--plitzi-switch-thumb`, `--plitzi-switch-thumb-checked`, `--plitzi-switch-thumb-shadow`.
123
+ - **`pagination`**: `previous`, `page` (the one shown is its `current` state), `next`, `loadMore`.
124
+ - **`richText`** and **`markdown`**: a slot per part — `heading` and `heading1`…`heading6`, `strong`, `emphasis`,
125
+ `divider`, `tableHead`, `tableRow`, `tableHeaderCell`, `tableCell`, and the code block's frame, header, language and
126
+ copy button. Both heading slots dress one `<h3>`, so `heading-level-overridden` warns when they set the same property
127
+ and the stylesheet's order makes the general one win. A document is drawn by the SDK's own renderer
128
+ (`MarkdownDocument` in `@plitzi/sdk-elements`) — plitzi-ui's `Markdown` keeps GitHub's stylesheet for a library's
129
+ consumers — and reads as a document unstyled: headings, lists, code, tables and quotes get their type from the SDK's
130
+ base layer, at no weight (`:where()`), so a class on a part's slot replaces what it sets property by property. A
131
+ `richText` body reads the same.
132
+ - `custom-css-slot` suggests the slot for a `customCss` rule on a part's SDK class — only where a class on the slot can
133
+ say the rest of the selector (a state, a pseudo-element); `element-slot-unknown` warns of a slot an element does not
134
+ have.
135
+
136
+ ## Links, refreshes and toasts
137
+ - **`current: 'section'` on a link** keeps it current on its page and every page under its path (`aria-current="true"`
138
+ there), styled by the `current` state — no `activeOn` binding for a section.
139
+ - **A refresh asks only about elements the page shown holds**: a provider on the page being left no longer sends a
140
+ `/_rsc` about the new address.
141
+ - **The toasts' parts are `notifications` fields**: `minHeight`, `fontWeight`, `lineHeight`, `iconSize`, `iconGap`,
142
+ `closeColor`, `closeOpacity`, `progressHeight`.
143
+ - **A page asked for with its space's token hydrates its own space.** On a host serving many spaces
144
+ (`?access-token=`), the space document fetched beside the page went without the token, so the host's own space
145
+ answered it and the browser hydrated another space's document over the page — a hydration error, and its tree
146
+ rebuilt. The document's address now carries the token the page was asked for with.
147
+ - **The SDK's stylesheet carries the space's variables from the server's HTML.** It read them from what a provider
148
+ below it publishes while the page renders, which the server had not done yet when it wrote the sheet; it now
149
+ resolves them from the document itself (`useResolvedVariables` of `@plitzi/sdk-shared/dataSource/hooks`), the same
150
+ on both sides.
151
+ - **A realtime message the pub/sub cannot deliver is answered, not fatal.** A publish that Redis refuses — a timeout under
152
+ load — is answered `503` with `reason: 'unavailable'`, by the `POST` and in the WebSocket's `ack` alike; a connect,
153
+ a disconnect or a revoke that fails is logged, on either transport. Each used to reject with nobody waiting, and the server's `unhandledRejection` handler
154
+ shut the whole process down.
155
+
156
+ ## Reporting to Plitzi
157
+ - **`plitzi feedback`** starts a report of what broke, misled or cost time: it writes the page the report is laid out
158
+ in (`tmp/feedback/`) with the installed versions, the project and what `doctor` finds already in it, and tells the
159
+ agent how to fill it — each finding reproduced first, with evidence, impact, workaround and fix, no secrets — and to
160
+ publish it as an artifact whose link the developer sends. `--previous <url>` continues an earlier report.
161
+
162
+ ## Pages that load on every browser
163
+ - **The import map comes before anything that loads a module**, in the page server's HTML, a published site's
164
+ (`index.hbs` on the platform), the SDK's and the builder's. React's `modulepreload` links came first, and a browser
165
+ that had fetched a module already — Chrome before 133 — ignored the map: every bare `import "react"` failed
166
+ ("Failed to resolve module specifier") and the page never hydrated.
167
+
168
+ ## The dev tools
169
+ - **A page loads the React its dev tools need.** The development build only while the visitor has the dev tools on
170
+ (shift+F12, within what the deployment allows); turned off, the next load is a production page, React included. It
171
+ followed the authorization alone, so a space that allowed debugging always shipped development React.
172
+
173
+ ## check and lint
174
+ - **`plitzi check`, `push`, `lint` and `fix` hold the space to what `npm run author` and the server do**: its data
175
+ files too, so `push` no longer sends a space whose browser provider reads `src/data/` (`server-data-in-browser`).
176
+ - **`plitzi check` lists each list's rows as drawn and as held in its source** (`feed 4 of 8 rows`,
177
+ `hits not rendered (16 in its source)`). In `--json`, `lists` is now `{ id: { rendered, source } }`.
178
+ - **`plitzi check` no longer reports bindings inside a container the page isn't showing**, nor text "in the colour
179
+ behind it" because of a bar painted over it or a pane that clips it.
180
+ - **`window.__plitzi.sources()` no longer turns a shared array into `'[…]'`**, and a list row no longer replaces its
181
+ list's `items`.
182
+ - **`plitzi lint` says authoring suggestions are quieted with `quiet` on the element**, and reports a
183
+ `plitzi-lint-disable` comment that names one (`disable-names-suggestion`).
184
+ - **`plitzi check` says when a page sent the browser elsewhere** (a page for signed-in visitors, to the sign-in) instead
185
+ of reporting every element missing, and `--as <username>` signs in first through the server's `/auth` routes, the
186
+ password from `PLITZI_CHECK_PASSWORD`.
187
+ - **`plitzi upgrade` never replaces @plitzi packages installed locally** — a tarball, a link, a portal, an override: it
188
+ leaves them and the install, and says which and the command that would install the registry's.
189
+ - **`plitzi explain` covers every code**: authoring's, `plitzi lint`'s and the project layout's.
190
+ - **Authoring reads the global sources' fields**: `auth.authenticated` in a condition is refused with "did you mean
191
+ `isAuthenticated`?" (`global-field-unknown`), and `invalidateElements` must name providers that exist
192
+ (`element-ids-target`). A template's reads of `computed`, `flags` and the global sources come off the parsed
193
+ template: a string inside it (`'https://auth.acme.com'`) is no longer read as `auth.acme`.
194
+ - **`custom-css-notifications` no longer reads the rules `notifications` itself writes** as toasts dressed by hand.
195
+ - **A refused space or layout is a report, not a stack**: the server's entry point imports the space once the layout is
196
+ checked, and `npm start` and `npm run author` print every problem and exit with 1.
197
+ - **New authoring suggestion `class-overrides-class`**: one class's shorthand (`padding`) silently erases a longhand
198
+ (`padding-top`) another class on the same element writes out.
199
+
200
+ - Updated dependencies [c7bbc2b]
201
+ - @plitzi/sdk-authoring@0.38.7
202
+
203
+ ## 0.38.6
204
+
205
+ ### Patch Changes
206
+
207
+ - 3bce653: ## Fixes
208
+
209
+ - **The dev tools draw their icons again.** The panel lives in a shadow root of its own, which the page's stylesheets
210
+ never reach, and Font Awesome moved to a sheet of its own in 0.38.5 (`plitzi-sdk-icons.css`): the badge and every tab
211
+ lost their icons. The panel now links that sheet inside its root, beside its own. Where it is served is the SDK's
212
+ new `sdkIconsStylePath` — the page server sends `/sdk-assets/plitzi-sdk-icons.css`, the same sheet the document
213
+ links — which the `iframe` and `shadow` render modes read too: they had `/plitzi-sdk-icons.css` hard-coded, a path a
214
+ page server does not serve.
215
+
216
+ - Updated dependencies [3bce653]
217
+ - @plitzi/sdk-authoring@0.38.6
218
+
3
219
  ## 0.38.5
4
220
 
5
221
  ### Patch Changes
package/README.md CHANGED
@@ -109,8 +109,9 @@ when an install fails the CLI says which setting names it.
109
109
  from, so what you start with and what signing up gives you cannot come apart — and unlike a document, you can read
110
110
  and change it.
111
111
  - **A live loop.** In client mode a save is a hot module replacement: the space module is swapped and the tree
112
- remounted, so the page updates without reloading. In server mode `start:dev` re-authors a saved space and the open
113
- page loads again, swaps a saved plugin where it is drawn, and restarts only for the server's own code.
112
+ remounted, so the page updates without reloading. In server mode `start:dev` authors a saved space again — in a
113
+ process of its own, handing the documents to the server, which serves them from memory — and the open page loads
114
+ again; it swaps a saved plugin where it is drawn, and restarts only for the server's own code.
114
115
  - **A plugin of the project's own.** `src/plugins/StatCard` is a React component the space renders through a
115
116
  `custom` element — the one thing about Plitzi a page of built-in elements cannot show. Every folder of
116
117
  `src/plugins` is registered by itself, under its name in camelCase, so `plitzi add plugin` is all a new one takes. Its props ARE the
@@ -141,20 +142,28 @@ when an install fails the CLI says which setting names it.
141
142
  | `src/data/` | Server mode: the project's own data — JSON its server reads for a provider (`query: '/data/<file>'`, `runtime: 'server'`) and never serves (`dataDir`). What a provider reads is in the page it renders: data a page must not carry is a server action's to read | yes |
142
143
  | `src/functions/` | Server mode: the project's own server code — tasks and `/fn/` routes (`defineFunctions`), built at boot | yes |
143
144
  | `vendor/plugins/` | The plugins the project runs as they were built, with no source (a project made from a space gets them), each folder with its `plugin-manifest.json`. The server runs them, and `author`, `check`, `fix` and `push` know every element type each provides | yes |
144
- | `tmp/` | What the project writes for itself while it runs: the plugins the server builds (`tmp/.sdk-plugins`), resized pictures, the port it took (`tmp/dev-server.json`), the space as last authored, screenshots and test output. Rebuilt when missing | no |
145
+ | `tmp/` | What the project writes for itself while it runs: the plugins the server builds (`tmp/.sdk-plugins`), resized pictures, the port it took (`tmp/dev-server.json`), screenshots and test output. Rebuilt when missing | no |
145
146
  | `state/` | Server mode: what the server keeps for the space — its `kv` in `state/kv.json` (`createFileKv`): saved layouts, counters, cached answers. The deployment's state: kept across restarts, never rebuilt. `action.kv` in `src/config/serverOptions.ts` keeps it elsewhere (`createSqliteKv` for several processes, or a database) | no |
146
147
  | `.plitzi/` | What the CLI records about the project: the space it came from (`space.json`), the functions' working copy, the files `create` wrote — what `pull`, `push` and `upgrade` stand on | yes |
147
148
 
148
149
  **`plitzi/` is the CLI's; `src/` is yours — but `src/main.ts`.** `plitzi/` holds `author.ts`, the types plugins import
149
150
  (`assets.d.ts`, server mode) or the page's base styles (`preflight.css`, client mode), and a `README.md` saying what
150
151
  each folder of `src/` is. `src/main.ts`, the entry point, is the CLI's too, kept in `src/` where an entry point is
151
- looked for; `upgrade` keeps all of them current, and the build compiles `src/` into `dist/main.js`. A plugin is declared by its folder: the server, `author` and `check` find every
152
+ looked for; `upgrade` keeps all of them current, and the build compiles `src/` into `dist/main.js`. In server mode it is a few lines: it authors the space
153
+ (`authorProjectSpace` from `@plitzi/sdk-authoring/node`, which reads `src/space/` as `author` reads it) and hands
154
+ it, the actions and the options to `serveProject` from `@plitzi/sdk-server/project`, which wires the rest from where the
155
+ project keeps it — so a fix to the server arrives with `npm update`, not as a file to upgrade. Neither is told where the
156
+ project is: it is the folder every script runs in, and both refuse to start anywhere else, naming what is missing
157
+ (`package.json`, `src/`) — run them from the project's root. Nor do they start on a part where nothing reads it — a
158
+ plugin folder with no `index.ts`, code in `src/plugin/`, `.env` in `src/` — naming every one at once (`doctor` says each
159
+ with its fix). A plugin is declared by its folder: the server, `author` and `check` find every
152
160
  `src/plugins/<Name>/declaration.ts` (`pluginDeclarations` from `@plitzi/sdk-authoring/node`). What the server does
153
- besides serving the space is the project's own, in files it reads: `src/config/serverOptions.ts` (handed to `createServer` —
161
+ besides serving the space is the project's own, in files it reads: `src/config/serverOptions.ts` (handed to `serveProject` —
154
162
  `images`, `action.limits`, `action.kv`, `rsc`) and, with `--source local`, `src/actions/index.ts` (the space's server
155
163
  actions, one `defineAction` each, a file each as they grow).
156
- What `main.ts` wires itself — where the space comes from, the plugins, `public/`, `src/data/`, `src/functions/`, the
157
- actions' lookups — is left out of `serverOptions`' type, and comes after it, so an option there can never unwire it.
164
+ What `serveProject` wires itself — where the space comes from, the plugins, `public/`, `src/data/`, `src/functions/`,
165
+ the actions' lookups — is left out of `serverOptions`' type (`ProjectServerOptions`), and comes after it, so an option
166
+ there can never unwire it.
158
167
  `src/functions/` holds the project's own server code; `start:dev` restarts on a change to any of them. A plugin is not
159
168
  server code to restart for: a save to one is built again and swapped in the open pages where it is drawn — the rest of
160
169
  the page, its state included, stays — its server half (`src/plugins/<Name>/functions/`) is loaded again in place, and a
@@ -176,6 +185,7 @@ with `--source local`.
176
185
  plitzi check / --width 1440,390 # is the page whole? in text, per width; --json for a tool
177
186
  plitzi check /products --state --element catalog-count # and what it holds: state, sources, one element
178
187
  plitzi check / --ssr # and what the server's HTML lacks that the hydrated page has
188
+ PLITZI_CHECK_PASSWORD=… plitzi check /studio --as maya # a page for signed-in visitors, signed in through /auth first
179
189
  plitzi shot /about --width 390 --scheme dark
180
190
  plitzi shot / --frames 4 --every 500 # what moves: a marquee, an autoplay
181
191
  plitzi shot / --compare https://example.com --width 1440 # beside another site: what differs, and how
@@ -186,8 +196,9 @@ another project. They wait for the page to settle — loaded, then half a second
186
196
  stream that stays open, so a page with a realtime `channel` is checked like any other (`openPage` of
187
197
  `@plitzi/sdk-authoring`, which the generated `npm run visual` uses too). `check` reports every element the space owes the page that is missing or hidden (with why), broken
188
198
  images, sideways scroll, text in the colour behind it, console errors, refused requests and failed flows — and the
189
- page's data: a binding that reads a path its provider's answer lacks (with the keys it has), a provider that failed,
190
- the rows each list rendered. A page's state in a few hundred tokens, where a screenshot costs thousands.
199
+ page's data: a binding that reads a path its provider's answer lacks (with the keys it has) — none inside an element
200
+ the page is not showing, which is not mounted — a provider that failed, and each list's rows, drawn and in its source
201
+ (`feed 4 of 8 rows`, `hits not rendered (16 in its source)`; `--json`: `lists: { id: { rendered, source } }`). A page's state in a few hundred tokens, where a screenshot costs thousands.
191
202
 
192
203
  `--scheme` is the space's own theme, set as a visitor's toggle sets it (the `theme` cookie); left out, the space's
193
204
  default, and `shot` names the file by the theme it was painted in. The dev tools' badge is hidden from both. A
@@ -236,13 +247,16 @@ has it as `npm run lint:space`.
236
247
  | `special-case-in-map` | a `map` that singles out a row by its `id`, `key`, `slug`, `name`, `title` or `label`: the difference belongs in the row's data |
237
248
  | `colour-not-token` | a hex, `rgb()`/`hsl()`/`oklch()`… or a named colour where a colour is all a property takes — outside the declared tokens (`variables`, `light`/`dark`), anchors, masks, markup and URLs |
238
249
  | `positional-id` | an id minted for an element nobody named — `container-45`, `heading-a7k2` |
250
+ | `disable-names-suggestion` | a `plitzi-lint-disable` comment naming a suggestion of authoring's, which a comment does not silence: `quiet: ['<code>']` on its element |
239
251
  | `space-does-not-author` | error: the space does not author, so authoring's suggestions could not be read — `npm run author` says why |
252
+ | `project-layout` | error: the project is laid out where its server and `npm run author` refuse to start — one line, each error `doctor`'s to say; authoring's suggestions are read once they are fixed |
240
253
  | `source-unreadable` | error: the source could not be read (no TypeScript installed, a rule that could not finish) |
241
254
 
242
255
  Beside them, every suggestion authoring makes about the space it authors to (`authorSpace(…).suggestions`) — whatever
243
256
  its code, the day authoring adds it — as a warning at the line that wrote its element; `plitzi explain <code>` says what
244
- each means. They are quieted on the element (`quiet: ['repeated-shape']`), where the builder and the MCP read it too.
245
- A practice the source departs from on purpose is said where it is, eslint's way:
257
+ each means. They are quieted on the element (`quiet: ['repeated-shape']`), where the builder and the MCP read it too —
258
+ the report says so under them. A practice the source departs from on purpose is said where it is, eslint's way, for
259
+ lint's own codes:
246
260
  `// plitzi-lint-disable-next-line colour-not-token -- the partner's own red`, `-line` for its own line, and
247
261
  `// plitzi-lint-disable <codes>` for the whole file.
248
262
 
@@ -283,7 +297,7 @@ did not write again.
283
297
 
284
298
  ```bash
285
299
  plitzi explain container # an element: its attributes and their values, what it fires and answers, its slots
286
- plitzi explain navigate # a step: its params and the function that writes it
300
+ plitzi explain navigate # a step: its params, what it publishes, and the function that writes it
287
301
  plitzi explain onScroll # a trigger: what it hands its flow, and what fires it
288
302
  plitzi explain class-and-css # a problem's code: what was wrong, what to write instead
289
303
  plitzi explain content-attribute # a suggestion's code: what is written the long way, and the short one
@@ -315,25 +329,43 @@ commands (`plitzi upgrade --write`, an install, `doctor --fix`) that clear most
315
329
 
316
330
  **`--fix`** makes only what is simple and safe, then examines the project again: a layout an older CLI left, moved (every
317
331
  import, `new URL(…, import.meta.url)` and script naming a moved file follows, and what the CLI recorded of its files
318
- follows them); an older CLI's dead files and caches deleted; `.gitignore` lines added or taken out; `"type": "module"`
319
- and `engines`; a folder `start:dev` watches; a `PLITZI_SIGNING_SECRET` where there is none (or one too short). What
320
- replaces a file of the project's, installs, or touches git is recommended, never done — `upgrade --write` and the install
321
- are a step of their own.
332
+ follows them); a part out of place with one reading of where it goes, moved the same way — `src/plugin/` into
333
+ `src/plugins/`, an `index.js` to `index.ts`, `src/.env` to the root when it has none, a name that differs only in case
334
+ renamed through one of its own; `.env.example` written from `.env` with no value kept, `.env` copied from
335
+ `.env.example`; an older CLI's dead files and caches deleted; `.gitignore` lines added or taken out; `"type": "module"`
336
+ and `engines`; a folder `start:dev` watches; a `PLITZI_SIGNING_SECRET` where there is none (or one too short). A move
337
+ that would write over a file is said and left. What replaces a file of the project's, installs, or touches git is
338
+ recommended, never done — `upgrade --write` and the install are a step of their own.
322
339
 
323
340
  **A project an older CLI made** is the usual patient, and its own installed CLI may predate `doctor`: run the latest one
324
341
  from it — `npx @plitzi/cli@latest doctor --fix`, then what it recommends. While its layout is an older one (the space in
325
342
  `src/space.ts`, `author` in `src/`, `functions/` at the root), nothing else is checked — read against it, every other
326
343
  area would only say what the move fixes — and `upgrade` writes no file until it is moved.
327
344
 
345
+ **Where each part lives** is one check (`checkProjectLayout`, `@plitzi/sdk-shared/project/layout`) said by three: the
346
+ server refuses to start on its errors, listing every one (and prints its warnings while developing — a plugin folder
347
+ added broken while `start:dev` runs is said there, and the server goes on), `npm run author` and the CLI's checks
348
+ (`check`, `push`, `fix`) refuse to author, and `doctor` says each with its fix under `layout`. `lint` says in one line
349
+ that there are some. Its codes, each with what it means, are `PROJECT_LAYOUT_CODES`: errors — a plugin folder with no
350
+ `index.ts` (or `index.tsx`), or both; a JavaScript entry; a folder name that is no element type (`story-editor` →
351
+ `StoryEditor`), two folders of one type, a plugin also built in `vendor/plugins/`; a plugin's `functions/`,
352
+ `src/functions/` or `src/runtime/` with code and no `index.ts`; a local space with no `src/space/index.ts`, or one
353
+ exported by default; a built plugin whose manifest is missing, unreadable, or names no script there; `.env` inside
354
+ `src/`; code in a folder named like one the server reads (`src/plugin/`, `plugins/` at the root). Warnings — the same
355
+ folder with nothing it would read (`src/Data/`, `src/runtimes/`, `src/public/`); a plugin with no `declaration.ts`; a
356
+ file loose in `src/plugins/`; a file of `src/data/` that is not JSON; no `.env` or no `.env.example`; JSON in
357
+ `public/data/` of a project with a server, and a file in `public/` named like a secret. A near name is asked about —
358
+ did you mean `index.ts`, `src/plugins/`? — and one that differs only in case says it works on macOS and not on Linux.
359
+
328
360
  | Area | What is held |
329
361
  |---|---|
330
- | `layout` | where an older CLI kept what this one reads elsewhere (`src/space.ts`, `src/site/`, `src/actions.ts`, `src/author.ts`, `functions/`) and what it left behind (`src/plugins/declarations.ts`, `.sdk-plugins/`, `.plitzi/dev-server.json`) |
331
- | `packages` | `"type": "module"`, the Node version; every package the project and its scripts need, declared and installed at a version its range allows; the SDK's packages at one version, no older than the CLI; one copy of the SDK and of React (none installed inside another); the scripts — gone, behind the CLI, or the project's own — the file each Node script starts and every folder `start:dev` watches; one lockfile |
332
- | `machinery` | the CLI's files (`MACHINERY`), as `upgrade` sees them: gone, behind, or the project's own (said, never failed); the scaffold record |
362
+ | `layout` | where an older CLI kept what this one reads elsewhere (`src/space.ts`, `src/site/`, `src/actions.ts`, `src/author.ts`, `functions/`) and what it left behind (`src/plugins/declarations.ts`, `.sdk-plugins/`, `.plitzi/dev-server.json`, the `tmp/space.json` an older `src/main.ts` re-read the space from); every part where the server, `npm run author` and the CLI's checks read it (`PROJECT_LAYOUT_CODES`, above) |
363
+ | `packages` | `"type": "module"`, the Node version; every package the project and its scripts need, declared and installed at a version its range allows; the SDK's packages at one version, no older than the CLI; one copy of the SDK and of React (none installed inside another); the scripts — gone, behind the CLI, or the project's own — the file each Node script starts, every folder `start:dev` watches, and a server's scripts reading `.env` (`--env-file-if-exists`; a watched one by the preload, never Node's flag); one lockfile |
364
+ | `machinery` | the CLI's files (`MACHINERY`), as `upgrade` sees them: gone, behind, or the project's own (said, never failed); one it no longer writes, left over (`src/env.ts`); the scaffold record |
333
365
  | `config` | `tsconfig.json` reads `src/` and `plitzi/` and sets what Node's type stripping needs; `tsconfig.build.json` writes the file `start:prod` runs; `.gitignore` keeps `.env` out (and `node_modules`, `tmp`, `dist`, `state`) and `.plitzi/` in; `.env` not in git; the signing secret, as long as the project's own server wants it; a cloud project's key |
334
366
  | `sources` | what Node runs as written — `src/main.ts`, `src/config/`, `src/actions/`, `src/space/`, `src/runtime/`, `plitzi/author.ts`, the plugins' declarations, and all they import: every relative import a file that is there, with its extension; JSON imported `with { type: 'json' }`; no JSX; every package declared (a devDependency, in what production runs, is said); what the server loads by name exported (`space`, `actions`, the runtime's default) |
335
- | `plugins` | each folder of `src/plugins/`: an `index.ts` that builds and exports its component, its packages declared; a `declaration.ts` whose `type` is the folder's (`StatCard` → `statCard`); one folder a type; none shadowed by a built copy in `vendor/plugins/` |
336
- | `data` | every file of `src/data/` and `public/data/` JSON — what the server answers with and `push` sends |
367
+ | `plugins` | each folder of `src/plugins/` the server can build: its entry builds and exports its component, its packages declared; its `declaration.ts` loads and its `type` is the folder's (`StatCard` → `statCard`) |
368
+ | `data` | every JSON file of `src/data/` and `public/data/` parses — what the server answers with and `push` sends |
337
369
  | `functions` | `src/functions/` built by the project's own `@plitzi/sdk-server` (`buildFunctions`), as every runner builds them |
338
370
  | `records` | `.plitzi/space.json`, `scaffold.json` and `functions.json` readable, and of the same space |
339
371
  | `skills` | `.claude/skills/plitzi-*` as the packages installed write them |
@@ -342,6 +374,24 @@ It loads the plugins' declarations and the project's own `@plitzi/sdk-server` to
342
374
  never starts the server or the runtime. A check that cannot finish is said as an error
343
375
  of its area, never a crash.
344
376
 
377
+ ## `feedback`
378
+
379
+ ```bash
380
+ npx @plitzi/cli feedback # a report to Plitzi, started
381
+ npx @plitzi/cli feedback --previous https://claude.ai/artifact/… # continuing an earlier one
382
+ ```
383
+
384
+ A report of what broke, misled or cost time, for a developer to send to Plitzi as a link. The CLI reads what a report
385
+ must not get wrong — every `@plitzi` package installed and its version, Node and the machine, the project's mode and
386
+ source, what `plitzi doctor` finds — and writes the page the report is laid out in, `tmp/feedback/report-<date>.html`:
387
+ a tally by severity, what was built, what changed since the earlier reports, where to start, the findings filtered by
388
+ severity and area and each copied as an issue, and what worked — in light and dark, on a phone. It prints how to fill
389
+ it for the agent the developer works with: one `REPORT` object, each finding reproduced on the installed versions
390
+ before it is written, with what happens, the evidence, the impact, the workaround and a fix; no secret, token or
391
+ customer's data. The agent then publishes it as a private artifact and gives the developer its URL. `--previous` hands
392
+ it the earlier reports: their numbering goes on, and what changed of each finding is said. `--json`: `{ file, facts,
393
+ brief }`.
394
+
345
395
  ## `upgrade`
346
396
 
347
397
  ```bash
@@ -358,10 +408,12 @@ one the project made its own is a diff, left unless `--take` names it (`all` for
358
408
  `.prettierignore` names them, so the project's `format` never turns one into a file `upgrade` believes was changed. A file of the project's own
359
409
  that the machinery reads (`src/config/serverOptions.ts`, `src/actions/index.ts`) is written when the project has none and the
360
410
  `main.ts` reading it is the CLI's, and never replaced. A script is the same: one the CLI wrote and nobody changed takes
361
- today's command, one the project changed is left and said (`.plitzi/scaffold.json` records both, and the package
411
+ today's command, one the project changed is left and said. A file the CLI no longer writes — `src/env.ts`, now that
412
+ Node reads `.env` — is removed the same way once the `main.ts` that read it is the CLI's; one the project changed is
413
+ said and left, unless `--take` names it (`.plitzi/scaffold.json` records the files and the scripts, and the package
362
414
  manager the files were written for — what a project not installed yet has no lockfile to say). In a project made from
363
415
  a space, a file the space gave over one of the CLI's would be the space's, and `upgrade` would leave it to `plitzi pull` —
364
- none does: `src/main.ts` runs whatever the space brought, from where it lands. `update` is the same
416
+ none does: `serveProject` runs whatever the space brought, from where it lands. `update` is the same
365
417
  command, and `plitzi skills update` is `upgrade skills --write`. `npm run author` says when the authoring skill is
366
418
  older than the `@plitzi/sdk-authoring` installed.
367
419
 
@@ -428,8 +480,9 @@ said before anything is sent, with what to do: a provider reading a file `src/da
428
480
  Adds elements of your own to the project you are in — one, several at once (`add plugin seat-picker legend`), or one at
429
481
  a time as the need comes. Each is a folder, written the way Plitzi's own elements are (`@plitzi/sdk-elements`): the
430
482
  component, its `declaration.ts` (its `type`, the events it fires, the actions it answers to, and the element the builder
431
- adds), its `Settings.tsx` panel for the builder, and the `index.ts` that puts them together. It asks what to call each,
432
- what the builder shows, and what it is for, and checks every folder is free before writing any.
483
+ adds), its `Settings.tsx` panel for the builder, and the `index.ts` that puts them together — what the folder is built
484
+ from: `index.ts`, or `index.tsx` for one that writes its JSX there, never both. It asks what to call each, what the
485
+ builder shows, and what it is for, and checks every folder is free before writing any.
433
486
 
434
487
  - **In a project `plitzi create` wrote**, it goes in `src/plugins`, where the project already looks: nothing to
435
488
  register, and a running `start:dev` picks it up without a restart. Host it with `custom({ renderType: 'seatPicker' })` in `src/space/`
@@ -608,7 +661,14 @@ throws it away) and `push` refuses when the space moved on since. A problem come
608
661
  names them differently on purpose: a server gets the secret self-hosting key, a browser gets the public render key,
609
662
  whose protection is the origin it is presenting from.
610
663
 
611
- Every server project's `src/main.ts` reads `.env` itself (`process.loadEnvFile`), so `npm start` needs nothing else.
664
+ Every project has a `.env`, never committed, and a `.env.example`, committed: the same settings with no secret in them,
665
+ for a clone to copy and fill in. A server project's `.env` is read as each script starts —
666
+ `node --env-file-if-exists=.env` in `start`, `start:prod` and `author`, and in `start:dev`, which Node watches,
667
+ `node --import @plitzi/sdk-server/env` (Node's flag there has its watcher restart on every write in the project) —
668
+ before any of its modules is evaluated, so `src/config/serverOptions.ts` and the actions find their settings in
669
+ `process.env` as they load. A change to it is read on the next start, and a deployment that sets its environment needs
670
+ no file. A browser
671
+ project's is Vite's: only `VITE_*` reaches the page, and ships in it.
612
672
  `create` gives each one a signing key there, made for it: `PLITZI_SIGNING_SECRET`, what `ctx.sign` and `ctx.verify`
613
673
  sign with — at least 32 characters (`doctor --fix` writes one where it is missing). `PORT` is left commented out: 8080,
614
674
  or the next free port while developing.