@plitzi/cli 0.38.7 → 0.38.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/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
@@ -114,7 +114,7 @@ when an install fails the CLI says which setting names it.
114
114
  again; it swaps a saved plugin where it is drawn, and restarts only for the server's own code.
115
115
  - **A plugin of the project's own.** `src/plugins/StatCard` is a React component the space renders through a
116
116
  `custom` element — the one thing about Plitzi a page of built-in elements cannot show. Every folder of
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
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
118
118
  element's attributes, so a data source pointed at that element later reaches the component with no plumbing in
119
119
  between. Server-rendered in server mode (`action: 'compile'`), part of the bundle in client mode.
120
120
  - **A visual test.** The `visual` script starts the project, opens the page and asserts that every element the space
@@ -141,10 +141,10 @@ when an install fails the CLI says which setting names it.
141
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 |
142
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 |
143
143
  | `src/functions/` | Server mode: the project's own server code — tasks and `/fn/` routes (`defineFunctions`), built at boot | yes |
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
+ | `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
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 |
146
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 |
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
+ | `.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 |
148
148
 
149
149
  **`plitzi/` is the CLI's; `src/` is yours — but `src/main.ts`.** `plitzi/` holds `author.ts`, the types plugins import
150
150
  (`assets.d.ts`, server mode) or the page's base styles (`preflight.css`, client mode), and a `README.md` saying what
@@ -156,7 +156,7 @@ project keeps it — so a fix to the server arrives with `npm update`, not as a
156
156
  project is: it is the folder every script runs in, and both refuse to start anywhere else, naming what is missing
157
157
  (`package.json`, `src/`) — run them from the project's root. Nor do they start on a part where nothing reads it — a
158
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
159
+ with its fix). A plugin is declared by its folder: the server, `author` and `page check` find every
160
160
  `src/plugins/<Name>/declaration.ts` (`pluginDeclarations` from `@plitzi/sdk-authoring/node`). What the server does
161
161
  besides serving the space is the project's own, in files it reads: `src/config/serverOptions.ts` (handed to `serveProject` —
162
162
  `images`, `action.limits`, `action.kv`, `rsc`) and, with `--source local`, `src/actions/index.ts` (the space's server
@@ -179,43 +179,71 @@ in `src/data/products.json` read on the server as a typed source (`public/data/p
179
179
  in client mode), a catalog filtered by category, and a page per product — a file per part under `src/space/`. Both go
180
180
  with `--source local`.
181
181
 
182
- ## `check` and `shot`
182
+ ## `page check` and `page shot`
183
183
 
184
184
  ```bash
185
- plitzi check / --width 1440,390 # is the page whole? in text, per width; --json for a tool
186
- plitzi check /products --state --element catalog-count # and what it holds: state, sources, one element
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
189
- plitzi shot /about --width 390 --scheme dark
190
- plitzi shot / --frames 4 --every 500 # what moves: a marquee, an autoplay
191
- 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 /about /writers # several pages, in one browser
187
+ plitzi page check /products --state --element catalog-count # and what it holds: state, sources, one element
188
+ plitzi page check / --ssr # and what the server's HTML lacks that the hydrated page has
189
+ plitzi page check /enterprise --click site-footer-top # click one element: what it changed, or that nothing did
190
+ plitzi page check / --click news-send --fill news-email=ana@example.com # a form sent as a visitor fills it
191
+ plitzi page check /studio --as maya # a page for signed-in visitors, signed in through /auth first
192
+ plitzi page shot /about --width 390 --scheme dark
193
+ plitzi page shot / --frames 4 --every 500 # what moves: a marquee, an autoplay
194
+ plitzi page shot / --viewport --click .knob open-button --frames 4 --every 250 --sheet # an interaction, on one sheet
195
+ plitzi page shot / --compare https://example.com --width 1440 # beside another site: what differs, and how
192
196
  ```
193
197
 
194
198
  Both run on the project's own Playwright against its running server (`npm start`), and refuse a port that answers as
195
199
  another project. They wait for the page to settle — loaded, then half a second with nothing asked for — counting no
196
200
  stream that stays open, so a page with a realtime `channel` is checked like any other (`openPage` of
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
198
- images, sideways scroll, text in the colour behind it, console errors, refused requests and failed flows — and the
201
+ `@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
202
+ images, sideways scroll, a link or words cut off at the screen's edge (an ancestor hiding them, nothing scrolling to
203
+ them), text in the colour behind it, console errors, refused requests and failed flows — and the
199
204
  page's data: a binding that reads a path its provider's answer lacks (with the keys it has) — none inside an element
200
205
  the page is not showing, which is not mounted — a provider that failed, and each list's rows, drawn and in its source
201
206
  (`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.
207
+ `--element` adds, at rest, each property more than one of the element's classes sets: the value shown, the class it
208
+ comes from and what the others say — `border-radius: 999px, from ent-cta-pill (button-primary says 12px)` — or that
209
+ they all set it alike, so it stays without any one of them. That is said of the property alone: a class that shares
210
+ one may set others. A class is said to change nothing on the element only when every property it sets stays without
211
+ it, at rest at that width — and then with the other elements it is on: taking it off this element's `class` touches
212
+ none of them, changing the class itself changes them all (`--json`: `styles: { contested, inert, wornBy }`). Which
213
+ class wins is asked of the page (each taken off for a moment), so specificity, order and media are answered without a
214
+ picture.
215
+
216
+ `--click <id>` clicks one element once the page has settled, as a visitor does — brought into view first, which is
217
+ not the click's doing — and says what changed: the flows it ran and how each step ended, where the page went, what
218
+ scrolled, what is shown now and what no longer is, what the page said (a toast, an alert: `said: "Link copied"`), the
219
+ state. A form the browser held back is said with the field and the browser's reason (`the browser held the form back:
220
+ email — Please fill out this field.`), not as a click that ran nothing. A click that changed nothing says so in those
221
+ words, and a flow that ran and succeeded with nothing on the page changed is said as that too: a button whose flow
222
+ does nothing looks like one that works until it is clicked. A click that could not be made, or a flow that failed,
223
+ fails the check (`--json`: `clicked: { element, filled?, changes, failed, problem? }`).
224
+
225
+ `--fill <id>=<value>`, once per field, fills a field before the click as a visitor does — typed in, an option chosen, a
226
+ 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
227
+ field's element, or one that holds that one field (a `formControl`'s wrapper); one that holds several is refused with
228
+ their ids, and a field filled inside another element says whose it is. Without `--click` it is refused: nothing filled
229
+ is sent anywhere.
202
230
 
203
231
  `--scheme` is the space's own theme, set as a visitor's toggle sets it (the `theme` cookie); left out, the space's
204
- default, and `shot` names the file by the theme it was painted in. The dev tools' badge is hidden from both. A
205
- full-page `shot` is the whole page — the pane the SDK scrolls in unrolled, every lazy picture loaded, every arrival
232
+ default, and `page shot` names the file by the theme it was painted in. The dev tools' badge is hidden from both. A
233
+ full-page `page shot` is the whole page — the pane the SDK scrolls in unrolled, every lazy picture loaded, every arrival
206
234
  waiting for the scroll shown as it ends — in `tmp/shots/` unless `--out` says where.
207
235
 
208
- `shot --compare` writes the two pictures side by side and the differences in red. It compares each section where it
236
+ `page shot --compare` writes the two pictures side by side and the differences in red. It compares each section where it
209
237
  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
210
238
  texts both pages have and says what each does differently there — `h1 "Learn CSS" — font-size 68px → 60px · y +19px`.
211
239
  `--frames` compares pictures taken one after another and names what moved. A project `create` writes has them as
212
240
  `npm run check` and `npm run shot`.
213
241
 
214
- ## `fix`
242
+ ## `space fix`
215
243
 
216
244
  ```bash
217
- plitzi fix # what authoring would fix, as a diff of your own source
218
- plitzi fix --write # written, formatted as the project formats, and checked
245
+ plitzi space fix # what authoring would fix, as a diff of your own source
246
+ plitzi space fix --write # written, formatted as the project formats, and checked
219
247
  ```
220
248
 
221
249
  The fixes are the ones with a single reading (`fixSpace`'s: a key the element never reads, `'true'` where a boolean
@@ -224,12 +252,89 @@ by the line and column the element remembers — and only where the value is wri
224
252
  listed with where it is and why it was left. `--write` authors the space again in a fresh process and keeps the edits
225
253
  only if every fix is gone and no problem was added; a fix that would add one is put back and said.
226
254
 
227
- ## `lint`
255
+ ## `element where` and `element edit`
228
256
 
229
257
  ```bash
230
- plitzi lint # the space's source, eslint's way: each practice to change at its file and line
231
- plitzi lint --json # one object: { scope, notChecked, counts, findings }
232
- plitzi lint --max-warnings 0 # more warnings than that fail (exit 1); --strict: any warning does
258
+ plitzi element where hero-cta # by id: the file, the line and the call that writes it
259
+ plitzi element where navLink # every element wearing the class (`nav-link` or `navLink`)
260
+ plitzi element where "Get started" # every element showing the words
261
+ plitzi element where cta --by text # one reading only: id, class or text
262
+ plitzi element edit hero-cta --set content="Start free" # an attribute written in that call
263
+ plitzi element edit signup --set required=true --remove placeholder
264
+ plitzi element edit site-brand --every --set label="Home" # a helper's call that writes several elements: every one
265
+ ```
266
+
267
+ `element where` answers where the project's code writes an element — `src/space/pages/home.ts:42` and the call itself, or the
268
+ object a page or a layout is declared as — so
269
+ 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
270
+ authored again and each element's call read back, the way `space fix` finds it, so it follows an element wherever somebody
271
+ moved it, with nothing kept that could fall out of step. Ten matches at most, the call shown for the first three;
272
+ `--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 —
273
+ the first that matches is answered, and any other that matched too is said with its count and the command for it
274
+ (`--by text`); `--by` reads it one way only. Words are every word an element says: its content, a `label`, `title`,
275
+ `alt` or `placeholder`, a binding's template, the words an instance hands its component. Asked for a class, it says
276
+ where the class is declared too — the `styles()` call — before who wears it; and an element written inside a
277
+ `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
278
+ lines of `src/` holding the words instead.
279
+
280
+ `element edit` writes attributes in that call — `content` given as the factory's first argument (`text('Hi', { … })`) where it
281
+ is — keeping the kind each one has (a number stays a number; a new one is `true`/`false` or words), formats the file as
282
+ the project formats it, and authors the space again in a fresh process, read against the space before it: unless every
283
+ value asked for is there and nothing else in the space changed, the files go back to what they were, and what would
284
+ have changed besides is named. What it changed is printed, every line of it (`--json`: `effects`). An attribute a
285
+ 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
286
+ `pageHead(id, title)`) is changed where the helper is handed it — `pageHead('about-head', 'About us')` — followed up
287
+ 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
288
+ repeated for (`QUESTIONS.map(item => button({ content: item.question }))`) is changed in the one entry of the list
289
+ that holds it, in whichever file the list is written. A component's instance is edited like any element: its
290
+ attributes are the props it hands the component, and `element where` finds the words it hands too. A page is edited by its
291
+ attributes as `element where` shows them — `seoPageTitle` is written as the page's `seoTitle`. A value read in more than one
292
+ 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
293
+ element — a helper called for each — is never changed unasked: `element where` says which elements it writes and the call that
294
+ leads to this one alone, and `element edit` refuses, naming them, unless `--every` says the change is for all of them. Any other
295
+ value written as anything but a literal — a variable, a template, props spread from elsewhere — is left to the author,
296
+ said with where it is. The same `element edit` refused again within a few minutes says so,
297
+ and that running it once more will not change the answer (kept in `tmp/refusals.json`).
298
+
299
+ ## `element remove`, `element move` and `verify`
300
+
301
+ ```bash
302
+ plitzi element remove ent-trust # the element's call taken out, with the styles and imports only it used
303
+ plitzi element move ent-faq --before ent-pricing # put before (or --after) a sibling of the same list of children
304
+ plitzi verify # author, lint:space, typecheck, lint, format and every page: what fails
305
+ plitzi verify --no-pages # the pages left out, said as such
306
+ ```
307
+
308
+ `element remove` and `element move` act on the call that writes the element — or, a section a helper builds and returns
309
+ (`body: [enterpriseFaq()]`), on the helper's call — and are checked as `element edit` is: the space authored again in a fresh
310
+ process and read against the one before. A removal may take the element and what it holds and nothing else; a move
311
+ may change only its parent's order, with the element beside the one it was moved by. Anything more and the file goes
312
+ back, what it would have changed named — and the space read again goes through the same gate `npm run author` does, so
313
+ a change that leaves it refused is never kept. A removal is refused before anything is written when another element's
314
+ flow acts on what it would take away (`site-search openModal → search-modal`), each said with where it is. What it took
315
+ 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
316
+ factories' imports, named; a helper left with no caller is said, not deleted. A call written once for several
317
+ elements (a `map`), a page or a layout, and a move between two files are left to the author, said.
318
+
319
+ An element's own selector and its bindings are named after its place under its nearest id — not after its position
320
+ among its siblings — so a move renames nothing.
321
+
322
+ `verify` runs each check the project has a script for, as its package manager runs one, then opens every page with
323
+ no parameter in its path at 1440 and 390 px (the server must be up: `npm start`). Only what fails is printed, with the
324
+ last lines it said, and the first failure ends the run — one broken file fails every step after it the same way — the
325
+ rest said as not run until it passes (`--keep-going` runs them anyway). A page the browser was sent away from — one
326
+ for signed-in visitors — is checked again signed in as the project's account, when `.env` names one:
327
+ `PLITZI_CHECK_USER` and `PLITZI_CHECK_PASSWORD`, the password `page check --as` reads too (the environment wins over
328
+ `.env`, as it does for the project's scripts; never on the command line, which a shell keeps). One that even that
329
+ account is sent away from, or with no account named, is said as not checked, never as passing — on its own line, with
330
+ what checks it, without failing the run. Exit 1 when anything failed.
331
+
332
+ ## `space lint`
333
+
334
+ ```bash
335
+ plitzi space lint # the space's source, eslint's way: each practice to change at its file and line
336
+ plitzi space lint --json # one object: { scope, notChecked, counts, findings }
337
+ plitzi space lint --max-warnings 0 # more warnings than that fail (exit 1); --strict: any warning does
233
338
  ```
234
339
 
235
340
  How the space in `src/space/` is written — what only its source can say, and what grows hard to read and to change as
@@ -261,14 +366,14 @@ lint's own codes:
261
366
  `// plitzi-lint-disable <codes>` for the whole file.
262
367
 
263
368
  It is not whether the space authors — what it refuses and warns of is `npm run author`'s — nor a page as it renders
264
- (`check`), nor the project around the space (`doctor`); every report says so (`notChecked`). Exit code 1 while anything
369
+ (`page check`), nor the project around the space (`doctor`); every report says so (`notChecked`). Exit code 1 while anything
265
370
  is an error; with `--strict` a warning too, with `--max-warnings <n>` more than n of them.
266
371
 
267
- ## `import`
372
+ ## `page import`
268
373
 
269
374
  ```bash
270
- plitzi import https://example.com/pricing # into src/imported
271
- plitzi import https://example.com/ --out src/home --width 1440,390
375
+ plitzi page import https://example.com/pricing # into src/imported
376
+ plitzi page import https://example.com/ --out src/home --width 1440,390
272
377
  ```
273
378
 
274
379
  A page you own or may reuse, measured in the project's own Playwright as a place to start writing from — never a copy
@@ -303,11 +408,16 @@ plitzi explain class-and-css # a problem's code: what was wrong, what to writ
303
408
  plitzi explain content-attribute # a suggestion's code: what is written the long way, and the short one
304
409
  plitzi explain bindTemplate # a helper: how it is written, what it is for, an example
305
410
  plitzi explain motion # the arrivals, triggers and loops the SDK plays
411
+ plitzi explain pageFamily # any other export of @plitzi/sdk-authoring: its signature and its doc's first line
306
412
  plitzi explain --list steps # every one of a kind: elements, steps, triggers, codes, transformers, helpers
307
413
  ```
308
414
 
309
415
  What a name means when authoring, from the catalogues the checks themselves read — the answer to a question that would
310
- otherwise be a search through the SDK's types. `--json` answers in one object; over MCP it is `plitzi://explain/{name}`.
416
+ otherwise be a search through the SDK's types. A name no catalogue holds — `pageFamily`, `styles`, `SpaceSpec` — is any
417
+ export of `@plitzi/sdk-authoring`, answered from the `.d.ts` the project installed, so it is the version the project
418
+ runs. An element of the project's own — `src/plugins/<Name>/` — is explained by its type the same way: what it takes
419
+ (each attribute at its default), fires and answers, and the `custom({ … renderType })` that places it, which `plugin
420
+ add` prints too. `--json` answers in one object; over MCP it is `plitzi://explain/{name}`.
311
421
 
312
422
  ## `doctor`
313
423
 
@@ -322,7 +432,7 @@ plitzi doctor --strict # warnings fail too — for a CI that keeps the p
322
432
  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:
323
433
  a developer may change any file, and the checks are what each part must be for the project to install, start, build and
324
434
  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
325
- 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).
435
+ 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).
326
436
 
327
437
  Each finding has an area, a stable `code`, the file and its `fix`; the report ends with **what to run next** — the few
328
438
  commands (`plitzi upgrade --write`, an install, `doctor --fix`) that clear most of the list, by how many each fixes.
@@ -345,7 +455,7 @@ area would only say what the move fixes — and `upgrade` writes no file until i
345
455
  **Where each part lives** is one check (`checkProjectLayout`, `@plitzi/sdk-shared/project/layout`) said by three: the
346
456
  server refuses to start on its errors, listing every one (and prints its warnings while developing — a plugin folder
347
457
  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
458
+ (`page check`, `space push`, `space fix`) refuse to author, and `doctor` says each with its fix under `layout`. `space lint` says in one line
349
459
  that there are some. Its codes, each with what it means, are `PROJECT_LAYOUT_CODES`: errors — a plugin folder with no
350
460
  `index.ts` (or `index.tsx`), or both; a JavaScript entry; a folder name that is no element type (`story-editor` →
351
461
  `StoryEditor`), two folders of one type, a plugin also built in `vendor/plugins/`; a plugin's `functions/`,
@@ -365,7 +475,7 @@ did you mean `index.ts`, `src/plugins/`? — and one that differs only in case s
365
475
  | `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 |
366
476
  | `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) |
367
477
  | `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 |
478
+ | `data` | every JSON file of `src/data/` and `public/data/` parses — what the server answers with and `space push` sends |
369
479
  | `functions` | `src/functions/` built by the project's own `@plitzi/sdk-server` (`buildFunctions`), as every runner builds them |
370
480
  | `records` | `.plitzi/space.json`, `scaffold.json` and `functions.json` readable, and of the same space |
371
481
  | `skills` | `.claude/skills/plitzi-*` as the packages installed write them |
@@ -412,7 +522,7 @@ today's command, one the project changed is left and said. A file the CLI no lon
412
522
  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
523
  said and left, unless `--take` names it (`.plitzi/scaffold.json` records the files and the scripts, and the package
414
524
  manager the files were written for — what a project not installed yet has no lockfile to say). In a project made from
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` —
525
+ 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` —
416
526
  none does: `serveProject` runs whatever the space brought, from where it lands. `update` is the same
417
527
  command, and `plitzi skills update` is `upgrade skills --write`. `npm run author` says when the authoring skill is
418
528
  older than the `@plitzi/sdk-authoring` installed.
@@ -425,14 +535,16 @@ plitzi data describe src/data/products.json --json # { shape, example }
425
535
  ```
426
536
 
427
537
  The fields of a JSON file, their types and which rows have them — `price?: number (in 812 of 879)` — so a page can
428
- be bound to half a megabyte of data after reading twenty lines of it.
538
+ be bound to half a megabyte of data after reading twenty lines of it. An object keyed by data — slugs, ids — is one
539
+ shape, said once: `{ [key]: … } (500 keys: "first-post", …)`. A file written a letter off is offered the nearest one
540
+ beside it.
429
541
 
430
- ## `pull`
542
+ ## `space pull`
431
543
 
432
544
  ```bash
433
- plitzi pull # the space's changes in, yours kept
434
- plitzi pull --force # where a file changed on both sides, the space's copy wins
435
- plitzi pull --environment production --revision latest # follow another version from now on
545
+ plitzi space pull # the space's changes in, yours kept
546
+ plitzi space pull --force # where a file changed on both sides, the space's copy wins
547
+ plitzi space pull --environment production --revision latest # follow another version from now on
436
548
  ```
437
549
 
438
550
  In a project `create --from` wrote: a file the space changed and you did not is written, one you changed and the space
@@ -441,15 +553,15 @@ write **nothing** and name them. Both sides are compared as the project's Pretti
441
553
  `package.json` only gains the packages the space's code now asks for. It follows the version the project was made from —
442
554
  the draft, an environment's latest, or a pinned revision.
443
555
 
444
- ## `push`
556
+ ## `space push`
445
557
 
446
558
  ```bash
447
- plitzi push # at a terminal: tick what goes up — what changed is ticked already
448
- plitzi push space functions # only these: space, functions, data, runtime, plugins, files
449
- plitzi push space --force # replace the draft even though it was edited in the builder since
559
+ plitzi space push # at a terminal: tick what goes up — what changed is ticked already
560
+ plitzi space push space functions # only these: space, functions, data, runtime, plugins, files
561
+ plitzi space push space --force # replace the draft even though it was edited in the builder since
450
562
  ```
451
563
 
452
- The way back of `pull`: the project put on the space it works with, as its **draft**. With nobody at the terminal it
564
+ The way back of `space pull`: the project put on the space it works with, as its **draft**. With nobody at the terminal it
453
565
  sends what changed since the project last had the space. Each part goes up as its own command sends it, in the order
454
566
  that names come before what names them:
455
567
 
@@ -467,17 +579,17 @@ The draft is never replaced unseen: when it was edited in the builder since the
467
579
  is refused — pull first, or `--force`. A project that never had the space (one not made with `create --from`) may take a
468
580
  space nobody has worked on yet; one that holds work asks for `--force` too. Always the space the CLI is connected to,
469
581
  which must be the one the project came from, and never a published environment: publish in the builder. Afterwards
470
- `.plitzi/space.json` records what was sent, so `pull` keeps working — on a project that started on its own too.
582
+ `.plitzi/space.json` records what was sent, so `space pull` keeps working — on a project that started on its own too.
471
583
 
472
584
  The space goes back with its files where Plitzi serves them: a path to a file of `public/assets/` (`/assets/a.png`) —
473
- one `create --from` or `pull` wrote, or one the `files` part put on the CDN — is sent as that file's CDN address. Only
585
+ 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
474
586
  `public/assets/` goes to the CDN: the rest of `public/` is the project's own server's. What would not reach Plitzi is
475
587
  said before anything is sent, with what to do: a provider reading a file `src/data/` does not hold, a file of
476
588
  `public/assets/` the space names that is not on its CDN yet, and one of `public/` outside `assets/`.
477
589
 
478
- ## `add plugin`
590
+ ## `plugin add`
479
591
 
480
- Adds elements of your own to the project you are in — one, several at once (`add plugin seat-picker legend`), or one at
592
+ Adds elements of your own to the project you are in — one, several at once (`plugin add seat-picker legend`), or one at
481
593
  a time as the need comes. Each is a folder, written the way Plitzi's own elements are (`@plitzi/sdk-elements`): the
482
594
  component, its `declaration.ts` (its `type`, the events it fires, the actions it answers to, and the element the builder
483
595
  adds), its `Settings.tsx` panel for the builder, and the `index.ts` that puts them together — what the folder is built
@@ -497,7 +609,7 @@ A name that would make a built-in element's type (`button`, `form`) is refused:
497
609
  Told its shape, it writes that shape rather than the counter it writes otherwise — one element at a time:
498
610
 
499
611
  ```bash
500
- plitzi add plugin ticker --prop interval:number=5000 --prop paused:boolean --trigger onTick:count --callback reset --headless
612
+ plitzi plugin add ticker --prop interval:number=5000 --prop paused:boolean --trigger onTick:count --callback reset --headless
501
613
  ```
502
614
 
503
615
  `--prop name:type=default` (string, number or boolean) is an attribute: in the props, the declaration's defaults and
@@ -512,14 +624,14 @@ Prettier writes them.
512
624
  routes answer under `/fn/plugins/<type>/` (`usePluginRoute(type)` in the component names them), its tasks are steps
513
625
  `<type>.<action>`, and it runs with a plugin's own corner of `kv`, none of the space's credentials or channels. In a
514
626
  server-mode project or a plugin package (which gets `@plitzi/sdk-server` for the types); a project that renders in the
515
- browser alone has nothing to run it, and is refused. `pack plugin` carries it as `functions.source.json`, and the
627
+ browser alone has nothing to run it, and is refused. `plugin pack` carries it as `functions.source.json`, and the
516
628
  platform builds and keeps it privately when the plugin is uploaded — see
517
629
  [functions § a plugin's server half](../../docs/en/functions.md#10-a-plugins-server-half).
518
630
 
519
631
  ## `create --plugin`
520
632
 
521
633
  A plugin package: elements any space can load, with a Vite preview to write them in. It builds nothing itself —
522
- `pack plugin` does, for every plugin — so it carries no bundler config and no build dependency.
634
+ `plugin pack` does, for every plugin — so it carries no bundler config and no build dependency.
523
635
 
524
636
  ```bash
525
637
  plitzi create seat-picker --plugin # asks the name, what the builder shows, what it is for, who publishes it
@@ -535,14 +647,14 @@ Its scripts: `start` (every element inside a space, rendered by the SDK in the b
535
647
  replacement), `visual` (a browser checks each element renders, answers a click, and leaves the page whole),
536
648
  `typecheck`, `lint` and `format`.
537
649
 
538
- ## `pack plugin`
650
+ ## `plugin pack`
539
651
 
540
652
  The one place a plugin is built — from a plugin package, or from element folders of any project:
541
653
 
542
654
  ```bash
543
- plitzi pack plugin # in a plugin package: every element it holds
544
- plitzi pack plugin src/plugins/SeatPicker # an element of a self-hosted project
545
- plitzi pack plugin src/plugins/SeatPicker src/plugins/Legend # several in one plugin, the first its main
655
+ plitzi plugin pack # in a plugin package: every element it holds
656
+ plitzi plugin pack src/plugins/SeatPicker # an element of a self-hosted project
657
+ plitzi plugin pack src/plugins/SeatPicker src/plugins/Legend # several in one plugin, the first its main
546
658
  ```
547
659
 
548
660
  It writes one ES module (esbuild; React and the SDK kept out — the page provides them; images, fonts and any file
@@ -558,27 +670,27 @@ what a manifest is written from. `--out` moves the build, `--no-zip` leaves the
558
670
  version the manifest carries (the project's own by default).
559
671
 
560
672
  Beside the zip it writes the plugin's **source** (`<name>.source.json.gz`): every file of the project its elements import
561
- — followed with the project's own TypeScript, `import type` included — and the packages they need. `upload plugin`
673
+ — followed with the project's own TypeScript, `import type` included — and the packages they need. `plugin upload`
562
674
  keeps it on the space, which is what `create --from` brings back. `--source-root` names the project those paths are
563
675
  relative to, when the elements are not a project of their own. A file outside it, a credentials file or a credential
564
676
  in the code keeps it from being written — said, and never stopping the build.
565
677
 
566
- ## `pack source`
678
+ ## `source pack`
567
679
 
568
680
  ```bash
569
- plitzi pack source src/runtime/index.ts --kind runtime --name runtime -o runtime.source.json.gz
681
+ plitzi source pack src/runtime/index.ts --kind runtime --name runtime -o runtime.source.json.gz
570
682
  ```
571
683
 
572
- What `upload plugin` and `runtime push` keep, written to a file to look at: the closure of the entries named, gzipped.
684
+ What `plugin upload` and `runtime push` keep, written to a file to look at: the closure of the entries named, gzipped.
573
685
 
574
686
 
575
- ## `login`, `space` and `upload plugin`
687
+ ## `login`, `space use` and `plugin upload`
576
688
 
577
689
  ```bash
578
690
  plitzi login # sign in, in your browser
579
- plitzi space # choose the space to work in, in your browser
691
+ plitzi space use # choose the space to work in, in your browser
580
692
  plitzi whoami # who you are signed in as, and the space; --json for a tool
581
- plitzi upload plugin # the zip pack plugin left, on that space
693
+ plitzi plugin upload # the zip pack plugin left, on that space
582
694
  plitzi logout # the session revoked on the platform, and forgotten here
583
695
  ```
584
696
 
@@ -588,17 +700,17 @@ social sign-in work without it knowing. What it keeps is the session and a way t
588
700
  and it shows among your account's devices, where it can be ended like any other.
589
701
 
590
702
  **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
591
- one until `plitzi space` chooses another — which replaces the connection, and revokes the one before. No command takes a
703
+ one until `plitzi space use` chooses another — which replaces the connection, and revokes the one before. No command takes a
592
704
  space of its own: an upload goes to the space `plitzi whoami` names, so a plugin meant for a staging space cannot end
593
705
  up in the live one because of a flag.
594
706
 
595
- `upload plugin` takes the zip named, or the one `pack plugin` left in the project (the newest, when there are several —
707
+ `plugin upload` takes the zip named, or the one `plugin pack` left in the project (the newest, when there are several —
596
708
  asked at a terminal). It is checked for its `plugin-manifest.json` before anything is sent. Without a connection, or
597
709
  without a space, the browser opens for what is missing, so the first upload is one command too. It goes on one of the
598
710
  space's public buckets — `--bucket <identifier>` (narrowed to one CDN with `--cdn <identifier>`), or asked when there
599
711
  are several; a private bucket is refused, since no page could load from it — and is installed, as the builder does when
600
712
  a zip is dropped under Resources: added, or the plugin already there moved to the new version with its settings kept. The
601
- source `pack plugin` wrote beside the zip goes up after it, into the space's private bucket.
713
+ source `plugin pack` wrote beside the zip goes up after it, into the space's private bucket.
602
714
 
603
715
  `--api` (or `PLITZI_API_URL`) points it at another platform, a self-hosted or local one; the CLI trusts the
604
716
  certificate authorities the system trusts, as the browser beside it does.
@@ -621,11 +733,11 @@ connection kept open, memory that outlives a request, Node and its packages (`do
621
733
  **Its code lives in a project of yours** — a folder, usually a repository — and nowhere else: the builder shows how a
622
734
  runtime runs and sets its variables, but it does not hold its code and cannot change it. The project has
623
735
  `src/runtime/index.ts` (or `--entry`), whose default export is `defineRuntime(…)`, and `@plitzi/sdk-server` installed:
624
- `plitzi add runtime` writes it in a project from `plitzi create` in server mode, whose `src/main.ts` runs it too —
736
+ `plitzi runtime add` writes it in a project from `plitzi create` in server mode, whose `src/main.ts` runs it too —
625
737
  `/hello` answers on `npm start` — and whose `start:dev` restarts on it; `examples/self-hosting/10-runtime` is the smallest one to start
626
738
  from, and it runs as a server of its own too.
627
739
 
628
- `push` packs the module with the project's own `@plitzi/sdk-server` — the module and every package it imports, bar
740
+ `runtime push` packs the module with the project's own `@plitzi/sdk-server` — the module and every package it imports, bar
629
741
  `@plitzi/*` and React, which the platform provides — and sends it to the space `plitzi whoami` names. It becomes the
630
742
  draft's runtime, which starts on it; **publishing the space** from the builder takes it to the published site. A
631
743
  runtime is part of the plans that carry it; on another, the push is refused and says so. The source it was
@@ -649,8 +761,8 @@ plitzi functions dev seismic.feed --params '{}' --watch # on this mac
649
761
  ```
650
762
 
651
763
  A space's own server code — tasks its actions run as steps, routes under `/fn/` — and `src/functions/` is a working copy
652
- of it: `.plitzi/functions.json` keeps what was pulled, so `pull` refuses to overwrite what is not pushed (`--force`
653
- throws it away) and `push` refuses when the space moved on since. A problem comes back as
764
+ of it: `.plitzi/functions.json` keeps what was pulled, so `functions pull` refuses to overwrite what is not pushed (`--force`
765
+ throws it away) and `functions push` refuses when the space moved on since. A problem comes back as
654
766
  `src/functions/<file>:<line> <message>`. `dev` runs with the project's own `@plitzi/sdk-server` (`isolated-vm` and
655
767
  `core-js` beside it); credentials come from `PLITZI_FUNCTIONS_CREDENTIALS`. See `docs/en/functions.md`.
656
768
 
@@ -667,7 +779,8 @@ for a clone to copy and fill in. A server project's `.env` is read as each scrip
667
779
  `node --import @plitzi/sdk-server/env` (Node's flag there has its watcher restart on every write in the project) —
668
780
  before any of its modules is evaluated, so `src/config/serverOptions.ts` and the actions find their settings in
669
781
  `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
782
+ no file. `start:prod` also sets `NODE_ENV=production` itself — without it a deployed server is a development one, its
783
+ dev tools on and every action's trace in what a visitor is answered (`doctor` says a `start:prod` that does not). A browser
671
784
  project's is Vite's: only `VITE_*` reaches the page, and ships in it.
672
785
  `create` gives each one a signing key there, made for it: `PLITZI_SIGNING_SECRET`, what `ctx.sign` and `ctx.verify`
673
786
  sign with — at least 32 characters (`doctor --fix` writes one where it is missing). `PORT` is left commented out: 8080,