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
1 change: 0 additions & 1 deletion alias.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,6 @@ export const alias = {
'@devframes/plugin-terminals': p('terminals/src/node/index.ts'),
'@devframes/plugin-git': p('git/src/node/index.ts'),
'devframe/recipes/interactive-auth': r('devframe/src/recipes/interactive-auth.ts'),
'devframe/recipes/common-rpc-functions': r('devframe/src/recipes/common-rpc-functions.ts'),
'devframe/client': r('devframe/src/client/index.ts'),
'devframe': r('devframe/src'),
'@devframes/plugin-data-inspector/inject': p('data-inspector/src/inject/index.ts'),
Expand Down
2 changes: 1 addition & 1 deletion docs/content/1.guide/12.in-page-channel.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ Channel names are namespaced with the devframe id, like RPC ids. Function names

The required `functions` option and optional `events` option declare every incoming name on the endpoint's protocol side; use `{}` for an empty direction. Functions require a `handler`. Events accept an optional `handler`, and `{}` registers an event for runtime subscriptions through `on()`. Handlers are contextually typed from the shared protocol and support Standard-Schema argument validation and `jsonSerializable` metadata. `defineChannelFunction` retains the named definition shape for lower-level authoring.

`call()` accepts names from `functions`, including actions returning `void` or `Promise<void>`: callers can await completion and catch errors or timeouts. `emit()`, its deprecated alias `callEvent()`, and `on()` use the names declared in `events`. Function and event names have separate namespaces.
`call()` accepts names from `functions`, including actions returning `void` or `Promise<void>`: callers can await completion and catch errors or timeouts. `emit()` and `on()` use the names declared in `events`. Function and event names have separate namespaces.

```ts
import type { MyChannelProtocol } from '../shared/protocol'
Expand Down
2 changes: 1 addition & 1 deletion docs/content/1.guide/18.hub-initiate.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ Registrations are validated fail-fast: one module per type (`DF8108`), an existi

The hub's **single Auth** is one gate at the shared transport for every mounted devframe, built-ins, and the MCP route; one handshake (OTP, magic link, or pre-shared token) unlocks the namespace; `auth: false` disables it for localhost.

The aggregate MCP route mounts through the `'auto'` default once any mounted devframe (or an agent-flagged hub command) exposes agent tools; `mcp: true` forces it on, `mcp: false` off. It has its own origin gate, independent of this RPC Auth: the mounted route trusts same-machine callers, and `mcp: { authorization }` adds an identity check when the hub is reachable beyond loopback. A mounted devframe's own `mcp` setting is ignored: the hub exposes one aggregate route over them all, and warns ([`DF8005`](/errors/DF8005)) when a devframe asks for MCP while the hub set `mcp: false`.
The aggregate MCP route mounts through the `'auto'` default once any mounted devframe (or an agent-flagged hub command) exposes agent tools; `mcp: true` forces it on, `mcp: false` off. It has its own origin gate, independent of this RPC Auth: the mounted route trusts same-machine callers, and `mcp: { authorization }` adds an identity check when the hub is reachable beyond loopback. The hub exposes one aggregate route over every mounted devframe's tools.

## Singular vs hub mounting

Expand Down
2 changes: 1 addition & 1 deletion docs/content/1.guide/6.client-assets.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export default defineDevframe({

devframe serves it with SPA fallback (unknown paths → `index.html`) and no-store dev caching. Build the SPA with a relative base (`vite: { base: './' }`); it reads its runtime base from `document.baseURI`.

The [`dev`](/adapters/dev), [`build`](/adapters/build), and [Vite](/frameworks/vite) adapters share `clientAssets`; the deprecated `cli.distDir` is a fallback when it's unset.
The [`dev`](/adapters/dev), [`build`](/adapters/build), and [Vite](/frameworks/vite) adapters all read `clientAssets`.

## Programmatic hosting from `setup`

Expand Down
2 changes: 1 addition & 1 deletion docs/content/2.adapters/3.dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ Returns a `StartedServer`: origin, port, h3 app, WS server, RPC group, `close()`
| `host` | `def.cli?.host ?? 'localhost'` | Bind host. |
| `port` | resolved via `resolveDevServerPort` | Listen port. |
| `flags` | `{}` | To `setup(ctx, { flags })`. |
| `distDir` | `def.clientAssets` (falls back to deprecated `def.cli?.distDir`) | SPA dist; unset = bridge mode. |
| `distDir` | `def.clientAssets` | SPA dist; unset = bridge mode. |
| `basePath` | `resolveBasePath(def, 'standalone')` | Mount override. |
| `app` | fresh h3 app | Mount onto. |
| `openBrowser` | resolves from `flags.open` / `def.cli?.open` | `false` off; string opens a path. |
Expand Down
4 changes: 2 additions & 2 deletions docs/content/5.add-ons/1.devframes/4.a11y.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,10 @@ The hub serves the bundle same-origin and a client runtime imports it into the h
A host can also mount the module itself, for example a Vite host via `/@fs/`:

```ts
import createA11yDevframe, { a11yPageScriptBundlePath } from '@devframes/plugin-a11y'
import createA11yDevframe, { a11yClientScriptBundlePath } from '@devframes/plugin-a11y'

await ctx.install(createA11yDevframe(), {
dock: { clientScript: { importFrom: `/@fs/${a11yPageScriptBundlePath}` } },
dock: { clientScript: { importFrom: `/@fs/${a11yClientScriptBundlePath}` } },
})
```

Expand Down
33 changes: 0 additions & 33 deletions docs/content/6.errors/DF8005.md

This file was deleted.

1 change: 0 additions & 1 deletion docs/content/6.errors/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,6 @@ Emitted by `@devframes/hub` while assembling and mounting the unified surface.
| [DF8002](/errors/DF8002) | error | Both devframes and context Passed to initHub |
| [DF8003](/errors/DF8003) | error | connectionMeta() Before Hub Instance Ready |
| [DF8004](/errors/DF8004) | error | Devframe Id Is Not a Mountable URL Segment |
| [DF8005](/errors/DF8005) | warning | Devframe MCP Ignored While Hub MCP Is Off |

## Hub: docks & mounting (DF81xx)

Expand Down
18 changes: 18 additions & 0 deletions docs/content/7.migrations/1.migration-0.10.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,21 @@ npm install @devframes/agentic
```

Code that imported SDK types directly for devframe's MCP options no longer needs to: the full option surface is typed on `devframe/adapters/mcp` and `devframe/types` without any SDK types.

## Removed deprecated APIs

0.10 drops the symbols deprecated during the 0.9 line. Each has a drop-in replacement:

| Removed | Use instead |
| ------- | ----------- |
| `cli.mcp` on a definition | Pass `mcp` to the host (`createCac` / `--mcp`, `createDevServer`, `initDevframe`, `initHub`) |
| `cli.distDir` on a definition | Top-level `clientAssets` on the definition |
| `resolveClientAssets` (from `devframe`) | Read `definition.clientAssets` directly |
| `createDevframeClientHost`, `DevframeClientHost`, `DevframeClientHostOptions` (`@devframes/hub/client`) | `createDevframeClientRuntime`, `DevframeClientRuntime`, `DevframeClientRuntimeOptions` |
| `coerceAgentPositionalArgs`, `AgentArgsFallback` (`devframe/internal`) | `toolInputToRpcArgs` / `toolInputToCommandArgs` |
| `openInEditor`, `openInFinder`, `commonRpcFunctions` (`devframe/recipes/common-rpc-functions`) | The [`@devframes/service-open`](/add-ons/services/open) wire service |
| `callEvent()` on an in-page channel | `emit()` |
| `a11yPageScriptBundlePath`, `a11yAgentBundlePath` (`@devframes/plugin-a11y`) | `a11yClientScriptBundlePath` |
| `AGENT_DISCOVERY_FILE`, `AgentDiscovery`, `DataInspectorAgent` (`@devframes/plugin-data-inspector/inject`) | `DISCOVERY_FILE`, `InjectDiscovery`, `DataInspectorEndpoint` |

Dropping `cli.mcp` also removes the hub's `DF8005` warning: a hub's aggregate MCP route already covers every mounted devframe's tools, so a per-devframe MCP request no longer exists to conflict with it.
2 changes: 1 addition & 1 deletion docs/content/8.references/5.browser-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ The values of `rpc.status`: [Handling connection and auth errors](/guide/client#

The browser-only endpoint methods of the [in-page channel](/guide/in-page-channel). `emit()` sends to the opposite endpoint; `on()` handles events arriving from that endpoint.

`InPageChannelProtocol` separates `functions` and `events`. Each section has optional `pageScript` and `panel` maps naming the receiving direction. Endpoint options require a complete `functions` map with handlers; `events` is optional, and when provided can include optional handlers (use `{}` to declare an event without a handler for `channel.on()`). `call()` uses function names regardless of return type, while `emit()`, `callEvent()` (deprecated), and `on()` use event names. A function returning `void` or `Promise<void>` remains an awaitable request/response call.
`InPageChannelProtocol` separates `functions` and `events`. Each section has optional `pageScript` and `panel` maps naming the receiving direction. Endpoint options require a complete `functions` map with handlers; `events` is optional, and when provided can include optional handlers (use `{}` to declare an event without a handler for `channel.on()`). `call()` uses function names regardless of return type, while `emit()` and `on()` use event names. A function returning `void` or `Promise<void>` remains an awaitable request/response call.

| Method or property | Page-script endpoint | Panel endpoint |
|--------------------|-------------|-------|
Expand Down
2 changes: 1 addition & 1 deletion examples/demo-dock-client/src/node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ import { fileURLToPath } from 'node:url'
* (`dist/bundle.mjs`, nanoevents inlined). A host without bare-specifier
* resolution mounts this file's directory statically and passes the served
* URL as the dock's `importFrom`, the same pattern as
* `@devframes/plugin-a11y`'s `a11yPageScriptBundlePath`.
* `@devframes/plugin-a11y`'s `a11yClientScriptBundlePath`.
*/
export const demoDockClientBundlePath: string = fileURLToPath(new URL('./bundle.mjs', import.meta.url))
14 changes: 4 additions & 10 deletions knip.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,7 @@
"ignoreIssues": {
"plugins/*/src/node/index.ts": ["duplicates"],
"plugins/*/src/index.ts": ["duplicates"],
"services/*/src/index.ts": ["duplicates"],
// Deprecated rename aliases (old name re-exported next to its canonical
// replacement, kept for back-compat until the next major): the terms-page
// renames left `createDevframeClientHost` → `createDevframeClientRuntime`
// and `AGENT_DISCOVERY_FILE` → `DISCOVERY_FILE` aliases behind.
"packages/hub/src/client/host.ts": ["duplicates"],
"plugins/data-inspector/src/inject/index.ts": ["duplicates"]
"services/*/src/index.ts": ["duplicates"]
},
"workspaces": {
".": {
Expand Down Expand Up @@ -142,7 +136,7 @@
"src/internal/index.ts",
"src/node/index.ts",
"src/node/{auth,hub-internals}/index.ts",
"src/recipes/{common-rpc-functions,interactive-auth}.ts",
"src/recipes/interactive-auth.ts",
"src/rpc/{index,client,server}.ts",
"src/rpc/dump/index.ts",
"src/rpc/transports/{sse-client,sse-server,ws-bun,ws-deno,ws-client,ws-server}.ts",
Expand Down Expand Up @@ -207,7 +201,7 @@
},
"plugins/inspect": {
// The lockstep assets package is referenced only as a runtime string
// (`${pkg.name}--assets` in `cli.distDir`), never imported, so knip
// (`${pkg.name}--assets` in `clientAssets`), never imported, so knip
// can't see the dev-only workspace link that makes it resolvable in
// the monorepo. Repeat the `plugins/*` entry glob (a workspace config
// replaces, not merges, it).
Expand All @@ -225,7 +219,7 @@
"project": []
},
// Each plugin's lockstep `--assets` package is referenced only as a
// runtime string (`${pkg.name}--assets` in `cli.distDir`), never imported,
// runtime string (`${pkg.name}--assets` in `clientAssets`), never imported,
// so knip can't see the dev-only workspace link. A workspace config
// replaces (not merges) the `plugins/*` glob's `entry`, so repeat it.
"plugins/og": {
Expand Down
2 changes: 1 addition & 1 deletion packages/agentic/src/connect/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ const INDEX_TOOL = toAgentToolName('devframe:connect:list-instances')
const CALL_TOOL = toAgentToolName('devframe:connect:call-tool')

const MCP_DISABLED_HINT
= 'This instance runs without an MCP route. Restart it with the --mcp flag (or set `cli.mcp: true` on its definition) to expose its tools, then list instances again.'
= 'This instance runs without an MCP route. Restart it with the --mcp flag to expose its tools, then list instances again.'

const GATEWAY_TOOLS: Tool[] = [
{
Expand Down
1 change: 0 additions & 1 deletion packages/devframe/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
"./node": "./dist/node/index.mjs",
"./node/auth": "./dist/node/auth.mjs",
"./node/hub-internals": "./dist/node/hub-internals.mjs",
"./recipes/common-rpc-functions": "./dist/recipes/common-rpc-functions.mjs",
"./recipes/interactive-auth": "./dist/recipes/interactive-auth.mjs",
"./rpc": "./dist/rpc/index.mjs",
"./rpc/client": "./dist/rpc/client.mjs",
Expand Down
8 changes: 3 additions & 5 deletions packages/devframe/src/adapters/_shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,9 +124,8 @@ export async function loadAutoMcpAdapter(

/**
* Resolve the `mcp` entry a `__connection.json` should advertise for a dev
* server started with the given `mcp` option (falling back to `def.cli?.mcp`,
* exactly like `createDevServer`), or `undefined` when the route is
* disabled. `'auto'` (the omitted default) resolves at mount time against
* server started with the given `mcp` option, or `undefined` when the route
* is disabled. `'auto'` (the omitted default) resolves at mount time against
* the live agent surface, so hand-rolled meta advertises it only for an
* explicit setting; the adapters advertise the actually-mounted route
* themselves.
Expand All @@ -138,11 +137,10 @@ export async function loadAutoMcpAdapter(
* same-server default).
*/
export function resolveMcpConnectionMeta(
def: DevframeDefinition,
mcp: McpSetting | undefined,
port?: number,
): ConnectionMeta['mcp'] {
const config = resolveMcpConfig(mcp ?? def.cli?.mcp)
const config = resolveMcpConfig(mcp)
if (!config)
return undefined
const route = withoutLeadingSlash(config.path ?? DEVFRAME_MCP_ROUTE)
Expand Down
8 changes: 3 additions & 5 deletions packages/devframe/src/adapters/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import process from 'node:process'
import { colors as c } from 'devframe/utils/colors'
import { resolveStaticAssetsSource } from 'devframe/utils/remote-assets'
import { resolve } from 'pathe'
import { resolveClientAssets } from '../client-assets'
import {
DEVFRAME_CONNECTION_META_FILENAME,
DEVFRAME_RPC_DUMP_MANIFEST_FILENAME,
Expand All @@ -25,9 +24,8 @@ export interface CreateBuildOptions {
/**
* Override the SPA dist to copy into `outDir`: a local directory or a
* remote-assets declaration (materialized in full at build time). When
* omitted the adapter reads `devframe.clientAssets` (or the deprecated
* `devframe.cli?.distDir`); authors typically set this once on the
* definition itself.
* omitted the adapter reads `devframe.clientAssets`; authors typically set
* this once on the definition itself.
*/
distDir?: StaticAssetsSource
/**
Expand Down Expand Up @@ -61,7 +59,7 @@ export async function createBuild(d: DevframeDefinition, options: CreateBuildOpt
throw diagnostics.DF0042({ id: d.id })

const outDir = resolve(options.outDir ?? 'dist-static')
const distSource = options.distDir ?? resolveClientAssets(d)
const distSource = options.distDir ?? d.clientAssets
if (!distSource)
throw new Error(`[devframe] createBuild: no client assets for "${d.id}". Set \`clientAssets\` on the definition or pass it as an option.`)

Expand Down
13 changes: 6 additions & 7 deletions packages/devframe/src/adapters/cac.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,8 @@ export interface CreateCacOptions {
* Expose a route-based MCP server alongside the dev server, speaking the
* MCP Streamable-HTTP transport at `<base>__mcp`. Whether to expose MCP is
* a hosting decision made at the CLI assembly stage, so it lives here rather
* than on the definition. When unset, falls back to the definition's
* deprecated `cli.mcp`, then to the `'auto'` default (mount once the agent
* surface is non-empty). See {@link McpSetting}.
* than on the definition. When unset, falls back to the `'auto'` default
* (mount once the agent surface is non-empty). See {@link McpSetting}.
*
* The `--mcp` / `--no-mcp` flags override this per run.
*/
Expand Down Expand Up @@ -82,8 +81,8 @@ export function createCac(d: DevframeDefinition, options: CreateCacOptions = {})
// Only `--mcp` is declared: CAC's `--no-*` auto-negation would inject a
// `true` default, forcing the route on. Declaring just `--mcp` keeps the
// tri-state: absent → `undefined` (falls through to `options.mcp`, then
// `cli.mcp`, then the `'auto'` default), `--mcp` → `true` (mount
// unconditionally), `--no-mcp` → `false` (handled by CAC's `--no-` prefix).
// the `'auto'` default), `--mcp` → `true` (mount unconditionally),
// `--no-mcp` → `false` (handled by CAC's `--no-` prefix).
.option('--mcp', 'Force the MCP route on (use --no-mcp to disable; default mounts it once agent tools exist)')

// Register typed flags from the definition ahead of `cli.configure`
Expand All @@ -107,8 +106,8 @@ export function createCac(d: DevframeDefinition, options: CreateCacOptions = {})
const port = (flags.port as number | undefined) ?? await resolveDevServerPort(d, { host, defaultPort })
// `--mcp` / `--no-mcp` map to a boolean override; when neither is passed
// CAC leaves `mcp` undefined so we fall back to the assembly-stage
// `options.mcp`, and `createDevServer` falls through to `def.cli?.mcp`,
// then to the `'auto'` default.
// `options.mcp`, and `createDevServer` falls through to the `'auto'`
// default.
const mcp = (flags.mcp as boolean | undefined) ?? options.mcp
await createDevServer(d, {
host,
Expand Down
8 changes: 4 additions & 4 deletions packages/devframe/src/adapters/dev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export interface CreateDevServerOptions {
*/
flags?: Record<string, unknown>
/**
* Override the definition's `clientAssets` (or deprecated `cli.distDir`).
* Override the definition's `clientAssets`.
* When neither this option nor the definition's client assets are set, the
* dev server runs in **bridge mode**: only `__connection.json` and the WS
* endpoint are mounted; the SPA is expected to be hosted elsewhere (e.g. by
Expand Down Expand Up @@ -92,9 +92,9 @@ export interface CreateDevServerOptions {
auth?: boolean | DevframeAuthHandler
/**
* Expose a route-based MCP server on the dev server (Streamable-HTTP).
* Overrides `def.cli?.mcp`; `undefined` falls through to it, then to the
* `'auto'` default (mount once the agent surface is non-empty). `false`
* disables the route regardless. See {@link McpSetting}.
* `undefined` falls through to the `'auto'` default (mount once the agent
* surface is non-empty). `false` disables the route regardless. See
* {@link McpSetting}.
*/
mcp?: McpSetting
/**
Expand Down
Loading
Loading