You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: AGENTS.md
+9Lines changed: 9 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -211,9 +211,18 @@ Callouts (`> [!NOTE]`, `> [!TIP]`, `> [!INFO]`, `::: tip`, etc.) interrupt the r
211
211
212
212
Trim filler intros, redundant cross-links (one link per page is enough - sidebars handle navigation), and code samples that demonstrate more than the point being made. Lead each page with one sentence that says what the reader can build with this. Strip out promises about future work, marketing language ("powerful", "seamless"), and exposition that the surrounding code already conveys.
213
213
214
+
### 4. Guides teach, references list
215
+
216
+
The docs separate learning material from lookup material, following the [Divio documentation system](https://docs.divio.com/documentation-system/):
217
+
218
+
-**Guide pages (`docs/content/1.guide/`) are learning-oriented** - prose, code examples, and explanation. A lookup table (definition fields, options, enums, statuses, event names, route tables) belongs on a references page, with the guide keeping a one-or-two-sentence prose summary of the essentials plus a link to the reference section. Comparison and decision tables ("X vs Y", trade-off matrices) are explanation and stay in the guides; navigational link tables stay on `index.md` pages.
219
+
-**The references section (`docs/content/8.references/`) holds the lookup tables**, grouped: [Node-Side API](docs/content/8.references/4.node-api.md), [Browser-Side API](docs/content/8.references/5.browser-api.md), and [Hub API](docs/content/8.references/6.hub-api.md), alongside the terms, when-clauses, and events pages. Each reference section opens with one line naming what the table lists and linking the guide page that teaches it. A new lookup table goes into the matching reference page (and the references `index.md`), not into a guide.
220
+
-**The adapters, frameworks, helpers, and plugins sections are per-package reference pages** - each page is the reference for its own adapter/kit/package, so its options and RPC tables stay in place.
Own a CLI framework (commander, yargs, oclif)? Use the three factories `createCac` wraps against one `DevframeDefinition`: `createDevServer` (`devframe/adapters/dev`), `createBuild` (`devframe/adapters/build`), and `createMcpServer` (`devframe/adapters/mcp`) — see the [CLI adapter](/adapters/cac#use-your-own-cli-framework).
|`connection`| Connection prepared by `setupDevframeConnection()`. |
63
-
|`baseURL`| Mount path to probe for `__connection.json` (array = fallback). Default `'./'` (relative to `document.baseURI`); use an absolute path (`'/__devframe/'`) from outside the SPA. |
64
-
|`authToken`| Override the auth token (default: a locally-persisted id). |
65
-
|`cacheOptions`|`true` for default caching, or an options object. |
66
-
|`callTimeout`| Ms before a pending `rpc.call` rejects with a `'timeout'``DevframeConnectionError`; `0`/omit = wait forever. |
|`connectionMeta`| Descriptor that skips the `__connection.json` fetch. |
60
+
`baseURL` points at the mount path to probe for `__connection.json` (default `'./'`, relative to `document.baseURI`); `connection` adopts one prepared by `setupDevframeConnection()`. The rest cover auth (`authToken`), [caching](#caching) (`cacheOptions`), timeouts (`callTimeout`), transport hooks (`wsOptions`), `birpc` passthrough (`rpcOptions`), and discovery override (`connectionMeta`) — every option is in the [Browser-Side API reference](/references/browser-api#connectdevframe-options).
|`rpc:is-trusted:updated`| Trust granted, denied, or revoked. Carries the new `isTrusted` boolean. |
264
-
|`connection:status`| The [connection status](#handling-connection-and-auth-errors) changes. Carries `(status, previous)`. |
265
-
|`connection:error`| A connection-level failure — socket error or trust refused. Carries the `Error`. |
266
-
|`rpc:error`| An `rpc.call` rejects, from the node side or a down connection. Carries `(error, method)`. |
250
+
Four events arrive over `rpc.events`: `rpc:is-trusted:updated` when trust is granted, denied, or revoked; `connection:status` when the [connection status](#handling-connection-and-auth-errors) changes; `connection:error` on a connection-level failure; and `rpc:error` when an `rpc.call` rejects. Payloads are in the [Browser-Side API reference](/references/browser-api#rpc-client-events).
`rpc.status` collapses transport and trust into one value; `rpc.connectionError` holds the last connection-level `Error` (`null` when healthy):
284
-
285
-
| Status | Meaning |
286
-
|--------|---------|
287
-
|`connecting`| Establishing socket / handshake. Calls queue until open. |
288
-
|`connected`| Socket open and trusted; calls are served. |
289
-
|`unauthorized`| Socket open, trust refused. Prompt for [authentication](#authenticating-with-a-one-time-code). |
290
-
|`disconnected`| Socket closed (dropped mid-session or never opened). |
291
-
|`error`| Fatal — the socket errored or connection meta couldn't load. |
267
+
`rpc.status` collapses transport and trust into one value; `rpc.connectionError` holds the last connection-level `Error` (`null` when healthy). It moves through `connecting` (calls queue until open), `connected` (calls are served), `unauthorized` (socket open, trust refused — prompt for [authentication](#authenticating-with-a-one-time-code)), `disconnected`, and `error`; each value's meaning is in the [Browser-Side API reference](/references/browser-api#connection-statuses).
292
268
293
269
A `static` backend has no live socket, so `rpc.status` stays `connected`.
Copy file name to clipboardExpand all lines: docs/content/1.guide/12.in-page-channel.md
+1-10Lines changed: 1 addition & 10 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -123,16 +123,7 @@ Without an `initialValue`, a panel's `get` resolves once the first replay arrive
123
123
124
124
## Errors and fallbacks
125
125
126
-
Every failure mode is a coded `InPageChannelError` (`error.code`) with a message that explains itself:
127
-
128
-
| Code | When | What to do |
129
-
|------|------|------------|
130
-
|`timeout`| A call outlived `callTimeoutMs` (default 15s), or `whenConnected(ms)` expired | The message carries the endpoint status — `connecting` usually means the page script isn't loaded in this context |
131
-
|`closed`| The endpoint was closed with calls pending | Expected during teardown |
132
-
|`not-serializable`| A `jsonSerializable: true` payload contained a non-JSON value | The message names the offending path (e.g. `its arguments[0].nodes[2]` is a Map) |
133
-
|`not-cloneable`| The port refused to clone a payload (`DataCloneError`) | Strip functions/DOM nodes/reactivity proxies — or declare `jsonSerializable: true` for the precise error above |
134
-
|`invalid-args`| Incoming arguments failed their Standard-Schema validation | The message lists the schema issues |
135
-
|`state-uninitialized`| The page script read a shared state before providing its `initialValue`| Initialize on first access |
126
+
Every failure mode is a coded `InPageChannelError` (`error.code`) with a message that explains itself: `timeout` (a call or `whenConnected(ms)` outlived its deadline), `closed` (endpoint torn down with calls pending), `not-serializable` / `not-cloneable` (a payload the port can't carry — the message names the offending path), `invalid-args` (Standard-Schema validation failed), and `state-uninitialized` (a shared state read before its `initialValue`). Causes and fixes per code are in the [Browser-Side API reference](/references/browser-api#in-page-channel-error-codes).
136
127
137
128
The panel endpoint's connection lifecycle is explicit, so a panel renders a useful fallback instead of hanging:
Copy file name to clipboardExpand all lines: docs/content/1.guide/14.security.md
+3-16Lines changed: 3 additions & 16 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -51,22 +51,9 @@ Pass `clientAuthTokens` for CI/shared machines to skip the prompt, or a custom `
51
51
52
52
### Auth methods
53
53
54
-
| RPC method | Direction | Shape |
55
-
|------------|-----------|-------|
56
-
|`anonymous:devframe:auth`| client → server |`{ authToken, ua, origin }` → `{ isTrusted }` — re-authenticate a stored token |
57
-
|`anonymous:devframe:auth:exchange`| client → server |`{ code, ua, origin }` → `{ authToken \| null }` — exchange a code for a token |
58
-
|`devframe:auth:revoke`| client → server | self-revoke the caller's own token |
59
-
|`devframe:auth:revoked`| server → client | event — token revoked |
60
-
61
-
Node primitives (`devframe/node/auth`):
62
-
63
-
| Function | Role |
64
-
|----------|------|
65
-
|`getTempAuthCode()` / `refreshTempAuthCode()`| read / rotate the one-time code |
66
-
|`exchangeTempAuthCode(code, session, { ua, origin }, storage)`| verify a code, mint + store the token, trust the session, return it (or `null`) |
67
-
|`verifyAuthToken(token, session, storage)`| trust a session presenting a known token |
68
-
|`buildOtpAuthUrl(origin, code?)`| build a magic-link URL embedding the code |
69
-
|`revokeAuthToken(context, storage, token)`| delete a token and disconnect sessions using it |
54
+
The two `anonymous:`-prefixed handshake methods re-authenticate a stored token (`anonymous:devframe:auth`) and exchange a one-time code for a token (`anonymous:devframe:auth:exchange`); `devframe:auth:revoke` self-revokes, and the `devframe:auth:revoked` event drops affected RPC clients to untrusted. Wire shapes are in the [Node-Side API reference](/references/node-api#auth-methods).
55
+
56
+
Node primitives in `devframe/node/auth` — `getTempAuthCode` / `refreshTempAuthCode`, `exchangeTempAuthCode`, `verifyAuthToken`, `buildOtpAuthUrl`, and `revokeAuthToken` — implement the same flow for a host framework wiring its own gate; signatures are in the [reference](/references/node-api#node-auth-primitives).
70
57
71
58
RPC client methods (`devframe/client`): `requestTrustWithCode(code)`, `requestTrustWithToken(token)`, and `ensureTrusted(timeout?)` / `isTrusted` (the trust gate).
Copy file name to clipboardExpand all lines: docs/content/1.guide/15.agent-native.md
+1-5Lines changed: 1 addition & 5 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -183,8 +183,4 @@ Prefer coded diagnostics anywhere agent-reachable: agents act on `fix` and follo
183
183
184
184
## CLI
185
185
186
-
| Command | Description |
187
-
|---------|-------------|
188
-
|`<your-app> mcp`| Start the MCP server on `stdio`. |
189
-
|`<your-app> dev --mcp`| Serve the agent-consumable API on `/__mcp`. |
190
-
|`devframe connect`| Discover running devframes and proxy their tools — see [MCP adapter](/adapters/mcp#discovery-devframe-connect). |
186
+
`<your-app> mcp` starts the MCP server on `stdio`; `<your-app> dev --mcp` serves the agent-consumable API on `/__mcp`; `devframe connect` discovers running devframes and proxies their tools ([MCP adapter](/adapters/mcp#discovery-devframe-connect)). The command table is in the [Node-Side API reference](/references/node-api#mcp-cli-commands).
`DevframeHubContext` adds four subsystems to `DevframeNodeContext`:
17
-
18
-
| Subsystem | API | Purpose |
19
-
|---|---|---|
20
-
|`ctx.docks`|`register / update / values / activate`| Dock entries (iframes, launchers, custom-render) and groups; `activate(dockId, params?)` sets the active dock ([Cross-iframe dock activation](#cross-iframe-dock-activation)). |
|`ctx.commands`|`register / execute / list`| Hierarchical command palette with keybindings and `when` clauses. |
16
+
`DevframeHubContext` adds four subsystems to `DevframeNodeContext`: `ctx.docks` registers dock entries and groups and [activates docks](#cross-iframe-dock-activation); `ctx.terminals` aggregates terminal sessions with streaming output ([Terminals](/plugins/terminals#hub-aggregation)); `ctx.messages` is the server-side toast/notification queue; `ctx.commands` is the hierarchical command palette with keybindings and `when` clauses. Each subsystem's API is in the [Hub API reference](/references/hub-api#hub-subsystems).
24
17
25
18
Data-driven UI panels are an opt-in [JSON-Render](/guide/json-render) package (a `json-render` dock type).
26
19
@@ -69,13 +62,7 @@ It mirrors into the `devframe:docks:active` shared-state slot; the [terminals do
69
62
70
63
## Process-control launchers
71
64
72
-
A `type: 'launcher'` dock entry is a one-click action tile. Three optional `launcher` fields make it a live process controller:
73
-
74
-
| Field | Purpose |
75
-
|---|---|
76
-
|`command`| Bound command id; out-of-process hub UI providers dispatch via `hub:commands:execute` (register a handler via `ctx.commands`). |
77
-
|`terminalSessionId`| Tracked session id; a "view in terminal" action calls `hub:docks:activate` with the terminals dock id and `{ sessionId }`. |
78
-
|`digest`| Latest progress line, shown inline; patch via `docks.update()`. |
65
+
A `type: 'launcher'` dock entry is a one-click action tile. Three optional `launcher` fields make it a live process controller: `command` binds a command id dispatched via `hub:commands:execute`, `terminalSessionId` links a tracked session for a "view in terminal" action, and `digest` shows the latest progress line inline ([Hub API reference](/references/hub-api#launcher-fields)).
79
66
80
67
`onLaunch` lets a same-process host framework invoke directly; provide `command`, `onLaunch`, or both.
When a devframe shares an already-mounted `id`, `duplicationStrategy` decides:
177
-
178
-
| Strategy | Behavior |
179
-
|---|---|
180
-
|`'warn'` (default) | Keep the first, drop the later, emit `DF8105`. |
181
-
|`'silent'`| Drop the later one without warning. |
182
-
|`'throw'`| Throw `DF8105`. |
183
-
|`'duplicate'`| Every instance coexists under a disambiguated dock id (`my-tool`, `my-tool-2`, …). |
163
+
When a devframe shares an already-mounted `id`, `duplicationStrategy` decides: `'warn'` (the default) keeps the first and drops the later with [`DF8105`](/errors/DF8105), `'silent'` drops it quietly, `'throw'` raises, and `'duplicate'` lets every instance coexist under disambiguated dock ids ([Hub API reference](/references/hub-api#duplication-strategies)).
184
164
185
165
```ts
186
166
defineDevframe({
@@ -222,35 +202,13 @@ Group and members stay independent top-level entries in `devframe:docks`. Activa
222
202
223
203
#### Known categories
224
204
225
-
`DEFAULT_CATEGORIES_ORDER` (from `@devframes/hub`, `/node`, `/client`, `/constants`) names the default buckets:
226
-
227
-
| Category | Weight | Typical use |
228
-
|---|---|---|
229
-
|`framework`|`-100`| Framework internals. |
230
-
|`default`|`0`| Uncategorized. |
231
-
|`app`|`100`| App tools. |
232
-
|`ui`|`150`| Components, styling. |
233
-
|`data`|`250`| State, storage, queries. |
234
-
|`web`|`300`| Network, platform, a11y. |
235
-
|`performance`|`350`| Profiling, metrics. |
236
-
|`advanced`|`400`| Power-user tools. |
237
-
|`docs`|`500`| Documentation. |
238
-
|`~builtin`|`1000`| Built-in views; always last. |
205
+
`DEFAULT_CATEGORIES_ORDER` (from `@devframes/hub`, `/node`, `/client`, `/constants`) names the default buckets, running from `framework` (weight `-100`) through `default`, `app`, `ui`, `data`, `web`, `performance`, `advanced`, and `docs` to `~builtin` (always last). The weight table is in the [Hub API reference](/references/hub-api#dock-categories).
239
206
240
207
Framework kits can interleave category ids or override weights; an unknown category sorts as `0`.
241
208
242
-
## The protocol — what the hub UI provider sees
243
-
244
-
A hub UI provider imports no hub classes; it reads these shared-state keys and RPC methods:
209
+
## The hub UI protocol
245
210
246
-
| Channel | Type | What it carries |
247
-
|---|---|---|
248
-
|`devframe:docks` shared state |`DevframeDockEntry[]`| Every registered dock entry. |
249
-
|`devframe:commands` shared state |`DevframeServerCommandEntry[]`| Serializable command list (handlers stripped). |
250
-
|`devframe:user-settings` shared state |`DevframeDocksUserSettings`| Persisted project-scope hub settings. |
251
-
|`devframe:docks:active` shared state |`DevframeDocksActiveState`| Most recent [dock activation](#cross-iframe-dock-activation) request. |
|`hub:docks:activate` RPC |`({ dockId, params? }) => void`| Switch the active dock. |
211
+
A hub UI provider imports no hub classes; it renders from four shared-state slots — `devframe:docks` (every registered dock entry), `devframe:commands` (the serializable command list), `devframe:user-settings` (persisted hub settings), and `devframe:docks:active` (the most recent [dock activation](#cross-iframe-dock-activation) request) — and dispatches through two RPC methods, `hub:commands:execute` and `hub:docks:activate`. Types and payloads are in the [Hub API reference](/references/hub-api#hub-ui-protocol).
254
212
255
213
Broadcast notifications (`devframe:docks:activate`, `devframe:terminals:updated`, `devframe:messages:updated`) arrive via `rpc.client.register(...)`; the client runtime registers `devframe:docks:activate` for you ([Events Reference](/references/events)).
0 commit comments