@plitzi/plitzi-builder 0.38.14 → 0.38.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,198 @@
1
1
  # @plitzi/plitzi-builder
2
2
 
3
+ ## 0.38.16
4
+
5
+ ### Patch Changes
6
+
7
+ - 9cfdccb: ## Security
8
+
9
+ - **A site's credential reads nothing of the space over MCP** (`@plitzi/sdk-mcp`): the `render` token every published
10
+ page embeds — and a self-hosting `host` key — resolved to a grant naming the space, and the MCP served every read
11
+ under it: the unpublished draft, the change history with who made each change and every value before and after, the
12
+ functions' source, the space's private data, its action documents and connectors. Only an `agent` grant attaches a
13
+ space now; any other is a connection with no space (`plitzi_render` and the public guides), told so in the words
14
+ `NO_SPACE_ATTACHED` already uses. A deployment whose `getGrant` answered other scopes for reading must issue agent
15
+ grants for them.
16
+
17
+ ## Agents
18
+ - **`plitzi space watch`** (`@plitzi/cli`): the space read again on every save of `src/space/`, `src/plugins/`,
19
+ `src/data/` or `public/data/`, and only what changed said — what the save did to the space element by element, the
20
+ findings and warnings it brought and fixed (one that only moved down its file is the same one), a save that changed
21
+ nothing, or that the space stopped authoring and why. `--json` is one event a line (`ready`, `pass`, `refused`,
22
+ `error`), for an agent to run in the background instead of `author` and `space lint` after every edit. Each pass reads
23
+ the space in a process of its own (`space watch-pass`, hidden). `space lint`'s reading is `spaceFindings`, shared.
24
+ - **A space's activity, followed** (`@plitzi/sdk-shared`, `@plitzi/sdk-mcp`, `@plitzi/cli`): what happened on a space
25
+ after a cursor — its draft changed (a person in the builder, an agent, the autofix), a version went out, a server
26
+ action failed or was refused — and, with nothing yet, waited for, up to 50 s. One vocabulary,
27
+ `@plitzi/sdk-shared/activity` (`SpaceActivity`, `SpaceActivityPage`, `activityLine`, `isSpaceActivityPage`, the
28
+ limits); the reader's own writes left out and counted (`skippedMine`), `mine` keeps them.
29
+ - **`plitzi_activity { after, wait, limit, mine }`** (`@plitzi/sdk-mcp`), on the new `getActivity` adapter
30
+ (`SSRAdapters`). The listing budget is 78k (was 77k) for it.
31
+ - **`plitzi space activity [--follow] [--after <cursor>] [--mine] [--limit <n>] [--json]`** (`@plitzi/cli`), over
32
+ the platform's `GET /spaces/:spaceId/activity`; `--follow` stays, one page a line with `--json`, and asks again
33
+ when the platform does not answer.
34
+ - **The people in the builder see the agent work** (`@plitzi/sdk-server`, `@plitzi/sdk-shared`, `@plitzi/sdk-mcp`,
35
+ `@plitzi/plitzi-builder`): an agent grant carries the application the member connected (`Grant.client`,
36
+ `StoredSpaceToken.client`, `SSRGrant.client`), and every MCP write `SSRWriteContext.client` — the history's
37
+ `client` for an agent, which was never set. A collaborator may be an agent (`SubscriptionCollaborator.agent`): the
38
+ builder draws it as a robot, names it `Claude · for ana` (`collaboratorTitle`) in the header, on the canvas and in
39
+ its notices. The deployment announces it — Plitzi's joins it on a write, selects what it changed, and lets it go
40
+ after a minute of nothing. `activityLine` names it the same way (`Claude for ana over the MCP, …`), so
41
+ `plitzi space activity` says which application wrote.
42
+ - A tool may declare `documents: false` (`ToolSpec`): the host loads none of the space for it, and passes the call's
43
+ abort signal through `ToolContext.activity`.
44
+
45
+ ## Authoring
46
+ - **A file that does not parse is said at its line under any loader** (`@plitzi/sdk-authoring`): `moduleProblem` read
47
+ the first line of the error, and an esbuild transform (tsx, vitest) puts only `Transform failed with 1 error:` there
48
+ — the file, line and what is wrong are on the next. A line of the message that points at a file of the project is
49
+ now the problem (`src/space/hero.ts:139: Expected "}" but found ";"`), the project's root matched as given and as it
50
+ is on disk (`/var/…` and `/private/var/…` on macOS).
51
+
52
+ ## Testing
53
+ - **`unusedPort` is chosen where the system never hands one out** (`@plitzi/sdk-server`): it answered a port the system
54
+ had just handed out (`listen(0)`), from the ephemeral range every outgoing connection takes its local port from — so
55
+ another worker's request could take it before the test listened, and CI failed `runtime.test.ts` with `EADDRINUSE`
56
+ (the page server then ends the process). It is a free port below that range now, at random, checked first.
57
+
58
+ ## Docs
59
+ - **A self-hosted runtime's endpoints go in `data`**, as 0.38.15 moved them: `docs/en/runtimes.md`, the
60
+ `10-runtime` example and the website still put `served.stage` in `preAuth`, before the cross-site guard.
61
+ - New: `docs/en/activity.md`; `space watch` in `docs/en/agent-tooling.md`'s loop; the CLI README, the CLI skill, the
62
+ generated project's `AGENTS.md`, the MCP guide and README.
63
+
64
+ - Updated dependencies [9cfdccb]
65
+ - @plitzi/plitzi-sdk@0.38.16
66
+ - @plitzi/sdk-auth@0.38.16
67
+ - @plitzi/sdk-authoring@0.38.16
68
+ - @plitzi/sdk-dev-tools@0.38.16
69
+ - @plitzi/sdk-elements@0.38.16
70
+ - @plitzi/sdk-event-bridge@0.38.16
71
+ - @plitzi/sdk-interactions@0.38.16
72
+ - @plitzi/sdk-navigation@0.38.16
73
+ - @plitzi/sdk-plugins@0.38.16
74
+ - @plitzi/sdk-schema@0.38.16
75
+ - @plitzi/sdk-shared@0.38.16
76
+ - @plitzi/sdk-style@0.38.16
77
+ - @plitzi/sdk-variables@0.38.16
78
+
79
+ ## 0.38.15
80
+
81
+ ### Patch Changes
82
+
83
+ - 6cdd5cf: ## Security
84
+
85
+ - **A write another site caused is refused, cookie or none** (`@plitzi/sdk-server`, `@plitzi/sdk-shared`): the page
86
+ server guarded nothing it answers past `/auth` — a server action (`/_action`), a realtime publish, a space's `/fn/`
87
+ route, its runtime's endpoints, the deployment's own `data` stages, the adapter-only `loginPath`, `logoutPath` and
88
+ `exchangePath`. A plain `text/plain` POST from any page open in the same browser ran them, with the visitor's session
89
+ cookie when there was one (`SameSite=None` off this machine) and, in a project nobody signs in to, as whoever holds
90
+ the server's own credentials. Every unsafe request a browser says another site caused (`Sec-Fetch-Site: cross-site`,
91
+ or a foreign `Origin`) is now refused `403 reason: 'foreign'`, saying how to allow it: `crossSiteWrites.origins`
92
+ (with `auth`, `identity.platformOrigins` too) and `crossSiteWrites.paths` for a form other sites post to by design.
93
+ `Authorization`, and callers that are not browsers — webhooks, scripts — pass as before. One rule for this and the
94
+ sign-in check (`crossSiteRequest`, `csrf.ts`). A self-hosted runtime's endpoints now sit where the platform forwards a
95
+ space's — after the auth chain and this guard (`data`, was `preAuth`).
96
+
97
+ ## Testing
98
+ - **`page check` and `page shot` anywhere the project is served** (`@plitzi/cli`): `--url <origin>` for a second server
99
+ of it, staging or a deploy, instead of `npm start`'s port; `page check --space <module>` holds the pages to that space
100
+ instead of the project's — an agent's page — authored with `authorIsolated`.
101
+ - **A route with a query is checked as its page** (`@plitzi/cli`): `page check "/?v=2"` matched the query as part of
102
+ the path, found no page, and checked the space's "not found" page in its place.
103
+
104
+ - **What an element that chooses its children draws is checked** (`@plitzi/sdk-authoring`, `@plitzi/cli`): with
105
+ `choosesChildren`, the page checks owed none of its children — and checked none of them either: a dashboard drawing
106
+ three panels reported `checked: 1`. Each child it may draw, and what is inside one under no condition of its own,
107
+ now carries `shownWith` (the child it comes with) on its handle: once that child is on screen it and everything
108
+ named in it are owed like the rest of the page, and `checked` counts them. `onScreenIfChosen(handles, page)` lists
109
+ them.
110
+ - **A page that met a server error is looked at once more** (`@plitzi/cli`): `page check` and `verify` failed a page
111
+ for a `500` from somebody else's service having a bad second (`/fn/<space>/weather`), and passed on the next run with
112
+ nothing changed. A page whose requests got a `5xx` is checked again once; its report is the second look, and says
113
+ what failed the first time (`retriedAfter`). A `4xx` fails the same way twice, and is never retried.
114
+
115
+ ## Plugins
116
+ - **`useNotify`** (`@plitzi/plitzi-sdk`): a plugin shows the page's notifications — `notify('Deleted 79 recordings', {
117
+ appearance: 'danger' })` — the same toasts an `addNotification` step shows, in the space's theme and `notifications`
118
+ look, with no trigger, flow or `window` event of the space's to wire. The step's vocabulary (`NOTIFICATION_PLACEMENTS`,
119
+ `NOTIFICATION_APPEARANCES`, `NOTIFICATION_DEFAULTS`) is one list in `@plitzi/sdk-shared`, read by both.
120
+ - **`appearance: 'danger'` looks like one** (`@plitzi/plitzi-sdk`): it reached the toast library as a type it does not
121
+ know, so a danger notification showed neither the error icon nor the colour `notifications.danger` sets.
122
+ A value a notification does not take — from a flow, or a plugin in plain JavaScript — is set aside by name and said
123
+ in the console, rather than shown as the default in silence (`readNotificationOptions`, `@plitzi/sdk-shared`).
124
+ - **`useServerAction`** (`@plitzi/plitzi-sdk`, `@plitzi/sdk-authoring`, `@plitzi/sdk-interactions`,
125
+ `@plitzi/sdk-server`): a plugin runs one of the space's server actions, awaited —
126
+ `useServerAction<typeof habitDone>('habits-done')({ id })` answers `{ ok, output }` or `{ ok: false, reason, error }`
127
+ — through the `runServerAction` step itself: the same access, refusals, session handling and dev-tools entry.
128
+ `defineAction` keeps the literal types of its `call` way in, so the input is typed by the fields it declares (the
129
+ required ones required); `taskAction` types both ends from the task's `run`, and `FunctionTask<T, R>` takes what
130
+ `run` answers. `CallInputOf` / `CallOutputOf` read them. One operation is one action, never a `case` in one route.
131
+ What a run answers is typed (`ServerActionStatus`): a status the server never uses reads as a run that did not
132
+ complete, never as one that did.
133
+ The key those types ride under (`CALL_TYPES`) is exported, by `@plitzi/sdk-shared` and `@plitzi/sdk-authoring` with
134
+ `TypedActionEntry`, `CallInputOf` and `CallOutputOf`: a package that emits declarations could not write the type of an
135
+ action it exports (`TS4023` on every `export const actions = [defineAction(…)]`).
136
+ - **A plugin is drawn on the server first** (docs): a preference per device belongs in kept state (`keepState`,
137
+ `paintedState`) as a bound prop, never read from `localStorage` while rendering — React discards the whole tree on the
138
+ mismatch, and only in the browser of whoever saved something. `@plitzi/plitzi-ui` is not the page's: a plugin
139
+ importing it bundles its own copy, with its own contexts and its own look. The authoring skill's `plugin-reach.md`
140
+ says what a plugin says and to whom: a notification, another element (an event and the space's flow), a server
141
+ action, shared state, other pages.
142
+
143
+ ## Realtime
144
+ - **A channel that retains** (`@plitzi/sdk-shared`, `@plitzi/sdk-server`, `@plitzi/sdk-elements`): declared
145
+ `retain: true` (with `publish: 'server'`, which authoring requires), the server keeps the latest message of each type
146
+ on a topic — said by `ctx.publish` or a flow's `realtime.publish` — and hands them to every page that joins, marked
147
+ `retained`. A page reads them as `<channel>.retained.<type>`, a plugin as `useChannel(topic).retained`, the newest of
148
+ a type holding whichever order they arrive in; `null` forgets a type. Kept in the store the actions' `kv` uses (beside
149
+ the grants, by compare-and-swap), so every replica hands out the same; a topic keeps at most 64 types and 512 KB, and
150
+ a publish past that is refused before anything is sent. State every screen shares is one publish and one binding —
151
+ no kv key, initial read or copy in `state` of the project's own. The fleet store `realtime.grants` is now
152
+ `realtime.kv`.
153
+ - **The MCP writes every field a channel takes** (`@plitzi/sdk-mcp`): `patchSettings`'s channel had no `grant` — which
154
+ the guide taught — nor `retain` or the limits, so an agent could not declare a private channel at all. All are there
155
+ now, and the guide says what `retain` is for and that `channel_<id>.retained` holds it.
156
+
157
+ ## Authoring
158
+ - **`plitzi explain` knows every `@plitzi` package installed** (`@plitzi/cli`): a name that was not
159
+ `@plitzi/sdk-authoring`'s (`createServer`, `createJsonAdapters`, `useChannel`) was answered as the project's own code,
160
+ to `grep` in `src/`. It is read from the published types of every one installed, through their re-exports and entry
161
+ points (`@plitzi/sdk-server/handlers`), and a name two packages export — `createServer` is sdk-server's and sdk-mcp's
162
+ — is answered with both.
163
+
164
+ - **A space module somebody else wrote, authored where it reaches nothing** (`@plitzi/sdk-authoring`):
165
+ `authorIsolated(file, { timeoutMs })` of `@plitzi/sdk-authoring/node` runs `authorSpace` on it in a process Node's
166
+ permission model holds to reading the module's folder and its packages — no file written, no process started, no
167
+ variable of the caller's environment — kills one that runs too long, and validates what it answers again, so a forged
168
+ answer gains nothing. A refusal comes back as `authorSpace` says it, with the problems as data.
169
+ - **Pages an agent writes, served** (`@plitzi/sdk-server`): `createAuthoringHost({ dir, frameAncestors })` serves each
170
+ space it is handed at an address of its own (`put(space, { id }) → /?__pt=<id>`) as a draft of its one space, kept in
171
+ `dir` across restarts; `drop(id)` forgets one, and anything else answers `404` saying where the pages are.
172
+ - **A space is chosen by host or credential** (`@plitzi/sdk-server`, docs): `getSpaceDeployment` is asked on every
173
+ request, and what a page fetches after it carries nothing of its address but the host — a space chosen by the page's
174
+ query or path lost everything it asked for, and `/_plitzi/space/<hash>.json` answered a bare `404`. The contract and
175
+ the README say so (the README offered "by path prefix"), and that `404` says why.
176
+
177
+ - **`plitzi explain on` says how to read what a trigger carries** (`@plitzi/sdk-authoring`): its doc sat above a
178
+ helper, so `explain` printed only the signature. It now leads with `[named('picked', on('onPick')), …('{{ picked.seat
179
+ }}')]`, and the CLI skill's plugin section says the same.
180
+
181
+ - Updated dependencies [6cdd5cf]
182
+ - @plitzi/plitzi-sdk@0.38.15
183
+ - @plitzi/sdk-auth@0.38.15
184
+ - @plitzi/sdk-authoring@0.38.15
185
+ - @plitzi/sdk-dev-tools@0.38.15
186
+ - @plitzi/sdk-elements@0.38.15
187
+ - @plitzi/sdk-event-bridge@0.38.15
188
+ - @plitzi/sdk-interactions@0.38.15
189
+ - @plitzi/sdk-navigation@0.38.15
190
+ - @plitzi/sdk-plugins@0.38.15
191
+ - @plitzi/sdk-schema@0.38.15
192
+ - @plitzi/sdk-shared@0.38.15
193
+ - @plitzi/sdk-style@0.38.15
194
+ - @plitzi/sdk-variables@0.38.15
195
+
3
196
  ## 0.38.14
4
197
 
5
198
  ### Patch Changes
@@ -1,4 +1,4 @@
1
- import { SubscriptionCollaboratorElementState } from '@plitzi/sdk-shared';
1
+ import { SubscriptionCollaborator, SubscriptionCollaboratorElementState } from '@plitzi/sdk-shared';
2
2
  /**
3
3
  * The coordinate protocol between collaborators, both ends of it in one place.
4
4
  *
@@ -51,3 +51,8 @@ declare const resolveElementState: (elementState: SubscriptionCollaboratorElemen
51
51
  selected: string | undefined;
52
52
  };
53
53
  export { collaboratorAnchorSelector, readCursorAnchor, resolveCursorPosition, resolveElementState };
54
+ /**
55
+ * What a collaborator is called on the canvas, in the header and in the notices: a person by their name, an agent by
56
+ * its application and whom it works for (`Claude · for ana`).
57
+ */
58
+ export declare const collaboratorTitle: ({ user, agent }: Pick<SubscriptionCollaborator, "user" | "agent">) => string;
@@ -4,7 +4,10 @@ export type CollaboratorAvatarProps = {
4
4
  color?: string;
5
5
  firstName: string;
6
6
  surName: string;
7
+ /** An agent writing over the MCP: drawn as one, not as a person's initials. */
8
+ agent?: boolean;
9
+ title?: string;
7
10
  };
8
- /** The collaborator's initials in their presence color, as shown in the app header. */
9
- declare const CollaboratorAvatar: ({ ref, color, firstName, surName }: CollaboratorAvatarProps) => import('react').JSX.Element;
11
+ /** The collaborator's initials in their presence color, as shown in the app header — or, for an agent, a robot. */
12
+ declare const CollaboratorAvatar: ({ ref, color, firstName, surName, agent, title }: CollaboratorAvatarProps) => import('react').JSX.Element;
10
13
  export default CollaboratorAvatar;
@@ -1,6 +1,6 @@
1
1
  declare const _default: {
2
2
  "name": "@plitzi/plitzi-builder",
3
- "version": "0.38.14",
3
+ "version": "0.38.16",
4
4
  "homepage": "./",
5
5
  "license": "AGPL-3.0",
6
6
  "files": [