Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,7 @@ await createCli(devframe).parse()
|---------|----------|
| `cli` | Standalone CLI tool with `dev` / `build` / `mcp` subcommands. |
| `build` | Generates a static, self-contained SPA snapshot. |
| `vite` | Runs as a Vite plugin alongside the host app's dev server. |
| `kit` | Mounts into a DevTools Kit aggregator (e.g. `@vitejs/devtools-kit`). |
| `vite` | Mounts the devframe into Vite DevTools (or any compatible host) via `@vitejs/devtools-kit`. |
| `embedded` | Overlays inside another devframe's UI. |
| `mcp` | Surfaces the devframe's RPC to coding agents over MCP. |

Expand Down
2 changes: 1 addition & 1 deletion alias.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export const alias = {
'devframe/adapters/cli': r('devframe/src/adapters/cli.ts'),
'devframe/adapters/dev': r('devframe/src/adapters/dev.ts'),
'devframe/adapters/build': r('devframe/src/adapters/build.ts'),
'devframe/adapters/vite': r('devframe/src/adapters/vite.ts'),
'devframe/helpers/vite': r('devframe/src/helpers/vite.ts'),
'devframe/adapters/embedded': r('devframe/src/adapters/embedded.ts'),
'devframe/adapters/mcp': r('devframe/src/adapters/mcp.ts'),
'@devframes/nuxt/runtime/plugin.client': r('nuxt/src/runtime/plugin.client.ts'),
Expand Down
6 changes: 3 additions & 3 deletions docs/errors/DF0033.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ outline: deep

## Cause

`createVitePlugin({ devMiddleware })` could not bring up the bridge dev server that pairs a host-served SPA (Vite, Nuxt, Astro, etc.) with devframe's RPC backend. Common reasons:
`viteDevBridge({ devMiddleware })` could not bring up the bridge dev server that pairs a host-served SPA (Vite, Nuxt, Astro, etc.) with devframe's RPC backend. Common reasons:

- The preferred port is in use and no fallback range was configured.
- Calling `def.setup(ctx)` threw — the devframe's own setup logic surfaced an error.
Expand All @@ -20,10 +20,10 @@ This is a soft warning — the surrounding Vite dev server keeps running, but th

## Fix

- Pin a port via `cli.port` / `cli.portRange` on the devframe definition, or via `devMiddleware.port` on `createVitePlugin`.
- Pin a port via `cli.port` / `cli.portRange` on the devframe definition, or via `devMiddleware.port` on `viteDevBridge`.
- Inspect the `reason` (or the attached `cause`) for the underlying error — fix the setup function or free the port.
- For Nuxt: pass `devMiddleware: { port: <free-port> }` to the `@devframes/nuxt` module.

## Source

- [`packages/devframe/src/adapters/vite.ts`](https://github.com/vitejs/devtools/blob/main/devframe/packages/devframe/src/adapters/vite.ts) — `createVitePlugin({ devMiddleware })` logs `DF0033` when port resolution or `createDevServer` throws during `configureServer`.
- [`packages/devframe/src/helpers/vite.ts`](https://github.com/vitejs/devtools/blob/main/devframe/packages/devframe/src/helpers/vite.ts) — `viteDevBridge({ devMiddleware })` logs `DF0033` when port resolution or `createDevServer` throws during `configureServer`.
61 changes: 33 additions & 28 deletions docs/guide/adapters.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,8 @@ Every adapter factory has the shape `createXxx(devframeDef, options?)`.
|---------|-------|---------|----------|
| [`cli`](#cli) | `devframe/adapters/cli` | `createCli(def, options?)` | Standalone tools run via `node ./my-tool.js` |
| [`dev`](#dev) | `devframe/adapters/dev` | `createDevServer(def, options?)` | Run the dev server programmatically — drive it from any CLI framework |
| [`vite`](#vite) | `devframe/adapters/vite` | `createVitePlugin(def, options?)` | Mount a tool's UI inside an existing Vite dev server |
| [`build`](#build) | `devframe/adapters/build` | `createBuild(def, options?)` | Offline reports, CI artifacts, deployable SPA snapshots |
| [`kit`](#kit) | `@vitejs/devtools-kit/node` | `createPluginFromDevframe(def, options?)` | Integrating into Vite DevTools Kit |
| [`vite`](#vite) | `@vitejs/devtools-kit/node` | `createPluginFromDevframe(def, options?)` | Mount the definition into Vite DevTools (or any compatible host) |
| [`embedded`](#embedded) | `devframe/adapters/embedded` | `createEmbedded(def, { ctx })` | Runtime registration into an already-running host |
| [`mcp`](#mcp) | `devframe/adapters/mcp` | `createMcpServer(def, options?)` | Exposing a devframe to coding agents |

Expand Down Expand Up @@ -180,7 +179,7 @@ A devframe's SPA basePath depends on which adapter is running it:
| Adapter kind | Default basePath | Reason |
|--------------|------------------|--------|
| `cli`, `spa`, `build` (standalone) | `/` | The devframe owns the origin. |
| `vite`, `kit`, `embedded` (hosted) | `/__<id>/` | The devframe shares the origin with a host app and namespaces itself. |
| `vite`, `embedded` (hosted) | `/__<id>/` | The devframe shares the origin with a host app and namespaces itself. |

Override either side explicitly with `DevframeDefinition.basePath`:

Expand All @@ -194,26 +193,6 @@ defineDevframe({

SPA authors should build with relative asset paths (`vite.base: './'`); the client resolves its connection descriptor relative to the page at runtime. See [Client](./client#runtime-basepath-discovery) for the discovery rules.

## Vite

A thin Vite plugin that mounts a devframe's SPA into an existing Vite dev server as a *hosted* adapter — the mount path defaults to `/__<id>/` to namespace away from the app. The plugin mounts the SPA only; for RPC, use `kit` or `cli`.

```ts
import { createVitePlugin } from 'devframe/adapters/vite'
import { defineConfig } from 'vite'
import devframe from './devframe'

export default defineConfig({
plugins: [createVitePlugin(devframe)],
})
```

| Option | Default | Description |
|--------|---------|-------------|
| `base` | `def.basePath ?? '/__<id>/'` | Mount path inside the Vite dev server. |

Use this adapter when a devframe's UI is purely static and you want to surface it during Vite `serve` without shipping a separate dev server. Set `DevframeDefinition.basePath` on the definition for a custom path that stays consistent across adapters.

## Build

Produces a self-contained static deploy of a devframe:
Expand Down Expand Up @@ -252,9 +231,9 @@ When `def.spa` is set on the definition, `createBuild` also writes `spa-loader.j

Deployed SPAs that use `setupBrowser` ship their own client entry that registers the handlers.

## Kit
## Vite

Wraps a `DevframeDefinition` so Vite DevTools Kit's plugin-scan picks it up. The factory lives in `@vitejs/devtools-kit/node` — kit owns docking and process management while devframe stays portable.
The Vite-DevTools adapter — wraps a `DevframeDefinition` so Vite DevTools' kit plugin-scan picks it up. The factory lives in `@vitejs/devtools-kit/node` so devframe itself stays free of any Vite or `@vitejs/*` dependency. The pattern (`definition → host plugin → mount`) is general; other hosts can implement equivalent bridges.

```ts
import { createPluginFromDevframe } from '@vitejs/devtools-kit/node'
Expand All @@ -265,18 +244,18 @@ export default function myVitePlugin() {
}
```

The returned object has the shape `{ name, devtools: { setup, capabilities } }`. Use this adapter when your devframe should live inside the Vite DevTools dock alongside other integrations. Kit synthesises an iframe dock entry from the definition's `id` / `name` / `icon` / `basePath`; for richer kit-specific behaviour (extra terminals, commands, dock overrides) pass `options.setup`. See the [DevTools Kit → DevTools Plugin](https://devtools.vite.dev/kit/devtools-plugin) page for the Vite-specific guide.
The returned object has the shape `{ name, devtools: { setup, capabilities } }`. Use this adapter when your devframe should live inside the Vite DevTools dock alongside other integrations. The kit synthesises an iframe dock entry from the definition's `id` / `name` / `icon` / `basePath`; for richer host-side behaviour (extra terminals, commands, dock overrides) pass `options.setup`. See the [DevTools Kit → DevTools Plugin](https://devtools.vite.dev/kit/devtools-plugin) page for the Vite-specific guide.

| Option | Default | Description |
|--------|---------|-------------|
| `name` | `devframe:<id>` | Override the Vite plugin name. |
| `base` | `def.basePath ?? /.${id}/` | Mount path override. |
| `dock` | `{}` | Overrides for the synthesized iframe dock entry (category, icon, when). |
| `setup` | — | Additional kit-only setup hook; receives the kit-augmented context. |
| `setup` | — | Additional host-only setup hook; receives the kit-augmented context (Vite DevTools' `docks`, `terminals`, `messages`, `commands`). |

## Embedded

Register a devframe into an already-running context at runtime. Mirrors Kit's internal plugin-scan, but for callers that need dynamic, post-startup registration. The host decides the mount path; `embedded` is a hosted adapter and inherits the `/__<id>/` default when one is needed.
Register a devframe into an already-running context at runtime. Mirrors the `vite` adapter's plugin-scan, but for callers that need dynamic, post-startup registration. The host decides the mount path; `embedded` is a hosted adapter and inherits the `/__<id>/` default when one is needed.

```ts
import { createEmbedded } from 'devframe/adapters/embedded'
Expand Down Expand Up @@ -308,3 +287,29 @@ await createMcpServer(devframe, { transport: 'stdio' })
`@modelcontextprotocol/sdk` is a peer dependency — install it when shipping MCP support. The current transport is `stdio`.

See the [Agent-Native](./agent-native) page for the full API, safety model, and Claude Desktop integration example.

## Helpers

These are not adapters — they're small utilities for integrating devframe into specific runtimes outside the adapter list.

### `devframe/helpers/vite`

A thin Vite plugin for mounting a devframe inside an existing Vite dev server, used by `@devframes/nuxt` and available for any Vite-based host (Astro, SolidStart, plain Vite apps). Two modes:

- **Static mount** (default) — mounts `def.cli.distDir` at `options.base` (`/__<id>/` by default). No RPC server.
- **Bridge mode** (`devMiddleware: true | {…}`) — skips the static mount; the host app owns the SPA. Devframe spawns a separate RPC + WS server and registers Vite middleware at `<base>__connection.json` so the host-served SPA can discover the WS endpoint.

```ts
import { viteDevBridge } from 'devframe/helpers/vite'
import { defineConfig } from 'vite'
import devframe from './devframe'

export default defineConfig({
plugins: [viteDevBridge(devframe)],
})
```

| Option | Default | Description |
|--------|---------|-------------|
| `base` | `def.basePath ?? '/__<id>/'` | Mount path inside the Vite dev server. |
| `devMiddleware` | `false` | `true` or `{ port?, host?, flags? }` to enable bridge mode. |
4 changes: 2 additions & 2 deletions docs/guide/client.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ const ok = await rpc.requestTrustWithToken('another-token')

### Broadcast-channel sync

`connectDevframe` listens on `BroadcastChannel('vite-devtools-auth')` for `auth-update` messages. When an auth page in another tab announces a new token, every open client requests trust with it automatically — no reload required.
`connectDevframe` listens on a shared `BroadcastChannel` (named `vite-devtools-auth` for cross-tab handshake interop with Vite DevTools' auth page) for `auth-update` messages. When an auth page in another tab announces a new token, every open client requests trust with it automatically — no reload required.

## Calling functions

Expand Down Expand Up @@ -183,7 +183,7 @@ await connectDevframe({

## Remote docks

Remote docks are a kit-side feature (see [Vite DevTools Kit → Remote Client](https://devtools.vite.dev/kit/remote-client)). The kit injects a connection descriptor into the iframe URL; on the hosted page, `connectDevframe` auto-detects the descriptor from the URL fragment / query string — call it as usual:
Remote docks are a host-side feature — hosts that support them (Vite DevTools is one; see [its remote-client docs](https://devtools.vite.dev/kit/remote-client) for that implementation) inject a connection descriptor into the iframe URL. On the hosted page, `connectDevframe` auto-detects the descriptor from the URL fragment / query string — call it as usual:

```ts
import { connectDevframe } from 'devframe/client'
Expand Down
21 changes: 10 additions & 11 deletions docs/guide/devframe-definition.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ outline: deep

# Devframe Definition

Every Devframe tool starts with a single `defineDevframe` call. The returned `DevframeDefinition` is a portable value that any of the [adapters](./adapters) can consume — the same definition runs under `createCli`, `createBuild`, `createMcpServer`, kit's `createPluginFromDevframe`, and so on.
Every Devframe tool starts with a single `defineDevframe` call. The returned `DevframeDefinition` is a portable value that any of the [adapters](./adapters) can consume — the same definition runs under `createCli`, `createBuild`, `createMcpServer`, the `vite` adapter's `createPluginFromDevframe`, and so on.

## Minimal definition

Expand All @@ -28,7 +28,7 @@ export default defineDevframe({
})
```

When mounted into Vite DevTools via [`createPluginFromDevframe`](./adapters#kit), the dock entry and iframe mount are derived from `id`, `name`, `icon`, and `basePath` automatically. Hub-level features (`docks`, `terminals`, `messages`, `commands`) live on the kit-augmented context.
Host adapters (such as the [`vite` adapter](./adapters#vite) for Vite DevTools) derive their mount entry from `id`, `name`, `icon`, and `basePath` automatically.

## Definition fields

Expand All @@ -38,7 +38,7 @@ When mounted into Vite DevTools via [`createPluginFromDevframe`](./adapters#kit)
| `name` | `string` | **Required.** Display name shown in the dock and agent manifests. |
| `icon` | `string \| { light, dark }` | Optional Iconify name or URL; supports light/dark pairs. |
| `version` | `string` | Optional version string surfaced to clients. |
| `basePath` | `string` | Optional mount path override. Defaults depend on the adapter: `/` for standalone (`cli` / `spa` / `build`), `/.<id>/` for hosted (`vite` / `kit` / `embedded`). |
| `basePath` | `string` | Optional mount path override. Defaults depend on the adapter: `/` for standalone (`cli` / `spa` / `build`), `/.<id>/` for hosted (`vite` / `embedded`). |
| `capabilities` | `{ dev?, build?, spa? }` | Per-runtime feature flags. A `boolean` applies to the runtime as a whole; an object enables individual features. |
| `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 `createCli`. |
| `setupBrowser` | `(ctx) => void \| Promise<void>` | Browser-only entry used by the SPA adapter. |
Expand Down Expand Up @@ -84,14 +84,13 @@ interface DevToolsNodeContext {
}
```

Hub-level subsystems — `docks`, `terminals`, `messages`, `commands`, `createJsonRenderer` — live on the kit-augmented context owned by `@vitejs/devtools-kit`. A devframe app that wants to register kit-only behavior does so through the optional `setup` hook on `createPluginFromDevframe`.
Host adapters can augment `ctx` with additional surfaces. For example, the [`vite` adapter](./adapters#vite) exposes Vite DevTools' dock, command, message, and terminal hosts via an optional `setup` hook on `createPluginFromDevframe` — consult the host's docs for those extras.

Each host has a dedicated page:
Each devframe-level host has a dedicated page:
- [RPC](./rpc) — `ctx.rpc`
- [Shared State](./shared-state) — `ctx.rpc.sharedState`
- [Diagnostics](./diagnostics) — `ctx.diagnostics`
- [Agent-Native](./agent-native) — `ctx.agent`
- Hub-side surfaces — [Dock System](https://devtools.vite.dev/kit/dock-system), [Commands](https://devtools.vite.dev/kit/commands), [Messages](https://devtools.vite.dev/kit/messages), [Terminals](https://devtools.vite.dev/kit/terminals) — live in the [Vite DevTools Kit](https://devtools.vite.dev/kit/) docs.

## Browser setup

Expand Down Expand Up @@ -182,15 +181,15 @@ const devframe = defineDevframe({ id: 'my-devframe', name: 'My Devframe', setup(
// 1. Standalone CLI:
await createCli(devframe).parse()

// 2. Embedded in a Vite project (from `vite.config.ts`):
export const myPlugin = () => createPluginFromDevframe(devframe)

// 3. Offline snapshot:
// 2. Offline snapshot:
await createBuild(devframe, { outDir: 'dist-static' })

// 3. Mount into a host (Vite DevTools shown — other hosts can implement equivalents):
export const myPlugin = () => createPluginFromDevframe(devframe)
```

## What's next

- [Adapters](./adapters) — pick a deployment target
- [RPC](./rpc) — register server functions
- [Vite DevTools Kit](https://devtools.vite.dev/kit/) — mount your devframe into the multi-integration hub
- [`vite` adapter](./adapters#vite) — mount your devframe into Vite DevTools or another compatible host
Loading
Loading