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
2 changes: 0 additions & 2 deletions alias.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ export const alias = {
'devframe/utils/structured-clone': r('devframe/src/utils/structured-clone.ts'),
'devframe/utils/when': r('devframe/src/utils/when.ts'),
'devframe/adapters/cac': r('devframe/src/adapters/cac.ts'),
'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/helpers/vite': r('devframe/src/helpers/vite.ts'),
Expand Down Expand Up @@ -80,7 +79,6 @@ export const alias = {
'@devframes/plugin-git': p('git/src/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/recipes/open-helpers': r('devframe/src/recipes/open-helpers.ts'),
'devframe/client': r('devframe/src/client/index.ts'),
'devframe': r('devframe/src'),
'@devframes/plugin-data-inspector/client': p('data-inspector/src/client/index.ts'),
Expand Down
2 changes: 2 additions & 0 deletions docs/.vitepress/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,8 @@ export function devframeNav(prefix = ''): DefaultTheme.NavItem[] {
{ text: 'Contributing', link: `${repo}/blob/main/CONTRIBUTING.md` },
{
items: [
{ text: 'Migrating to 0.9', link: `${prefix}/guide/migration-0.9` },
{ text: 'Migrating to 0.8', link: `${prefix}/guide/migration-0.8` },
{ text: 'Migrating to 0.7', link: `${prefix}/guide/migration-0.7` },
{ text: 'Migrating to 0.6', link: `${prefix}/guide/migration-0.6` },
],
Expand Down
2 changes: 0 additions & 2 deletions docs/adapters/cac.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@ const devframe = defineDevframe({
await createCac(devframe).parse()
```

The `devframe/adapters/cli` entry (`createCli`) remains as a deprecated alias for this module — new code should import `createCac` from `devframe/adapters/cac`.

Running the resulting binary:

```sh
Expand Down
78 changes: 78 additions & 0 deletions docs/guide/migration-0.8.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
---
outline: deep
---

# Migrating to 0.8

0.8 makes RPC schemas validator-neutral and validated at runtime, upgrades the MCP adapter to `@modelcontextprotocol/sdk` v2, and lands the agent-native MCP surface (`ctx.agent`, tool providers, and the `devframe connect` connector). This page covers the changes between 0.7.x and 0.8 — see the [v0.8.0 release notes](https://github.com/devframes/devframe/releases/tag/v0.8.0) for the full changelog.

## RPC schemas are Standard Schema and validated at runtime

`args` and `returns` on `defineRpcFunction` are now typed against [Standard Schema](https://standardschema.dev/) rather than valibot's `GenericSchema`. Any Standard-Schema-compliant validator works — valibot, zod, arktype — so existing valibot schemas keep compiling and inferring types unchanged.

Two things change in practice:

**Devframe no longer bundles a validator.** `valibot` was dropped from `devframe`'s runtime dependencies, so author your schemas with whichever validator you prefer and install it yourself:

```sh
npm install valibot # or: zod / arktype
```

If your app already pulls in zod (the JSON-render integration and the MCP server both use it), prefer zod for your RPC schemas and reuse the dependency. For first-party code that wants zero dependencies, devframe ships a minimal built-in builder at `devframe/utils/simple-schema`:

```ts
// Bring your own validator …
import { defineRpcFunction } from 'devframe'
import * as v from 'valibot'

export const rename = defineRpcFunction({
name: 'devframes:plugin:terminals:rename',
type: 'action',
args: [v.object({ id: v.string(), title: v.string() })],
returns: v.void(),
setup: ctx => ({ handler: ({ id, title }) => { /* … */ } }),
})
```

```ts
// … or use the built-in zero-dep builder
import { defineRpcFunction } from 'devframe'
import { s } from 'devframe/utils/simple-schema'

export const rename = defineRpcFunction({
name: 'devframes:plugin:terminals:rename',
type: 'action',
args: [s.object({ id: s.string(), title: s.string() })],
returns: s.void(),
setup: ctx => ({ handler: ({ id, title }) => { /* … */ } }),
})
```

**Declared schemas are now enforced.** Each argument is validated against its schema at the boundary before the handler runs, and the resolved return value is validated on the way out; a mismatch is rejected with a coded diagnostic instead of reaching (or leaving) the handler. Payloads are guarded, not rewritten — extra object fields the schema doesn't mention still reach the handler. Audit any schema that was previously more of a type hint than a contract, since inputs that used to slip through now throw.

See [RPC](./rpc) for the full reference.

## MCP adapter upgraded to `@modelcontextprotocol/sdk` v2

The MCP adapter now targets the v2 SDK, which ships as scoped `@modelcontextprotocol/server` and `@modelcontextprotocol/client` packages. Swap the peer dependency when you ship MCP support:

| 0.7.x | 0.8 |
|-------|-----|
| `@modelcontextprotocol/sdk@^1` | `@modelcontextprotocol/server@^2` |

```sh
npm uninstall @modelcontextprotocol/sdk
npm install @modelcontextprotocol/server
```

`@modelcontextprotocol/server` remains an optional peer dependency, pulled in only through `devframe/adapters/mcp`. The `devframe connect` connector (below) additionally uses `@modelcontextprotocol/client` — install it too if you drive agents through the connector.

If you imported SDK types directly, the deep `@modelcontextprotocol/sdk/...` subpaths are now flat entries on the scoped packages (e.g. `@modelcontextprotocol/sdk/server/stdio.js` → `@modelcontextprotocol/server/stdio`). See [MCP](/adapters/mcp) for the adapter reference.

## Agent-native MCP surface

0.8 adds the agent host on `ctx.agent` — `registerTool`, `registerToolProvider`, and `registerResource` — plus an instance registry and the `devframe connect` MCP connector shipped in the `devframe` bin. These are additive; existing `agent`-flagged RPCs keep working and are projected to MCP as before.

One type sharpens: an RPC `handler` (and its `dump`) now returns `Thenable<returns>` — the `returns` schema describes the *resolved* value and the runtime always awaits the handler. Synchronous handlers are unaffected; an `async` handler whose declared `returns` was the unwrapped value now type-checks correctly rather than needing the promise spelled into the schema.

See [Agent-Native](./agent-native) for the tool/resource surface and [MCP → `devframe connect`](/adapters/mcp#discovery-devframe-connect) for the connector.
98 changes: 98 additions & 0 deletions docs/guide/migration-0.9.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
---
outline: deep
---

# Migrating to 0.9

0.9 removes the compatibility shims that were deprecated across the 0.7 series. Each removed export has a drop-in replacement that has shipped alongside it since 0.7, so migrating is a matter of updating import paths and a handful of call sites. This page covers the changes between 0.8.x and 0.9.

## `devframe/adapters/cli` is removed

The CLI adapter was renamed to `cac` in 0.7. The `devframe/adapters/cli` entry — `createCli`, `CreateCliOptions`, and `CliHandle` — is now gone. Import from `devframe/adapters/cac` instead:

| 0.8.x | 0.9 |
|-------|-----|
| `import { createCli } from 'devframe/adapters/cli'` | `import { createCac } from 'devframe/adapters/cac'` |
| `CreateCliOptions` | `CreateCacOptions` |
| `CliHandle` | `CacHandle` |

```ts
// 0.8.x
import { createCli } from 'devframe/adapters/cli'

await createCli(devframe).parse()
```

```ts
// 0.9
import { createCac } from 'devframe/adapters/cac'

await createCac(devframe).parse()
```

The typed-flag helpers `defineCliFlags` and `parseCliFlags` live on `devframe/adapters/cac` too. See [CLI (cac)](/adapters/cac) for the full adapter reference.

## `devframe/recipes/open-helpers` is removed

The recipe was renamed to `common-rpc-functions` in 0.7.16. Import `commonRpcFunctions` from `devframe/recipes/common-rpc-functions`:

```ts
// 0.8.x
import { openHelpers } from 'devframe/recipes/open-helpers'
```

```ts
// 0.9
import { commonRpcFunctions } from 'devframe/recipes/common-rpc-functions'
```

The `openInEditor` and `openInFinder` members are unchanged. See [Common RPC functions](/helpers/common-rpc-functions) for the full reference.

## RPC dump re-exports move to `devframe/rpc/dump`

The static-dump helpers and types are served from the dedicated `devframe/rpc/dump` entry; the aliases that re-exported them from the top-level `devframe/rpc` barrel are removed. Import them from `devframe/rpc/dump`:

```ts
// 0.8.x
import { createClientFromDump, dumpFunctions } from 'devframe/rpc'

// 0.9
import { createClientFromDump, dumpFunctions } from 'devframe/rpc/dump'
```

This applies to every dump export — `collectStaticRpcDump`, `createClientFromDump`, `dumpFunctions`, `getDefinitionsWithDumps`, `reviveDumpError`, `serializeDumpError`, and the `StaticRpcDump*` types.

## `@devframes/hub` json-render shims are removed

json-render moved out of the hub into the opt-in [`@devframes/json-render`](./json-render) integration in 0.7. The hub-local compatibility shims are now removed: the `defineJsonRenderSpec` helper, the `ctx.createJsonRenderer` factory, the `DevframeViewJsonRender` dock type, and the `JsonRenderSpec` / `JsonRenderElement` / `JsonRenderer` types.

| 0.8.x (`@devframes/hub`) | 0.9 (`@devframes/json-render`) |
|---|---|
| `defineJsonRenderSpec(spec)` | Pass the spec directly to `createJsonRenderView(ctx, { id, spec })` |
| `ctx.createJsonRenderer(spec)` | `createJsonRenderView(ctx, { id, spec })` (from `@devframes/json-render/node`) |
| `JsonRenderSpec` | `DevframeJsonRenderSpec` |
| `JsonRenderElement` | element shape of `DevframeJsonRenderSpec` |
| `JsonRenderer` | `JsonRenderView` |
| `DevframeViewJsonRender` | `DevframeJsonRenderDockEntry` (from `@devframes/json-render/hub`) |

```ts
// 0.8.x
import { defineJsonRenderSpec } from '@devframes/hub'

const spec = defineJsonRenderSpec({ root: 'panel', elements: { /* ... */ } })
const renderer = ctx.createJsonRenderer(spec)
```

```ts
// 0.9
import { createJsonRenderView } from '@devframes/json-render/node'

const view = createJsonRenderView(ctx, {
id: 'panel',
spec: { root: 'panel', elements: { /* ... */ } },
})
```

`createJsonRenderView` returns a view carrying a serializable `ref` (a shared-state key or an inline spec). Project it onto a hub dock with `toJsonRenderDockEntry` from `@devframes/json-render/hub`, which contributes the `'json-render'` dock type to the hub's open dock union. A dock entry now carries that serializable `view` ref rather than a live renderer handle — a client reads `entry.view.stateKey` (or `entry.view.spec`) to render it.

See [JSON-Render](./json-render) for the full integration reference.
2 changes: 0 additions & 2 deletions docs/helpers/common-rpc-functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@ defineDevframe({

Both functions are `action`-type RPCs returning `void`, and their arguments are schema-validated — `openInEditor`'s `editor` argument is restricted to `KNOWN_EDITORS`, so a value outside that list fails validation rather than reaching the underlying `launch-editor` process spawn. Both handlers dynamically `import()` their underlying `devframe/utils/*` implementation, so the `launch-editor` and `open` dependencies only load when the recipe actually runs.

The `devframe/recipes/open-helpers` entry (`openHelpers`) remains as a deprecated alias for this module — new code should import `commonRpcFunctions` from `devframe/recipes/common-rpc-functions`.

## Pick and choose

Register only the helper you need rather than the whole array:
Expand Down
4 changes: 2 additions & 2 deletions knip.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,12 @@
"entry": [
"src/{index,constants}.ts",
"src/helpers/vite.ts",
"src/adapters/{build,cac,cli,dev,embedded,initiate}.ts",
"src/adapters/{build,cac,dev,embedded,initiate}.ts",
"src/adapters/mcp/index.ts",
"src/client/index.ts",
"src/node/index.ts",
"src/node/{auth,hub-internals}/index.ts",
"src/recipes/{common-rpc-functions,interactive-auth,open-helpers}.ts",
"src/recipes/{common-rpc-functions,interactive-auth}.ts",
"src/rpc/{index,client,server}.ts",
"src/rpc/dump/index.ts",
"src/rpc/transports/{ws-bun,ws-client,ws-server}.ts",
Expand Down
2 changes: 0 additions & 2 deletions packages/devframe/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
".": "./dist/index.mjs",
"./adapters/build": "./dist/adapters/build.mjs",
"./adapters/cac": "./dist/adapters/cac.mjs",
"./adapters/cli": "./dist/adapters/cli.mjs",
"./adapters/dev": "./dist/adapters/dev.mjs",
"./adapters/embedded": "./dist/adapters/embedded.mjs",
"./adapters/mcp": "./dist/adapters/mcp.mjs",
Expand All @@ -35,7 +34,6 @@
"./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",
"./recipes/open-helpers": "./dist/recipes/open-helpers.mjs",
"./rpc": "./dist/rpc/index.mjs",
"./rpc/client": "./dist/rpc/client.mjs",
"./rpc/dump": "./dist/rpc/dump.mjs",
Expand Down
3 changes: 0 additions & 3 deletions packages/devframe/src/adapters/cac.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@
// without it throws at load time with the usual Node module-not-found
// error. The typed-flag helpers (`defineCliFlags` / `parseCliFlags`) are
// re-exported below so they live alongside the CLI adapter.
//
// The historical `devframe/adapters/cli` entry (`createCli`) re-exports
// this module under deprecated aliases for backward compatibility.
import type { CAC } from 'cac'
import type { H3 } from 'h3'
import type { DevframeDefinition } from '../types/devframe'
Expand Down
20 changes: 0 additions & 20 deletions packages/devframe/src/adapters/cli.ts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import type { StandardSchemaV1 } from '@standard-schema/spec'
import { describe, expect, it } from 'vitest'
import { commonRpcFunctions, KNOWN_EDITORS, openInEditor, openInFinder } from '../common-rpc-functions'
import { openHelpers } from '../open-helpers'

/** Synchronously check whether a value satisfies a Standard Schema. */
function accepts(schema: StandardSchemaV1, value: unknown): boolean {
Expand Down Expand Up @@ -42,8 +41,4 @@ describe('recipes/common-rpc-functions', () => {
expect(commonRpcFunctions).toContain(openInEditor)
expect(commonRpcFunctions).toContain(openInFinder)
})

it('keeps the deprecated `devframe/recipes/open-helpers` entry working as an alias', () => {
expect(openHelpers).toBe(commonRpcFunctions)
})
})
12 changes: 0 additions & 12 deletions packages/devframe/src/recipes/open-helpers.ts

This file was deleted.

3 changes: 2 additions & 1 deletion packages/devframe/src/rpc/dump/__tests__/dump.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import type { RpcDumpRecord } from '../../types'
import * as v from 'valibot'
import { describe, expect, it } from 'vitest'
import { createClientFromDump, createDefineWrapperWithContext, defineRpcFunction, dumpFunctions } from '../..'
import { createClientFromDump, dumpFunctions } from '..'
import { createDefineWrapperWithContext, defineRpcFunction } from '../..'

describe('dumps', () => {
it('should collect dumps from definition', async () => {
Expand Down
50 changes: 0 additions & 50 deletions packages/devframe/src/rpc/index.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,3 @@
import type {
StaticRpcDumpCollection as _StaticRpcDumpCollection,
StaticRpcDumpFile as _StaticRpcDumpFile,
StaticRpcDumpManifest as _StaticRpcDumpManifest,
StaticRpcDumpManifestQueryEntry as _StaticRpcDumpManifestQueryEntry,
StaticRpcDumpManifestStaticEntry as _StaticRpcDumpManifestStaticEntry,
StaticRpcDumpManifestValue as _StaticRpcDumpManifestValue,
StaticRpcDumpSerialization as _StaticRpcDumpSerialization,
} from './dump/static'
import {
createClientFromDump as _createClientFromDump,
dumpFunctions as _dumpFunctions,
getDefinitionsWithDumps as _getDefinitionsWithDumps,
} from './dump'
import {
reviveDumpError as _reviveDumpError,
serializeDumpError as _serializeDumpError,
} from './dump/error'
import {
collectStaticRpcDump as _collectStaticRpcDump,
} from './dump/static'

export * from './cache'
export * from './collector'
export * from './define'
Expand All @@ -28,31 +6,3 @@ export * from './serialization'
export * from './types'
export * from './validate-io'
export * from './validation'

/** @deprecated Import from `devframe/rpc/dump` instead. */
export const collectStaticRpcDump = _collectStaticRpcDump
/** @deprecated Import from `devframe/rpc/dump` instead. */
export const createClientFromDump = _createClientFromDump
/** @deprecated Import from `devframe/rpc/dump` instead. */
export const dumpFunctions = _dumpFunctions
/** @deprecated Import from `devframe/rpc/dump` instead. */
export const getDefinitionsWithDumps = _getDefinitionsWithDumps
/** @deprecated Import from `devframe/rpc/dump` instead. */
export const reviveDumpError = _reviveDumpError
/** @deprecated Import from `devframe/rpc/dump` instead. */
export const serializeDumpError = _serializeDumpError

/** @deprecated Import from `devframe/rpc/dump` instead. */
export type StaticRpcDumpCollection = _StaticRpcDumpCollection
/** @deprecated Import from `devframe/rpc/dump` instead. */
export type StaticRpcDumpFile = _StaticRpcDumpFile
/** @deprecated Import from `devframe/rpc/dump` instead. */
export type StaticRpcDumpManifest = _StaticRpcDumpManifest
/** @deprecated Import from `devframe/rpc/dump` instead. */
export type StaticRpcDumpManifestQueryEntry = _StaticRpcDumpManifestQueryEntry
/** @deprecated Import from `devframe/rpc/dump` instead. */
export type StaticRpcDumpManifestStaticEntry = _StaticRpcDumpManifestStaticEntry
/** @deprecated Import from `devframe/rpc/dump` instead. */
export type StaticRpcDumpManifestValue = _StaticRpcDumpManifestValue
/** @deprecated Import from `devframe/rpc/dump` instead. */
export type StaticRpcDumpSerialization = _StaticRpcDumpSerialization
2 changes: 0 additions & 2 deletions packages/devframe/tsdown.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,6 @@ const serverEntries = {
'utils/open': 'src/utils/open.ts',
'utils/serve-static': 'src/utils/serve-static.ts',
'adapters/cac': 'src/adapters/cac.ts',
'adapters/cli': 'src/adapters/cli.ts',
'adapters/dev': 'src/adapters/dev.ts',
'adapters/build': 'src/adapters/build.ts',
'adapters/embedded': 'src/adapters/embedded.ts',
Expand All @@ -112,7 +111,6 @@ const serverEntries = {
'cli/main': 'src/cli/main.ts',
'helpers/vite': 'src/helpers/vite.ts',
'recipes/common-rpc-functions': 'src/recipes/common-rpc-functions.ts',
'recipes/open-helpers': 'src/recipes/open-helpers.ts',
'recipes/interactive-auth': 'src/recipes/interactive-auth.ts',
}

Expand Down
Loading
Loading