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
+3-3Lines changed: 3 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -2,7 +2,7 @@
2
2
3
3
## Positioning
4
4
5
-
**`devframe`** is the framework-neutral container for one devtool integration, portable across viewers. Build a single tool (its RPC, its SPA, its diagnostics, its CLI/build/spa/embedded outputs) without caring how it'll be displayed. A devframe app runs standalone (CLI, static deploy, embedded SPA) just as well as it mounts inside a hub.
5
+
**`devframe`** is the framework-neutral container for one devtool integration, portable across viewers. Build a single tool (its RPC, its SPA, its diagnostics, its CLI/build/embedded outputs) without caring how it'll be displayed. A devframe app runs standalone (CLI, static deploy, embedded SPA) just as well as it mounts inside a hub.
6
6
7
7
**`@devframes/hub`** is the framework-neutral hub layer that sits on top of devframe and provides the multi-integration orchestration (docks, terminals, messages, commands). It does not ship UI - implementers (e.g. `@vitejs/devtools-kit`) provide their own UI on top of the hub's RPC + shared-state protocol. It does ship a **headless client runtime** (`createDevframeClientHost()` from `@devframes/hub/client`): booted in the host page, it assembles the shared `DevframeClientContext` (panel, docks, commands, when) and imports each dock entry's client script (`action` / `custom-render` / iframe `clientScript`) into that page - how a plugin like the a11y inspector runs code inside the page being inspected. See `examples/hub-vite/` for a working ~120-line Vite host demonstrating the protocol end to end.
8
8
@@ -79,8 +79,8 @@ These reinforce devframe's positioning as "the container for one devtool integra
79
79
80
80
-**Single-integration scope.** Devframe describes one tool. If a feature only makes sense when multiple tools share a UI - docking, a unified command palette, cross-tool toasts, terminal aggregation - it belongs in a hub package, not here.
81
81
-**Headless by default.** No default startup banners, no opinionated logging to stdout, no default styling. Provide hooks (`onReady`, `cli.configure`, etc.); let the application print its own branding. Structured diagnostics via `nostics` are fine - ad-hoc `console.log`s baked into adapters are not.
82
-
-**Mount path depends on adapter context.** Given `id: 'foo'`, the default mount path is `/__foo/` for *hosted* adapters (`vite`, `embedded`) and `/` for *standalone* adapters (`cli`, `spa`, `build`). Authors override via `DevframeDefinition.basePath`. Don't hardcode mount paths in adapter code paths that may run standalone.
83
-
-**SPAs own their basePath at runtime.** Build SPAs with relative asset paths (`vite.base: './'`); discover the effective base in the browser from the executing script's location / `document.baseURI`. `createBuild`/ `createSpa` copy SPA output verbatim - no HTML rewriting, no build-time `--base` injection. The client (`connectDevframe`) resolves `.connection.json` relative to the runtime base automatically.
82
+
-**Mount path depends on adapter context.** Given `id: 'foo'`, the default mount path is `/__foo/` for *hosted* adapters (`vite`, `embedded`) and `/` for *standalone* adapters (`cli`, `build`). Authors override via `DevframeDefinition.basePath`. Don't hardcode mount paths in adapter code paths that may run standalone.
83
+
-**SPAs own their basePath at runtime.** Build SPAs with relative asset paths (`vite.base: './'`); discover the effective base in the browser from the executing script's location / `document.baseURI`. `createBuild`copies SPA output verbatim - no HTML rewriting, no build-time `--base` injection. The client (`connectDevframe`) resolves `.connection.json` relative to the runtime base automatically.
84
84
-**CLI flags compose from both sides.** The `cac` instance backing `createCac` is exposed both to the `DevframeDefinition` (`cli.configure(cli)`) - for capabilities contributed by the tool itself - and to the `createCac` caller - for flags added at the final assembly stage. Parsed flag values are forwarded to `setup(ctx, { flags })`. Never hardcode domain-specific flags into `createCac`.
Copy file name to clipboardExpand all lines: docs/adapters/build.md
+1-11Lines changed: 1 addition & 11 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -10,32 +10,22 @@ Produces a self-contained static deploy of a devframe:
10
10
2. Runs `setup(ctx)` with `mode: 'build'`.
11
11
3. Collects RPC dumps for every `'static'` function and any `'query'` function with `dump.inputs` / `snapshot: true`.
12
12
4. Writes `<outDir>/__connection.json` (`{ backend: 'static' }`) and sharded dump files under `<outDir>/__rpc-dump/` — both at the SPA root so the deployed client discovers them via relative paths from `document.baseURI`.
13
-
5. When `def.spa` is set, also writes `<outDir>/spa-loader.json` describing how the SPA hydrates its data.
|`outDir`|`dist-static`| Output directory. Cleared on each build. |
28
-
|`base`|`/`| Absolute URL base the output is served from. |
29
26
|`distDir`|`def.cli?.distDir`| Override the SPA dist directory. |
27
+
|`pretty`|`false`| Pretty-print dump JSON (larger on disk). |
30
28
31
29
The resulting directory hosts on any static web server (`serve`, nginx, GitHub Pages, …). The client auto-detects `static` mode by resolving `./__connection.json` against `document.baseURI` and runs in read-only form.
32
30
33
31
`createBuild` copies the SPA verbatim, so deploying under a custom URL base just means building the SPA with relative asset paths (`vite.base: './'`) — the client discovers the effective base at runtime.
34
-
35
-
When `def.spa` is set on the definition, `createBuild` also writes `spa-loader.json` next to `index.html` describing how the deployed SPA sources its data:
36
-
37
-
-`'none'` — use the baked RPC dump only (read-only static view).
38
-
-`'query'` — hydrate from URL search params.
39
-
-`'upload'` — accept a drag-and-drop file.
40
-
41
-
Deployed SPAs that use `setupBrowser` ship their own client entry that registers the handlers.
Copy file name to clipboardExpand all lines: docs/adapters/cac.md
+2-2Lines changed: 2 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -4,7 +4,7 @@ outline: deep
4
4
5
5
# CLI (cac)
6
6
7
-
The cac adapter wraps a `DevframeDefinition` in a [`cac`](https://github.com/cacjs/cac)-powered command-line interface. From one entry it spins up an `h3` dev server with WebSocket RPC, builds static snapshots, builds SPA bundles, or starts an MCP server.
7
+
The cac adapter wraps a `DevframeDefinition` in a [`cac`](https://github.com/cacjs/cac)-powered command-line interface. From one entry it spins up an `h3` dev server with WebSocket RPC, builds static snapshots, or starts an MCP server.
8
8
9
9
`cac` is an optional peer dependency, pulled in only through this adapter — install it alongside `devframe` to opt into `createCac`:
10
10
@@ -68,7 +68,7 @@ defineDevframe({
68
68
id: 'my-devframe',
69
69
cli: {
70
70
command: 'my-devframe', // binary name; default: the id
71
-
distDir: './client/dist', // required for dev/build/spa
71
+
distDir: './client/dist', // required for dev/build
72
72
port: 7777, // preferred port
73
73
portRange: [7777, 9000], // passed through to get-port-please
74
74
random: false, // passed through to get-port-please
> "`{id}`" declares `capabilities.dev: false` — it does not support a live dev server (its value is a static export only).
10
+
11
+
## Cause
12
+
13
+
`createDevServer` runs unconditionally when called directly, but a definition can opt out of the live dev server via `capabilities.dev: false` — for a devframe whose value is inherently static (e.g. a report generator with nothing to serve live), a dev server would only ever produce an empty or misleading surface. This diagnostic covers a caller invoking `createDevServer()` directly.
14
+
15
+
## Example
16
+
17
+
```ts
18
+
// ✗ Bad — starts a dev server for a devframe that opted out of it
- Pass `{ force: true }` to `createDevServer()` to run it anyway.
28
+
- Otherwise, drop `capabilities.dev: false` on the definition if a live dev server should be supported after all.
29
+
30
+
## Source
31
+
32
+
-[`packages/devframe/src/adapters/dev.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/adapters/dev.ts) — `createDevServer()` throws this when `capabilities.dev` is `false` and `force` isn't set.
Copy file name to clipboardExpand all lines: docs/examples/built-with.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -12,6 +12,6 @@ Real-world devframes:
12
12
13
13
End-to-end examples in this repo, exercising the full adapter surface:
14
14
15
-
-[**files-inspector**](https://github.com/devframes/devframe/tree/main/examples/files-inspector) — lists files in cwd via RPC; exercises CLI dev/build/spa surfaces.
15
+
-[**files-inspector**](https://github.com/devframes/devframe/tree/main/examples/files-inspector) — lists files in cwd via RPC; exercises CLI dev/build surfaces.
16
16
-[**streaming-chat**](https://github.com/devframes/devframe/tree/main/examples/streaming-chat) — streams synthetic chat tokens from server to client via `ctx.rpc.streaming`.
17
17
-[**next-runtime-snapshot**](https://github.com/devframes/devframe/tree/main/examples/next-runtime-snapshot) — Next.js App Router SPA over RPC, surfacing the host Node runtime (system info, memory, env).
Copy file name to clipboardExpand all lines: docs/examples/index.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -8,7 +8,7 @@ End-to-end examples that exercise the full adapter surface, each a runnable app
8
8
9
9
| Example | UI framework | What it shows |
10
10
|---------|--------------|---------------|
11
-
|[files-inspector](./files-inspector)| Preact | Lists files in the cwd via RPC; exercises the CLI dev / build / spa surfaces. |
11
+
|[files-inspector](./files-inspector)| Preact | Lists files in the cwd via RPC; exercises the CLI dev / build surfaces. |
12
12
|[json-render](./json-render)| Vue | A server-authored JSON-render view rendered by `@devframes/json-render-ui`, with live state and an action bridge. |
13
13
|[streaming-chat](./streaming-chat)| Preact | Streams synthetic chat tokens server → client, with history kept in shared state. |
14
14
|[next-runtime-snapshot](./next-runtime-snapshot)| React (Next.js) | A Next.js App Router SPA over RPC, surfacing the host Node runtime. |
|`homepage`|`string`|**Required.** Project homepage or documentation URL. |
49
49
|`description`|`string`|**Required.** One-line summary of what the tool does. |
50
50
|`icon`|`string \| { light, dark }`| Optional Iconify name or URL; supports light/dark pairs. |
51
-
|`basePath`|`string`| Optional mount path override. Defaults depend on the adapter: `/` for standalone (`cli` / `spa` / `build`), `/.<id>/` for hosted (`vite` / `embedded`). |
51
+
|`basePath`|`string`| Optional mount path override. Defaults depend on the adapter: `/` for standalone (`cli` / `build`), `/.<id>/` for hosted (`vite` / `embedded`). |
52
52
|`duplicationStrategy`|`'warn' \| 'silent' \| 'throw' \| 'duplicate'`| How a hub reacts when another devframe sharing this `id` is mounted onto the same hub. Defaults to `'warn'`. See [Hub](./hub). Hub adapters consult it; standalone adapters ignore it. |
53
-
|`capabilities`|`{ dev?, build?, spa? }`| Per-runtime feature flags. A `boolean` applies to the runtime as a whole; an object enables individual features. |
53
+
|`capabilities`|`{ dev?, build? }`| Per-runtime feature flags. A `boolean` applies to the runtime as a whole; an object enables individual features. |
54
54
|`setup`|`(ctx, info?) => void \| Promise<void>`|**Required.** Server-side entry point. Runs in every runtime. The optional second argument carries runtime metadata — most notably the parsed CLI `flags` when running under `createCac`. |
55
-
|`setupBrowser`|`(ctx) => void \| Promise<void>`| Browser-only entry used by the SPA adapter. |
56
55
|`cli`|`DevframeCliOptions`| Defaults for the CLI adapter. See [CLI options](#cli-options) below. |
57
-
|`spa`|`DevframeSpaOptions`| Defaults for the SPA adapter (`base`, `loader`). |
58
56
59
57
### Sourcing metadata from `package.json`
60
58
@@ -171,23 +169,6 @@ Each devframe-level host has a dedicated page:
The SPA adapter supports a `setupBrowser(ctx)` hook that runs inside the deployed client bundle. Use it for tools that perform their own in-browser work — parsing a dropped file, calling public APIs from the client, etc.
177
-
178
-
```ts
179
-
defineDevframe({
180
-
id: 'my-devframe',
181
-
name: 'My Devframe',
182
-
setup(ctx) { /* server-side */ },
183
-
setupBrowser(ctx) {
184
-
// `ctx.rpc` is the write-disabled static client in SPA mode.
185
-
},
186
-
})
187
-
```
188
-
189
-
Deployed SPAs that use `setupBrowser` ship their own client entry that registers the handlers.
190
-
191
172
## CLI options
192
173
193
174
`cli` configures the CLI adapter's defaults and plugs additional flags/commands into the CAC instance:
@@ -198,7 +179,7 @@ defineDevframe({
198
179
name: 'My Devframe',
199
180
cli: {
200
181
command: 'my-devframe', // binary name; default: the `id`
201
-
distDir: './client/dist', // required for dev / build / spa
182
+
distDir: './client/dist', // required for dev / build
202
183
port: 9876, // preferred port; default: 9999
203
184
portRange: [9876, 10000], // forwarded to get-port-please
204
185
random: false, // forwarded to get-port-please
@@ -220,7 +201,7 @@ defineDevframe({
220
201
| Field | Type | Description |
221
202
|-------|------|-------------|
222
203
|`command`|`string`| Binary name surfaced in `--help`. Default: the definition's `id`. |
|`distDir`|`string`| SPA dist directory. **Required** for `dev` / `build`. |
224
205
|`port`|`number`| Preferred port for the dev server. |
225
206
|`portRange`|`[number, number]`| Port scan range, passed through to `get-port-please`. |
226
207
|`random`|`boolean`| Prefer a random open port. |
@@ -231,18 +212,6 @@ defineDevframe({
231
212
232
213
`setup(ctx, info)` receives `info.flags` populated from both devframe's built-in flags and any you declared via `configure` — saves duplicating flag parsing.
233
214
234
-
## SPA options
235
-
236
-
```ts
237
-
defineDevframe({
238
-
id: 'my-devframe',
239
-
spa: {
240
-
base: '/',
241
-
loader: 'query', // 'query' | 'upload' | 'none'
242
-
},
243
-
})
244
-
```
245
-
246
215
See [Adapters](/adapters/) for how each adapter consumes these.
Copy file name to clipboardExpand all lines: docs/guide/index.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -15,7 +15,7 @@ Devframe keeps its surface focused on one tool, so the same definition stays por
15
15
-**One tool per definition.** A devframe describes a single integration. Deploy it through any adapter; host-level features that only matter when several tools share a UI (palettes, cross-tool toasts, unified terminals) come from whichever host you mount into — Vite DevTools is one example.
16
16
-**Headless.** Hook into `onReady`, `cli.configure`, and friends to print your own startup banners and styling — Devframe stays out of the way.
17
17
-**App-owned file watching.** Wire your own watcher (chokidar, fs.watch, …) and signal change via `ctx.rpc.sharedState.set(...)` or event-typed RPCs.
18
-
-**Context-aware mount paths.** Standalone adapters (`cli`, `spa`, `build`) serve at `/` by default; hosted adapters (`vite`, `embedded`) serve at `/.<id>/`. Override via `DevframeDefinition.basePath`.
18
+
-**Context-aware mount paths.** Standalone adapters (`cli`, `build`) serve at `/` by default; hosted adapters (`vite`, `embedded`) serve at `/.<id>/`. Override via `DevframeDefinition.basePath`.
19
19
-**SPAs own their base at runtime.** Build with relative asset paths (`vite.base: './'`); `connectDevframe` discovers the effective base from the executing script's location.
20
20
-**CLI flags compose.** The `cac` instance is exposed to both the devframe (`cli.configure`) and the caller of `createCac`, so capability flags and app flags merge cleanly.
0 commit comments