@plitzi/cli 0.38.6 → 0.38.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,10 +4,10 @@ The command line for Plitzi.
4
4
 
5
5
  ```bash
6
6
  npx @plitzi/cli create my-site # a project that renders a space
7
- npx @plitzi/cli add plugin seat-picker legend # elements of your own, in the project you are in
7
+ npx @plitzi/cli plugin add seat-picker legend # elements of your own, in the project you are in
8
8
  npx @plitzi/cli create seat-picker --plugin # a plugin package any space can load
9
- npx @plitzi/cli pack plugin # a plugin built, and zipped the way the builder takes it
10
- npx @plitzi/cli upload plugin # that zip, on the space you work in, and installed there
9
+ npx @plitzi/cli plugin pack # a plugin built, and zipped the way the builder takes it
10
+ npx @plitzi/cli plugin upload # that zip, on the space you work in, and installed there
11
11
  ```
12
12
 
13
13
  ## What every command does the same way
@@ -21,10 +21,10 @@ npx @plitzi/cli upload plugin # that zip, on the space you work
21
21
  there, `-e, --environment` for which version of the space, `--width` for the widths a page is looked at (one, or
22
22
  several separated by commas), `--api` for the platform, `--json` for a tool or an agent.
23
23
  - **`--dry-run` says what it would do, and does none of it** — on every command that writes or sends: `create`,
24
- `add plugin`, `add runtime`, `pull`, `push`, `pack plugin`, `source`, `import`, `upload plugin`, `functions pull`/
25
- `push`, `runtime push`/`start`/`stop`/`size`/`vars`, `skills update`, `doctor --fix`. Each file it would write (`+` new, `~` replaced, `-`
24
+ `plugin add`, `runtime add`, `space pull`, `space push`, `plugin pack`, `source pack`, `page import`, `plugin upload`, `functions pull`/
25
+ `functions push`, `runtime push`/`start`/`stop`/`size`/`vars`, `skills update`, `doctor --fix`. Each file it would write (`+` new, `~` replaced, `-`
26
26
  removed), what it would install or run, what it would send and where. It still reads what it needs to say so — the
27
- project, the files it would send, the space it would pull, signing in for that. `upgrade` and `fix` only show until
27
+ project, the files it would send, the space it would pull, signing in for that. `upgrade` and `space fix` only show until
28
28
  `--write`.
29
29
 
30
30
  ## `create`
@@ -65,8 +65,8 @@ code (JSON, with the reason said, where one would not read back exactly), its fu
65
65
  runtime, and its files downloaded into `public/` with every CDN address rewritten — served by the project with nothing
66
66
  of Plitzi's. `.env` gets a signing key made for it and the names of the variables and credentials the space had, never
67
67
  their values. It signs in as you and needs a space you may change; the end of `create` says what came across
68
- differently. What the project was given is recorded in `.plitzi/space.json` — commit it — for [`pull`](#pull) and
69
- [`push`](#push). See `docs/en/projects-from-spaces.md`.
68
+ differently. What the project was given is recorded in `.plitzi/space.json` — commit it — for [`space pull`](#space-pull) and
69
+ [`space push`](#space-push). See `docs/en/projects-from-spaces.md`.
70
70
 
71
71
  ## The package manager
72
72
 
@@ -82,7 +82,7 @@ bundler — so the linker is pinned to the layout npm and pnpm already give it.
82
82
 
83
83
  ## Node runs the TypeScript
84
84
 
85
- Every script that runs TypeScript — `start`, `author`, `shot` — is plain `node`: Node 22.18+ strips the types
85
+ Every script that runs TypeScript — `start`, `author`, `page shot` — is plain `node`: Node 22.18+ strips the types
86
86
  itself, so nothing transpiles beside the server. (`tsx` did, and its loader thread cost a page server more memory
87
87
  than the server: ~270 MB to start where the same server starts in ~90.) The project's `tsconfig` holds it to what
88
88
  that needs — relative imports name their `.ts` file (`allowImportingTsExtensions`), type-only imports say so
@@ -109,11 +109,12 @@ 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
- `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
117
+ `src/plugins` is registered by itself, under its name in camelCase, so `plitzi plugin add` is all a new one takes. Its props ARE the
117
118
  element's attributes, so a data source pointed at that element later reaches the component with no plumbing in
118
119
  between. Server-rendered in server mode (`action: 'compile'`), part of the bundle in client mode.
119
120
  - **A visual test.** The `visual` script starts the project, opens the page and asserts that every element the space
@@ -140,21 +141,29 @@ when an install fails the CLI says which setting names it.
140
141
  | `public/` | Served to anyone who asks, as it is — pictures, a favicon, and in client mode the data the browser fetches (`public/data/`). **It is on the internet**: never a secret, a key, a private document or data only some visitors may read | yes |
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
- | `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 |
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`, `page check`, `space fix` and `space push` know every element type each provides | yes |
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
- | `.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
+ | `.plitzi/` | What the CLI records about the project: the space it came from (`space.json`), the functions' working copy, the files `create` wrote — what `space pull`, `space 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 `page 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
@@ -170,41 +179,68 @@ in `src/data/products.json` read on the server as a typed source (`public/data/p
170
179
  in client mode), a catalog filtered by category, and a page per product — a file per part under `src/space/`. Both go
171
180
  with `--source local`.
172
181
 
173
- ## `check` and `shot`
182
+ ## `page check` and `page shot`
174
183
 
175
184
  ```bash
176
- plitzi check / --width 1440,390 # is the page whole? in text, per width; --json for a tool
177
- plitzi check /products --state --element catalog-count # and what it holds: state, sources, one element
178
- plitzi check / --ssr # and what the server's HTML lacks that the hydrated page has
179
- plitzi shot /about --width 390 --scheme dark
180
- plitzi shot / --frames 4 --every 500 # what moves: a marquee, an autoplay
181
- plitzi shot / --compare https://example.com --width 1440 # beside another site: what differs, and how
185
+ plitzi page check / --width 1440,390 # is the page whole? in text, per width; --json for a tool
186
+ plitzi page check /products --state --element catalog-count # and what it holds: state, sources, one element
187
+ plitzi page check / --ssr # and what the server's HTML lacks that the hydrated page has
188
+ plitzi page check /enterprise --click site-footer-top # click one element: what it changed, or that nothing did
189
+ plitzi page check / --click news-send --fill news-email=ana@example.com # a form sent as a visitor fills it
190
+ PLITZI_CHECK_PASSWORD=… plitzi page check /studio --as maya # a page for signed-in visitors, signed in through /auth first
191
+ plitzi page shot /about --width 390 --scheme dark
192
+ plitzi page shot / --frames 4 --every 500 # what moves: a marquee, an autoplay
193
+ plitzi page shot / --compare https://example.com --width 1440 # beside another site: what differs, and how
182
194
  ```
183
195
 
184
196
  Both run on the project's own Playwright against its running server (`npm start`), and refuse a port that answers as
185
197
  another project. They wait for the page to settle — loaded, then half a second with nothing asked for — counting no
186
198
  stream that stays open, so a page with a realtime `channel` is checked like any other (`openPage` of
187
- `@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
199
+ `@plitzi/sdk-authoring`, which the generated `npm run visual` uses too). `page check` reports every element the space owes the page that is missing or hidden (with why), broken
188
200
  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.
201
+ page's data: a binding that reads a path its provider's answer lacks (with the keys it has) — none inside an element
202
+ the page is not showing, which is not mounted — a provider that failed, and each list's rows, drawn and in its source
203
+ (`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.
204
+ `--element` adds, at rest, each property more than one of the element's classes sets: the value shown, the class it
205
+ comes from and what the others say — `border-radius: 999px, from ent-cta-pill (button-primary says 12px)` — or that
206
+ they all set it alike, so it stays without any one of them. That is said of the property alone: a class that shares
207
+ one may set others. A class is said to change nothing on the element only when every property it sets stays without
208
+ it, at rest at that width — and then with the other elements it is on: taking it off this element's `class` touches
209
+ none of them, changing the class itself changes them all (`--json`: `styles: { contested, inert, wornBy }`). Which
210
+ class wins is asked of the page (each taken off for a moment), so specificity, order and media are answered without a
211
+ picture.
212
+
213
+ `--click <id>` clicks one element once the page has settled, as a visitor does — brought into view first, which is
214
+ not the click's doing — and says what changed: the flows it ran and how each step ended, where the page went, what
215
+ scrolled, what is shown now and what no longer is, what the page said (a toast, an alert: `said: "Link copied"`), the
216
+ state. A form the browser held back is said with the field and the browser's reason (`the browser held the form back:
217
+ email — Please fill out this field.`), not as a click that ran nothing. A click that changed nothing says so in those
218
+ words, and a flow that ran and succeeded with nothing on the page changed is said as that too: a button whose flow
219
+ does nothing looks like one that works until it is clicked. A click that could not be made, or a flow that failed,
220
+ fails the check (`--json`: `clicked: { element, filled?, changes, failed, problem? }`).
221
+
222
+ `--fill <id>=<value>`, once per field, fills a field before the click as a visitor does — typed in, an option chosen, a
223
+ box ticked with `true` or `false` — so a form's flow is run with what it is for, not only refused empty. The id is the
224
+ field's element, or one that holds that one field (a `formControl`'s wrapper); one that holds several is refused with
225
+ their ids, and a field filled inside another element says whose it is. Without `--click` it is refused: nothing filled
226
+ is sent anywhere.
191
227
 
192
228
  `--scheme` is the space's own theme, set as a visitor's toggle sets it (the `theme` cookie); left out, the space's
193
- default, and `shot` names the file by the theme it was painted in. The dev tools' badge is hidden from both. A
194
- full-page `shot` is the whole page — the pane the SDK scrolls in unrolled, every lazy picture loaded, every arrival
229
+ default, and `page shot` names the file by the theme it was painted in. The dev tools' badge is hidden from both. A
230
+ full-page `page shot` is the whole page — the pane the SDK scrolls in unrolled, every lazy picture loaded, every arrival
195
231
  waiting for the scroll shown as it ends — in `tmp/shots/` unless `--out` says where.
196
232
 
197
- `shot --compare` writes the two pictures side by side and the differences in red. It compares each section where it
233
+ `page shot --compare` writes the two pictures side by side and the differences in red. It compares each section where it
198
234
  is on the other page, so a page 400 px longer is said once, with the section the drift starts at; then it pairs the
199
235
  texts both pages have and says what each does differently there — `h1 "Learn CSS" — font-size 68px → 60px · y +19px`.
200
236
  `--frames` compares pictures taken one after another and names what moved. A project `create` writes has them as
201
237
  `npm run check` and `npm run shot`.
202
238
 
203
- ## `fix`
239
+ ## `space fix`
204
240
 
205
241
  ```bash
206
- plitzi fix # what authoring would fix, as a diff of your own source
207
- plitzi fix --write # written, formatted as the project formats, and checked
242
+ plitzi space fix # what authoring would fix, as a diff of your own source
243
+ plitzi space fix --write # written, formatted as the project formats, and checked
208
244
  ```
209
245
 
210
246
  The fixes are the ones with a single reading (`fixSpace`'s: a key the element never reads, `'true'` where a boolean
@@ -213,12 +249,86 @@ by the line and column the element remembers — and only where the value is wri
213
249
  listed with where it is and why it was left. `--write` authors the space again in a fresh process and keeps the edits
214
250
  only if every fix is gone and no problem was added; a fix that would add one is put back and said.
215
251
 
216
- ## `lint`
252
+ ## `element where` and `element edit`
217
253
 
218
254
  ```bash
219
- plitzi lint # the space's source, eslint's way: each practice to change at its file and line
220
- plitzi lint --json # one object: { scope, notChecked, counts, findings }
221
- plitzi lint --max-warnings 0 # more warnings than that fail (exit 1); --strict: any warning does
255
+ plitzi element where hero-cta # by id: the file, the line and the call that writes it
256
+ plitzi element where navLink # every element wearing the class (`nav-link` or `navLink`)
257
+ plitzi element where "Get started" # every element showing the words
258
+ plitzi element where cta --by text # one reading only: id, class or text
259
+ plitzi element edit hero-cta --set content="Start free" # an attribute written in that call
260
+ plitzi element edit signup --set required=true --remove placeholder
261
+ plitzi element edit site-brand --every --set label="Home" # a helper's call that writes several elements: every one
262
+ ```
263
+
264
+ `element where` answers where the project's code writes an element — `src/space/pages/home.ts:42` and the call itself, or the
265
+ object a page or a layout is declared as — so
266
+ the call is edited instead of the files around it being read. It is asked of the code as it is now: the space is
267
+ authored again and each element's call read back, the way `space fix` finds it, so it follows an element wherever somebody
268
+ moved it, with nothing kept that could fall out of step. Ten matches at most, the call shown for the first three;
269
+ `--json` adds the element's attributes when it was asked for by id. A query is read as an id, then a class, then words —
270
+ the first that matches is answered, and any other that matched too is said with its count and the command for it
271
+ (`--by text`); `--by` reads it one way only. Words are every word an element says: its content, a `label`, `title`,
272
+ `alt` or `placeholder`, a binding's template, the words an instance hands its component. Asked for a class, it says
273
+ where the class is declared too — the `styles()` call — before who wears it; and an element written inside a
274
+ `LIST.map(item => …)` says which list it is repeated for and the file it is in. A space that does not author is said, with the
275
+ lines of `src/` holding the words instead.
276
+
277
+ `element edit` writes attributes in that call — `content` given as the factory's first argument (`text('Hi', { … })`) where it
278
+ is — keeping the kind each one has (a number stays a number; a new one is `true`/`false` or words), formats the file as
279
+ the project formats it, and authors the space again in a fresh process, read against the space before it: unless every
280
+ value asked for is there and nothing else in the space changed, the files go back to what they were, and what would
281
+ have changed besides is named. What it changed is printed, every line of it (`--json`: `effects`). An attribute a
282
+ binding computes is refused — the page shows the binding's value, never one written — and `element where` marks it `Bound`. A value that is a parameter of the helper the call is in (`heading(title, { … })` inside
283
+ `pageHead(id, title)`) is changed where the helper is handed it — `pageHead('about-head', 'About us')` — followed up
284
+ as far as the project's code hands it on, and only when the helper reads it once. A value read off a list the call is
285
+ repeated for (`QUESTIONS.map(item => button({ content: item.question }))`) is changed in the one entry of the list
286
+ that holds it, in whichever file the list is written. A component's instance is edited like any element: its
287
+ attributes are the props it hands the component, and `element where` finds the words it hands too. A page is edited by its
288
+ attributes as `element where` shows them — `seoPageTitle` is written as the page's `seoTitle`. A value read in more than one
289
+ place — a list entry a nav and a menu both draw — changes them all only with `--every`, every one named. A call that writes more than one
290
+ element — a helper called for each — is never changed unasked: `element where` says which elements it writes and the call that
291
+ leads to this one alone, and `element edit` refuses, naming them, unless `--every` says the change is for all of them. Any other
292
+ value written as anything but a literal — a variable, a template, props spread from elsewhere — is left to the author,
293
+ said with where it is. The same `element edit` refused again within a few minutes says so,
294
+ and that running it once more will not change the answer (kept in `tmp/refusals.json`).
295
+
296
+ ## `element remove`, `element move` and `verify`
297
+
298
+ ```bash
299
+ plitzi element remove ent-trust # the element's call taken out, with the styles and imports only it used
300
+ plitzi element move ent-faq --before ent-pricing # put before (or --after) a sibling of the same list of children
301
+ plitzi verify # author, lint:space, typecheck, lint, format and every page: what fails
302
+ plitzi verify --no-pages # the pages left out, said as such
303
+ ```
304
+
305
+ `element remove` and `element move` act on the call that writes the element — or, a section a helper builds and returns
306
+ (`body: [enterpriseFaq()]`), on the helper's call — and are checked as `element edit` is: the space authored again in a fresh
307
+ process and read against the one before. A removal may take the element and what it holds and nothing else; a move
308
+ may change only its parent's order, with the element beside the one it was moved by. Anything more and the file goes
309
+ back, what it would have changed named — and the space read again goes through the same gate `npm run author` does, so
310
+ a change that leaves it refused is never kept. A removal is refused before anything is written when another element's
311
+ flow acts on what it would take away (`site-search openModal → search-modal`), each said with where it is. What it took
312
+ is said once, by the outermost element, with how many it held. A `styles()` declared for the removed element alone goes with it, and its
313
+ factories' imports, named; a helper left with no caller is said, not deleted. A call written once for several
314
+ elements (a `map`), a page or a layout, and a move between two files are left to the author, said.
315
+
316
+ An element's own selector and its bindings are named after its place under its nearest id — not after its position
317
+ among its siblings — so a move renames nothing.
318
+
319
+ `verify` runs each check the project has a script for, as its package manager runs one, then opens every page with
320
+ no parameter in its path at 1440 and 390 px (the server must be up: `npm start`). Only what fails is printed, with the
321
+ last lines it said, and the first failure ends the run — one broken file fails every step after it the same way — the
322
+ rest said as not run until it passes (`--keep-going` runs them anyway); a page the browser was sent away from — one for signed-in visitors — is said as not checked, never
323
+ as passing — said on its own line, without failing the run, since a space with pages for signed-in visitors always
324
+ has some (`plitzi page check <path> --as <username>` opens one). Exit 1 when anything failed.
325
+
326
+ ## `space lint`
327
+
328
+ ```bash
329
+ plitzi space lint # the space's source, eslint's way: each practice to change at its file and line
330
+ plitzi space lint --json # one object: { scope, notChecked, counts, findings }
331
+ plitzi space lint --max-warnings 0 # more warnings than that fail (exit 1); --strict: any warning does
222
332
  ```
223
333
 
224
334
  How the space in `src/space/` is written — what only its source can say, and what grows hard to read and to change as
@@ -236,25 +346,28 @@ has it as `npm run lint:space`.
236
346
  | `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
347
  | `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
348
  | `positional-id` | an id minted for an element nobody named — `container-45`, `heading-a7k2` |
349
+ | `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
350
  | `space-does-not-author` | error: the space does not author, so authoring's suggestions could not be read — `npm run author` says why |
351
+ | `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
352
  | `source-unreadable` | error: the source could not be read (no TypeScript installed, a rule that could not finish) |
241
353
 
242
354
  Beside them, every suggestion authoring makes about the space it authors to (`authorSpace(…).suggestions`) — whatever
243
355
  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:
356
+ each means. They are quieted on the element (`quiet: ['repeated-shape']`), where the builder and the MCP read it too —
357
+ the report says so under them. A practice the source departs from on purpose is said where it is, eslint's way, for
358
+ lint's own codes:
246
359
  `// plitzi-lint-disable-next-line colour-not-token -- the partner's own red`, `-line` for its own line, and
247
360
  `// plitzi-lint-disable <codes>` for the whole file.
248
361
 
249
362
  It is not whether the space authors — what it refuses and warns of is `npm run author`'s — nor a page as it renders
250
- (`check`), nor the project around the space (`doctor`); every report says so (`notChecked`). Exit code 1 while anything
363
+ (`page check`), nor the project around the space (`doctor`); every report says so (`notChecked`). Exit code 1 while anything
251
364
  is an error; with `--strict` a warning too, with `--max-warnings <n>` more than n of them.
252
365
 
253
- ## `import`
366
+ ## `page import`
254
367
 
255
368
  ```bash
256
- plitzi import https://example.com/pricing # into src/imported
257
- plitzi import https://example.com/ --out src/home --width 1440,390
369
+ plitzi page import https://example.com/pricing # into src/imported
370
+ plitzi page import https://example.com/ --out src/home --width 1440,390
258
371
  ```
259
372
 
260
373
  A page you own or may reuse, measured in the project's own Playwright as a place to start writing from — never a copy
@@ -283,17 +396,22 @@ did not write again.
283
396
 
284
397
  ```bash
285
398
  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
399
+ plitzi explain navigate # a step: its params, what it publishes, and the function that writes it
287
400
  plitzi explain onScroll # a trigger: what it hands its flow, and what fires it
288
401
  plitzi explain class-and-css # a problem's code: what was wrong, what to write instead
289
402
  plitzi explain content-attribute # a suggestion's code: what is written the long way, and the short one
290
403
  plitzi explain bindTemplate # a helper: how it is written, what it is for, an example
291
404
  plitzi explain motion # the arrivals, triggers and loops the SDK plays
405
+ plitzi explain pageFamily # any other export of @plitzi/sdk-authoring: its signature and its doc's first line
292
406
  plitzi explain --list steps # every one of a kind: elements, steps, triggers, codes, transformers, helpers
293
407
  ```
294
408
 
295
409
  What a name means when authoring, from the catalogues the checks themselves read — the answer to a question that would
296
- otherwise be a search through the SDK's types. `--json` answers in one object; over MCP it is `plitzi://explain/{name}`.
410
+ otherwise be a search through the SDK's types. A name no catalogue holds — `pageFamily`, `styles`, `SpaceSpec` — is any
411
+ export of `@plitzi/sdk-authoring`, answered from the `.d.ts` the project installed, so it is the version the project
412
+ runs. An element of the project's own — `src/plugins/<Name>/` — is explained by its type the same way: what it takes
413
+ (each attribute at its default), fires and answers, and the `custom({ … renderType })` that places it, which `plugin
414
+ add` prints too. `--json` answers in one object; over MCP it is `plitzi://explain/{name}`.
297
415
 
298
416
  ## `doctor`
299
417
 
@@ -308,32 +426,50 @@ plitzi doctor --strict # warnings fail too — for a CI that keeps the p
308
426
  Whether the project is whole as the CLI sets it up, read from what it is now rather than from what the CLI once wrote:
309
427
  a developer may change any file, and the checks are what each part must be for the project to install, start, build and
310
428
  push. It is the CLI's check of the project, not of the space: what the space authors to and warns of is `npm run
311
- author`'s, how it is written `lint`'s, and how a page renders `check`'s. Exit code 1 while anything is an error (with `--strict`, a warning).
429
+ author`'s, how it is written `space lint`'s, and how a page renders `page check`'s. Exit code 1 while anything is an error (with `--strict`, a warning).
312
430
 
313
431
  Each finding has an area, a stable `code`, the file and its `fix`; the report ends with **what to run next** — the few
314
432
  commands (`plitzi upgrade --write`, an install, `doctor --fix`) that clear most of the list, by how many each fixes.
315
433
 
316
434
  **`--fix`** makes only what is simple and safe, then examines the project again: a layout an older CLI left, moved (every
317
435
  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.
436
+ follows them); a part out of place with one reading of where it goes, moved the same way — `src/plugin/` into
437
+ `src/plugins/`, an `index.js` to `index.ts`, `src/.env` to the root when it has none, a name that differs only in case
438
+ renamed through one of its own; `.env.example` written from `.env` with no value kept, `.env` copied from
439
+ `.env.example`; an older CLI's dead files and caches deleted; `.gitignore` lines added or taken out; `"type": "module"`
440
+ and `engines`; a folder `start:dev` watches; a `PLITZI_SIGNING_SECRET` where there is none (or one too short). A move
441
+ that would write over a file is said and left. What replaces a file of the project's, installs, or touches git is
442
+ recommended, never done — `upgrade --write` and the install are a step of their own.
322
443
 
323
444
  **A project an older CLI made** is the usual patient, and its own installed CLI may predate `doctor`: run the latest one
324
445
  from it — `npx @plitzi/cli@latest doctor --fix`, then what it recommends. While its layout is an older one (the space in
325
446
  `src/space.ts`, `author` in `src/`, `functions/` at the root), nothing else is checked — read against it, every other
326
447
  area would only say what the move fixes — and `upgrade` writes no file until it is moved.
327
448
 
449
+ **Where each part lives** is one check (`checkProjectLayout`, `@plitzi/sdk-shared/project/layout`) said by three: the
450
+ server refuses to start on its errors, listing every one (and prints its warnings while developing — a plugin folder
451
+ added broken while `start:dev` runs is said there, and the server goes on), `npm run author` and the CLI's checks
452
+ (`page check`, `space push`, `space fix`) refuse to author, and `doctor` says each with its fix under `layout`. `space lint` says in one line
453
+ that there are some. Its codes, each with what it means, are `PROJECT_LAYOUT_CODES`: errors — a plugin folder with no
454
+ `index.ts` (or `index.tsx`), or both; a JavaScript entry; a folder name that is no element type (`story-editor` →
455
+ `StoryEditor`), two folders of one type, a plugin also built in `vendor/plugins/`; a plugin's `functions/`,
456
+ `src/functions/` or `src/runtime/` with code and no `index.ts`; a local space with no `src/space/index.ts`, or one
457
+ exported by default; a built plugin whose manifest is missing, unreadable, or names no script there; `.env` inside
458
+ `src/`; code in a folder named like one the server reads (`src/plugin/`, `plugins/` at the root). Warnings — the same
459
+ folder with nothing it would read (`src/Data/`, `src/runtimes/`, `src/public/`); a plugin with no `declaration.ts`; a
460
+ file loose in `src/plugins/`; a file of `src/data/` that is not JSON; no `.env` or no `.env.example`; JSON in
461
+ `public/data/` of a project with a server, and a file in `public/` named like a secret. A near name is asked about —
462
+ did you mean `index.ts`, `src/plugins/`? — and one that differs only in case says it works on macOS and not on Linux.
463
+
328
464
  | Area | What is held |
329
465
  |---|---|
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 |
466
+ | `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) |
467
+ | `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 |
468
+ | `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
469
  | `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
470
  | `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 |
471
+ | `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`) |
472
+ | `data` | every JSON file of `src/data/` and `public/data/` parses — what the server answers with and `space push` sends |
337
473
  | `functions` | `src/functions/` built by the project's own `@plitzi/sdk-server` (`buildFunctions`), as every runner builds them |
338
474
  | `records` | `.plitzi/space.json`, `scaffold.json` and `functions.json` readable, and of the same space |
339
475
  | `skills` | `.claude/skills/plitzi-*` as the packages installed write them |
@@ -342,6 +478,24 @@ It loads the plugins' declarations and the project's own `@plitzi/sdk-server` to
342
478
  never starts the server or the runtime. A check that cannot finish is said as an error
343
479
  of its area, never a crash.
344
480
 
481
+ ## `feedback`
482
+
483
+ ```bash
484
+ npx @plitzi/cli feedback # a report to Plitzi, started
485
+ npx @plitzi/cli feedback --previous https://claude.ai/artifact/… # continuing an earlier one
486
+ ```
487
+
488
+ 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
489
+ must not get wrong — every `@plitzi` package installed and its version, Node and the machine, the project's mode and
490
+ source, what `plitzi doctor` finds — and writes the page the report is laid out in, `tmp/feedback/report-<date>.html`:
491
+ a tally by severity, what was built, what changed since the earlier reports, where to start, the findings filtered by
492
+ severity and area and each copied as an issue, and what worked — in light and dark, on a phone. It prints how to fill
493
+ it for the agent the developer works with: one `REPORT` object, each finding reproduced on the installed versions
494
+ before it is written, with what happens, the evidence, the impact, the workaround and a fix; no secret, token or
495
+ customer's data. The agent then publishes it as a private artifact and gives the developer its URL. `--previous` hands
496
+ it the earlier reports: their numbering goes on, and what changed of each finding is said. `--json`: `{ file, facts,
497
+ brief }`.
498
+
345
499
  ## `upgrade`
346
500
 
347
501
  ```bash
@@ -358,10 +512,12 @@ one the project made its own is a diff, left unless `--take` names it (`all` for
358
512
  `.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
513
  that the machinery reads (`src/config/serverOptions.ts`, `src/actions/index.ts`) is written when the project has none and the
360
514
  `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
515
+ today's command, one the project changed is left and said. A file the CLI no longer writes — `src/env.ts`, now that
516
+ Node reads `.env` — is removed the same way once the `main.ts` that read it is the CLI's; one the project changed is
517
+ said and left, unless `--take` names it (`.plitzi/scaffold.json` records the files and the scripts, and the package
362
518
  manager the files were written for — what a project not installed yet has no lockfile to say). In a project made from
363
- 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
519
+ 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 space pull` —
520
+ none does: `serveProject` runs whatever the space brought, from where it lands. `update` is the same
365
521
  command, and `plitzi skills update` is `upgrade skills --write`. `npm run author` says when the authoring skill is
366
522
  older than the `@plitzi/sdk-authoring` installed.
367
523
 
@@ -373,14 +529,16 @@ plitzi data describe src/data/products.json --json # { shape, example }
373
529
  ```
374
530
 
375
531
  The fields of a JSON file, their types and which rows have them — `price?: number (in 812 of 879)` — so a page can
376
- be bound to half a megabyte of data after reading twenty lines of it.
532
+ be bound to half a megabyte of data after reading twenty lines of it. An object keyed by data — slugs, ids — is one
533
+ shape, said once: `{ [key]: … } (500 keys: "first-post", …)`. A file written a letter off is offered the nearest one
534
+ beside it.
377
535
 
378
- ## `pull`
536
+ ## `space pull`
379
537
 
380
538
  ```bash
381
- plitzi pull # the space's changes in, yours kept
382
- plitzi pull --force # where a file changed on both sides, the space's copy wins
383
- plitzi pull --environment production --revision latest # follow another version from now on
539
+ plitzi space pull # the space's changes in, yours kept
540
+ plitzi space pull --force # where a file changed on both sides, the space's copy wins
541
+ plitzi space pull --environment production --revision latest # follow another version from now on
384
542
  ```
385
543
 
386
544
  In a project `create --from` wrote: a file the space changed and you did not is written, one you changed and the space
@@ -389,15 +547,15 @@ write **nothing** and name them. Both sides are compared as the project's Pretti
389
547
  `package.json` only gains the packages the space's code now asks for. It follows the version the project was made from —
390
548
  the draft, an environment's latest, or a pinned revision.
391
549
 
392
- ## `push`
550
+ ## `space push`
393
551
 
394
552
  ```bash
395
- plitzi push # at a terminal: tick what goes up — what changed is ticked already
396
- plitzi push space functions # only these: space, functions, data, runtime, plugins, files
397
- plitzi push space --force # replace the draft even though it was edited in the builder since
553
+ plitzi space push # at a terminal: tick what goes up — what changed is ticked already
554
+ plitzi space push space functions # only these: space, functions, data, runtime, plugins, files
555
+ plitzi space push space --force # replace the draft even though it was edited in the builder since
398
556
  ```
399
557
 
400
- The way back of `pull`: the project put on the space it works with, as its **draft**. With nobody at the terminal it
558
+ The way back of `space pull`: the project put on the space it works with, as its **draft**. With nobody at the terminal it
401
559
  sends what changed since the project last had the space. Each part goes up as its own command sends it, in the order
402
560
  that names come before what names them:
403
561
 
@@ -415,21 +573,22 @@ The draft is never replaced unseen: when it was edited in the builder since the
415
573
  is refused — pull first, or `--force`. A project that never had the space (one not made with `create --from`) may take a
416
574
  space nobody has worked on yet; one that holds work asks for `--force` too. Always the space the CLI is connected to,
417
575
  which must be the one the project came from, and never a published environment: publish in the builder. Afterwards
418
- `.plitzi/space.json` records what was sent, so `pull` keeps working — on a project that started on its own too.
576
+ `.plitzi/space.json` records what was sent, so `space pull` keeps working — on a project that started on its own too.
419
577
 
420
578
  The space goes back with its files where Plitzi serves them: a path to a file of `public/assets/` (`/assets/a.png`) —
421
- one `create --from` or `pull` wrote, or one the `files` part put on the CDN — is sent as that file's CDN address. Only
579
+ one `create --from` or `space pull` wrote, or one the `files` part put on the CDN — is sent as that file's CDN address. Only
422
580
  `public/assets/` goes to the CDN: the rest of `public/` is the project's own server's. What would not reach Plitzi is
423
581
  said before anything is sent, with what to do: a provider reading a file `src/data/` does not hold, a file of
424
582
  `public/assets/` the space names that is not on its CDN yet, and one of `public/` outside `assets/`.
425
583
 
426
- ## `add plugin`
584
+ ## `plugin add`
427
585
 
428
- Adds elements of your own to the project you are in — one, several at once (`add plugin seat-picker legend`), or one at
586
+ Adds elements of your own to the project you are in — one, several at once (`plugin add seat-picker legend`), or one at
429
587
  a time as the need comes. Each is a folder, written the way Plitzi's own elements are (`@plitzi/sdk-elements`): the
430
588
  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.
589
+ adds), its `Settings.tsx` panel for the builder, and the `index.ts` that puts them together — what the folder is built
590
+ from: `index.ts`, or `index.tsx` for one that writes its JSX there, never both. It asks what to call each, what the
591
+ builder shows, and what it is for, and checks every folder is free before writing any.
433
592
 
434
593
  - **In a project `plitzi create` wrote**, it goes in `src/plugins`, where the project already looks: nothing to
435
594
  register, and a running `start:dev` picks it up without a restart. Host it with `custom({ renderType: 'seatPicker' })` in `src/space/`
@@ -444,7 +603,7 @@ A name that would make a built-in element's type (`button`, `form`) is refused:
444
603
  Told its shape, it writes that shape rather than the counter it writes otherwise — one element at a time:
445
604
 
446
605
  ```bash
447
- plitzi add plugin ticker --prop interval:number=5000 --prop paused:boolean --trigger onTick:count --callback reset --headless
606
+ plitzi plugin add ticker --prop interval:number=5000 --prop paused:boolean --trigger onTick:count --callback reset --headless
448
607
  ```
449
608
 
450
609
  `--prop name:type=default` (string, number or boolean) is an attribute: in the props, the declaration's defaults and
@@ -459,14 +618,14 @@ Prettier writes them.
459
618
  routes answer under `/fn/plugins/<type>/` (`usePluginRoute(type)` in the component names them), its tasks are steps
460
619
  `<type>.<action>`, and it runs with a plugin's own corner of `kv`, none of the space's credentials or channels. In a
461
620
  server-mode project or a plugin package (which gets `@plitzi/sdk-server` for the types); a project that renders in the
462
- browser alone has nothing to run it, and is refused. `pack plugin` carries it as `functions.source.json`, and the
621
+ browser alone has nothing to run it, and is refused. `plugin pack` carries it as `functions.source.json`, and the
463
622
  platform builds and keeps it privately when the plugin is uploaded — see
464
623
  [functions § a plugin's server half](../../docs/en/functions.md#10-a-plugins-server-half).
465
624
 
466
625
  ## `create --plugin`
467
626
 
468
627
  A plugin package: elements any space can load, with a Vite preview to write them in. It builds nothing itself —
469
- `pack plugin` does, for every plugin — so it carries no bundler config and no build dependency.
628
+ `plugin pack` does, for every plugin — so it carries no bundler config and no build dependency.
470
629
 
471
630
  ```bash
472
631
  plitzi create seat-picker --plugin # asks the name, what the builder shows, what it is for, who publishes it
@@ -482,14 +641,14 @@ Its scripts: `start` (every element inside a space, rendered by the SDK in the b
482
641
  replacement), `visual` (a browser checks each element renders, answers a click, and leaves the page whole),
483
642
  `typecheck`, `lint` and `format`.
484
643
 
485
- ## `pack plugin`
644
+ ## `plugin pack`
486
645
 
487
646
  The one place a plugin is built — from a plugin package, or from element folders of any project:
488
647
 
489
648
  ```bash
490
- plitzi pack plugin # in a plugin package: every element it holds
491
- plitzi pack plugin src/plugins/SeatPicker # an element of a self-hosted project
492
- plitzi pack plugin src/plugins/SeatPicker src/plugins/Legend # several in one plugin, the first its main
649
+ plitzi plugin pack # in a plugin package: every element it holds
650
+ plitzi plugin pack src/plugins/SeatPicker # an element of a self-hosted project
651
+ plitzi plugin pack src/plugins/SeatPicker src/plugins/Legend # several in one plugin, the first its main
493
652
  ```
494
653
 
495
654
  It writes one ES module (esbuild; React and the SDK kept out — the page provides them; images, fonts and any file
@@ -505,27 +664,27 @@ what a manifest is written from. `--out` moves the build, `--no-zip` leaves the
505
664
  version the manifest carries (the project's own by default).
506
665
 
507
666
  Beside the zip it writes the plugin's **source** (`<name>.source.json.gz`): every file of the project its elements import
508
- — followed with the project's own TypeScript, `import type` included — and the packages they need. `upload plugin`
667
+ — followed with the project's own TypeScript, `import type` included — and the packages they need. `plugin upload`
509
668
  keeps it on the space, which is what `create --from` brings back. `--source-root` names the project those paths are
510
669
  relative to, when the elements are not a project of their own. A file outside it, a credentials file or a credential
511
670
  in the code keeps it from being written — said, and never stopping the build.
512
671
 
513
- ## `pack source`
672
+ ## `source pack`
514
673
 
515
674
  ```bash
516
- plitzi pack source src/runtime/index.ts --kind runtime --name runtime -o runtime.source.json.gz
675
+ plitzi source pack src/runtime/index.ts --kind runtime --name runtime -o runtime.source.json.gz
517
676
  ```
518
677
 
519
- What `upload plugin` and `runtime push` keep, written to a file to look at: the closure of the entries named, gzipped.
678
+ What `plugin upload` and `runtime push` keep, written to a file to look at: the closure of the entries named, gzipped.
520
679
 
521
680
 
522
- ## `login`, `space` and `upload plugin`
681
+ ## `login`, `space use` and `plugin upload`
523
682
 
524
683
  ```bash
525
684
  plitzi login # sign in, in your browser
526
- plitzi space # choose the space to work in, in your browser
685
+ plitzi space use # choose the space to work in, in your browser
527
686
  plitzi whoami # who you are signed in as, and the space; --json for a tool
528
- plitzi upload plugin # the zip pack plugin left, on that space
687
+ plitzi plugin upload # the zip pack plugin left, on that space
529
688
  plitzi logout # the session revoked on the platform, and forgotten here
530
689
  ```
531
690
 
@@ -535,17 +694,17 @@ social sign-in work without it knowing. What it keeps is the session and a way t
535
694
  and it shows among your account's devices, where it can be ended like any other.
536
695
 
537
696
  **One space at a time.** The space is chosen on the same grant screen an AI connector's is, and the CLI works in that
538
- one until `plitzi space` chooses another — which replaces the connection, and revokes the one before. No command takes a
697
+ one until `plitzi space use` chooses another — which replaces the connection, and revokes the one before. No command takes a
539
698
  space of its own: an upload goes to the space `plitzi whoami` names, so a plugin meant for a staging space cannot end
540
699
  up in the live one because of a flag.
541
700
 
542
- `upload plugin` takes the zip named, or the one `pack plugin` left in the project (the newest, when there are several —
701
+ `plugin upload` takes the zip named, or the one `plugin pack` left in the project (the newest, when there are several —
543
702
  asked at a terminal). It is checked for its `plugin-manifest.json` before anything is sent. Without a connection, or
544
703
  without a space, the browser opens for what is missing, so the first upload is one command too. It goes on one of the
545
704
  space's public buckets — `--bucket <identifier>` (narrowed to one CDN with `--cdn <identifier>`), or asked when there
546
705
  are several; a private bucket is refused, since no page could load from it — and is installed, as the builder does when
547
706
  a zip is dropped under Resources: added, or the plugin already there moved to the new version with its settings kept. The
548
- source `pack plugin` wrote beside the zip goes up after it, into the space's private bucket.
707
+ source `plugin pack` wrote beside the zip goes up after it, into the space's private bucket.
549
708
 
550
709
  `--api` (or `PLITZI_API_URL`) points it at another platform, a self-hosted or local one; the CLI trusts the
551
710
  certificate authorities the system trusts, as the browser beside it does.
@@ -568,11 +727,11 @@ connection kept open, memory that outlives a request, Node and its packages (`do
568
727
  **Its code lives in a project of yours** — a folder, usually a repository — and nowhere else: the builder shows how a
569
728
  runtime runs and sets its variables, but it does not hold its code and cannot change it. The project has
570
729
  `src/runtime/index.ts` (or `--entry`), whose default export is `defineRuntime(…)`, and `@plitzi/sdk-server` installed:
571
- `plitzi add runtime` writes it in a project from `plitzi create` in server mode, whose `src/main.ts` runs it too —
730
+ `plitzi runtime add` writes it in a project from `plitzi create` in server mode, whose `src/main.ts` runs it too —
572
731
  `/hello` answers on `npm start` — and whose `start:dev` restarts on it; `examples/self-hosting/10-runtime` is the smallest one to start
573
732
  from, and it runs as a server of its own too.
574
733
 
575
- `push` packs the module with the project's own `@plitzi/sdk-server` — the module and every package it imports, bar
734
+ `runtime push` packs the module with the project's own `@plitzi/sdk-server` — the module and every package it imports, bar
576
735
  `@plitzi/*` and React, which the platform provides — and sends it to the space `plitzi whoami` names. It becomes the
577
736
  draft's runtime, which starts on it; **publishing the space** from the builder takes it to the published site. A
578
737
  runtime is part of the plans that carry it; on another, the push is refused and says so. The source it was
@@ -596,8 +755,8 @@ plitzi functions dev seismic.feed --params '{}' --watch # on this mac
596
755
  ```
597
756
 
598
757
  A space's own server code — tasks its actions run as steps, routes under `/fn/` — and `src/functions/` is a working copy
599
- of it: `.plitzi/functions.json` keeps what was pulled, so `pull` refuses to overwrite what is not pushed (`--force`
600
- throws it away) and `push` refuses when the space moved on since. A problem comes back as
758
+ of it: `.plitzi/functions.json` keeps what was pulled, so `functions pull` refuses to overwrite what is not pushed (`--force`
759
+ throws it away) and `functions push` refuses when the space moved on since. A problem comes back as
601
760
  `src/functions/<file>:<line> <message>`. `dev` runs with the project's own `@plitzi/sdk-server` (`isolated-vm` and
602
761
  `core-js` beside it); credentials come from `PLITZI_FUNCTIONS_CREDENTIALS`. See `docs/en/functions.md`.
603
762
 
@@ -608,7 +767,14 @@ throws it away) and `push` refuses when the space moved on since. A problem come
608
767
  names them differently on purpose: a server gets the secret self-hosting key, a browser gets the public render key,
609
768
  whose protection is the origin it is presenting from.
610
769
 
611
- Every server project's `src/main.ts` reads `.env` itself (`process.loadEnvFile`), so `npm start` needs nothing else.
770
+ Every project has a `.env`, never committed, and a `.env.example`, committed: the same settings with no secret in them,
771
+ for a clone to copy and fill in. A server project's `.env` is read as each script starts —
772
+ `node --env-file-if-exists=.env` in `start`, `start:prod` and `author`, and in `start:dev`, which Node watches,
773
+ `node --import @plitzi/sdk-server/env` (Node's flag there has its watcher restart on every write in the project) —
774
+ before any of its modules is evaluated, so `src/config/serverOptions.ts` and the actions find their settings in
775
+ `process.env` as they load. A change to it is read on the next start, and a deployment that sets its environment needs
776
+ no file. A browser
777
+ project's is Vite's: only `VITE_*` reaches the page, and ships in it.
612
778
  `create` gives each one a signing key there, made for it: `PLITZI_SIGNING_SECRET`, what `ctx.sign` and `ctx.verify`
613
779
  sign with — at least 32 characters (`doctor --fix` writes one where it is missing). `PORT` is left commented out: 8080,
614
780
  or the next free port while developing.