### Install and Run the Example Source: https://github.com/devframes/devframe/blob/main/examples/minimal-next-devframe-hub/README.md Installs dependencies and starts the Next.js development server for the minimal hub example. ```sh pnpm install pnpm --filter minimal-next-devframe-hub dev ``` -------------------------------- ### Install and Run Vite Devframe Hub Source: https://github.com/devframes/devframe/blob/main/examples/minimal-vite-devframe-hub/README.md Installs dependencies and starts the Vite development server for the minimal Devframe Hub example. ```sh pnpm install pnpm --filter minimal-vite-devframe-hub dev ``` -------------------------------- ### Install and Run Files Inspector Source: https://github.com/devframes/devframe/blob/main/examples/files-inspector/README.md Commands to install dependencies, build the Preact client, start the Dev server, create a static build, and serve the static build. ```sh pnpm install pnpm -C examples/files-inspector run build # build the Preact client pnpm -C examples/files-inspector run dev # http://127.0.0.1:9876/__devframe-files-inspector/ pnpm -C examples/files-inspector run cli:build # static deploy in ./dist/static serve examples/files-inspector/dist/static # any static host works (relative paths) pnpm -C examples/files-inspector run test # E2E tests ``` -------------------------------- ### Running CLI Commands Source: https://github.com/devframes/devframe/blob/main/docs/adapters/cli.md Examples of common commands executed from the CLI, including starting the dev server, building static assets, and running the MCP server. ```shell my-devframe # dev server at http://localhost:9999/ my-devframe --port 8080 my-devframe build --out-dir dist-static my-devframe build --out-dir dist-static --base /devframe/ my-devframe mcp # stdio MCP server (experimental) ``` -------------------------------- ### Devframe Definition with Browser Setup Source: https://github.com/devframes/devframe/blob/main/docs/guide/devframe-definition.md This example shows a Devframe definition that includes both a server-side `setup` function and a browser-side `setupBrowser` function. The `setupBrowser` hook is intended for logic that runs within the deployed client bundle, such as calling public APIs from the client. ```typescript defineDevframe({ id: 'my-devframe', name: 'My Devframe', setup(ctx) { /* server-side */ }, setupBrowser(ctx) { // `ctx.rpc` is the write-disabled static client in SPA mode. }, }) ``` -------------------------------- ### Install Devframe Source: https://github.com/devframes/devframe/blob/main/docs/guide/index.md Install the devframe package using pnpm. ```sh pnpm add devframe ``` -------------------------------- ### Start MCP Server Programmatically Source: https://github.com/devframes/devframe/blob/main/docs/guide/agent-native.md Programmatically start an MCP server using `createMcpServer`. The `stdio` transport is common for agent communication. Ensure `@modelcontextprotocol/sdk` is installed as a peer dependency. ```typescript import { defineDevframe } from 'devframe' import { createMcpServer } from 'devframe/adapters/mcp' const devframe = defineDevframe({ /* … */ }) await createMcpServer(devframe, { transport: 'stdio' }) ``` -------------------------------- ### Basic CLI Setup Source: https://github.com/devframes/devframe/blob/main/docs/adapters/cli.md Import and define a Devframe, then create and parse CLI arguments using the CLI adapter. ```typescript import { defineDevframe } from 'devframe' import { createCli } from 'devframe/adapters/cli' const devframe = defineDevframe({ id: 'my-devframe', name: 'My Devframe', cli: { distDir: './client/dist' }, setup(ctx) { /* register docks, RPC, etc. */ }, }) await createCli(devframe).parse() ``` -------------------------------- ### Running the Devframe CLI Source: https://github.com/devframes/devframe/blob/main/docs/guide/index.md Examples of how to run the created devframe CLI with different commands. ```sh node ./my-devframe.js # dev server on http://localhost:9999/ node ./my-devframe.js build # self-contained static deploy in dist-static/ node ./my-devframe.js mcp # stdio MCP server (experimental) ``` -------------------------------- ### Build and Run Streaming Chat Demo Source: https://github.com/devframes/devframe/blob/main/examples/streaming-chat/README.md Commands to build and run the streaming chat example locally. ```sh pnpm -C examples/streaming-chat run build pnpm -C examples/streaming-chat run dev ``` -------------------------------- ### Type-Safe Client Call Example Source: https://github.com/devframes/devframe/blob/main/docs/guide/rpc.md Example demonstrating how a type-safe client, augmented with server functions, can call RPCs with autocompletion and argument typing. ```typescript import { connectDevframe } from 'devframe/client' const rpc = await connectDevframe() const modules = await rpc.call('my-devframe:get-modules', { limit: 10 }) // ^? typed from the augmentation above ``` -------------------------------- ### Development Commands Source: https://github.com/devframes/devframe/blob/main/AGENTS.md Common commands for installing dependencies, building, developing, testing, type checking, linting, and running the application. ```sh pnpm install # requires pnpm@11.x pnpm build # tsdown pnpm dev # tsdown --watch pnpm test # pnpm build && vitest (api snapshot guards against stale dist) pnpm typecheck # tsc --noEmit pnpm lint --fix # ESLint via @antfu/eslint-config pnpm start # tsx src/index.ts ``` -------------------------------- ### Run Streaming Chat Tests Source: https://github.com/devframes/devframe/blob/main/examples/streaming-chat/README.md Command to execute the tests for the streaming chat example. ```sh pnpm -C examples/streaming-chat run test ``` -------------------------------- ### RPC Naming Convention Example Source: https://github.com/devframes/devframe/blob/main/skills/devframe/SKILL.md This example demonstrates the recommended convention for naming RPCs and other identifiers within Devframe. Prefixes should always include the devframe's unique ID to prevent naming collisions. ```typescript 'my-inspector:get-modules' // ✓ 'my-inspector:state' // ✓ 'get-modules' // ✗ — may collide with other devframes sharing the host ``` -------------------------------- ### Install Nuxt Devframe Module Source: https://github.com/devframes/devframe/blob/main/docs/helpers/nuxt.md Install the @devframes/nuxt module in your Nuxt project. This is the zero-config setup. ```typescript export default defineNuxtConfig({ modules: ['@devframes/nuxt'], }) ``` -------------------------------- ### Start and Write to a Server-to-Client Streaming Channel Source: https://github.com/devframes/devframe/blob/main/skills/devframe/SKILL.md Starts a server-to-client streaming channel, allowing data chunks to be written, errors to be signaled, and the stream to be closed. Provides an AbortSignal and a WritableStream for consumption. ```typescript // Server — typically inside an action handler that returns the stream id const stream = channel.start({ id: 'optional-stream-id' }) stream.write(token) // imperative stream.error(err) // terminal failure stream.close() // terminal success stream.signal // AbortSignal — flips when consumers cancel or all subscribers drop stream.writable // WritableStream for `pipeTo`-style consumption ``` -------------------------------- ### RPC Function using Setup Context Source: https://github.com/devframes/devframe/blob/main/docs/guide/rpc.md An RPC function 'my-devframe:count' that uses the DevframeNodeContext provided in the setup to access shared state and count the number of keys in the RPC shared state. ```typescript defineRpcFunction({ name: 'my-devframe:count', type: 'query', setup: ctx => ({ handler: async () => ctx.rpc.sharedState.keys().length, }), }) ``` -------------------------------- ### Common When Clause Examples Source: https://github.com/devframes/devframe/blob/main/docs/guide/when-clauses.md Illustrates various common scenarios for using when clauses, including always visible, never visible, specific client types, and combinations of conditions. ```plaintext when: 'true' // always visible when: 'false' // never visible when: 'clientType == embedded' // only embedded when: 'dockOpen && !paletteOpen' // dock open and palette closed when: '(clientType == embedded && dockOpen) || clientType == standalone' when: 'my-devtool.ready' // custom plugin context ``` -------------------------------- ### Opt-in Devframe Skill via Symlink Source: https://github.com/devframes/devframe/blob/main/skills/devframe/README.md Link the devframe skill directory to your Claude Code skills path. This is a temporary solution until an installable skill is published. ```sh ln -s "$PWD/devframe/skills/devframe" "$HOME/.claude/skills/devframe" ``` -------------------------------- ### Define Devframe with RPC Registration Source: https://github.com/devframes/devframe/blob/main/skills/devframe/SKILL.md This snippet defines the main Devframe export. The setup function initializes the tool's context and registers all server RPC functions with the Devframe context's RPC surface. ```typescript // src/devframe.ts import { defineDevframe } from 'devframe/types' import { setMyToolContext } from './context' import { serverFunctions } from './rpc' export default defineDevframe({ id: 'my-tool', setup(ctx) { setMyToolContext(ctx, { loaders: createLoaders() }) serverFunctions.forEach(fn => ctx.rpc.register(fn)) }, }) ``` -------------------------------- ### Create and Start a Streaming Channel Source: https://github.com/devframes/devframe/blob/main/docs/guide/rpc.md Use this to create a streaming channel for chunk-style server-to-client feeds. It handles stream IDs, cancellation, replay, and Web Streams interop. ```typescript const channel = ctx.rpc.streaming.create('my-devframe:chat', { replayWindow: 256, }) const stream = channel.start() sourceReadable.pipeTo(stream.writable) ``` -------------------------------- ### Integrating Devframe with Commander CLI Source: https://github.com/devframes/devframe/blob/main/docs/guide/standalone-cli.md Use Devframe's build and dev server adapters with an existing CLI framework like Commander. This example shows how to create 'dev' and 'build' commands. ```typescript import process from 'node:process' import { Command } from 'commander' import { defineDevframe } from 'devframe' import { createBuild } from 'devframe/adapters/build' import { createDevServer } from 'devframe/adapters/dev' const devframe = defineDevframe({ id: 'my-tool', name: 'My Tool', cli: { distDir: './dist/public', port: 7777 }, setup(ctx, { flags }) { /* ... */ }, }) const program = new Command('my-tool') program .command('dev', { isDefault: true }) .option('-p, --port ', 'Port', '7777') .option('--config ', 'Config file path') .action(async (opts) => { const handle = await createDevServer(devframe, { port: Number(opts.port), flags: { config: opts.config }, onReady: ({ origin }) => console.log(`Ready at ${origin}`), }) process.on('SIGINT', () => handle.close().then(() => process.exit(0))) }) program .command('build') .option('--out-dir ', 'Output directory', 'dist-static') .action(opts => createBuild(devframe, { outDir: opts.outDir })) await program.parseAsync() ``` -------------------------------- ### Conditional Logic Based on Runtime Mode Source: https://github.com/devframes/devframe/blob/main/docs/guide/devframe-definition.md Use the `ctx.mode` field within the `setup` function to conditionally execute code for 'dev' or 'build' runtimes. This is useful for setting up dev-specific features like file watchers or build-specific static work. ```typescript defineDevframe({ id: 'my-devframe', name: 'My Devframe', setup(ctx) { if (ctx.mode === 'build') { // Static-only work — baked into the RPC dump. } else { // Dev-mode wiring, file watchers, etc. } }, }) ``` -------------------------------- ### Create MCP Server with StdIO Transport Source: https://github.com/devframes/devframe/blob/main/docs/adapters/mcp.md Use this snippet to initialize an MCP server for Devframe using the standard input/output transport. Ensure '@modelcontextprotocol/sdk' is installed as a peer dependency. ```typescript import { createMcpServer } from 'devframe/adapters/mcp' import devframe from './devframe' await createMcpServer(devframe, { transport: 'stdio' }) ``` -------------------------------- ### Mounting Devframe into Vite DevTools Source: https://github.com/devframes/devframe/blob/main/skills/devframe/SKILL.md Illustrates how to integrate a Devframe inspector into Vite DevTools using `createPluginFromDevframe`. The `setup` hook allows for custom commands and host-specific configurations. ```typescript // vite.config.ts import { createPluginFromDevframe } from '@vitejs/devtools-kit/node' import myInspector from './my-inspector' export default { plugins: [ createPluginFromDevframe(myInspector, { // Optional kit-only setup — runs after the auto-derived dock entry. setup(kitCtx) { kitCtx.commands.register({ id: 'my-inspector:clear-cache', title: 'Clear Cache', handler: () => { /* ... */ }, }) }, }), ], } ``` -------------------------------- ### Minimal CLI Devframe Setup Source: https://github.com/devframes/devframe/blob/main/docs/guide/standalone-cli.md Defines the core Devframe configuration for a CLI tool, including command-line options and RPC function registration. Use this to set up the main entry point for your standalone CLI application. ```typescript import process from 'node:process' import { defineDevframe, defineRpcFunction } from 'devframe' import { createCli } from 'devframe/adapters/cli' import { colors as c } from 'devframe/utils/colors' import { resolve } from 'pathe' const distDir = resolve(import.meta.dirname, '../dist/public') const devframe = defineDevframe({ id: 'my-tool', name: 'My Tool', cli: { command: 'my-tool', distDir, port: 7777, portRange: [7777, 9000], open: true, auth: false, // single-user localhost — skip the trust handshake configure(cli) { cli .option('--config ', 'Config file path') .option('--base-path ', 'Base directory for resolution') }, }, async setup(ctx, { flags }) { ctx.rpc.register(defineRpcFunction({ name: 'my-tool:get-payload', type: 'query', async handler() { return await loadPayload({ configPath: flags.config, basePath: flags.basePath, }) }, })) }, }) await createCli(devframe, { onReady({ origin }) { console.log(c.green`My Tool ready at ${origin}`) }, }).parse(process.argv) ``` -------------------------------- ### Registering a Dock Entry with a When Clause Source: https://github.com/devframes/devframe/blob/main/docs/guide/when-clauses.md Control the visibility of dock entries using the 'when' clause. This example makes a dock entry visible only when the client type is 'embedded'. ```typescript ctx.docks.register({ id: 'my-devtool:inspector', title: 'Inspector', type: 'action', icon: 'ph:cursor-duotone', when: 'clientType == embedded', action: { importFrom: 'my-devtool/inspector' }, }) ``` -------------------------------- ### Mounting a Devframe into a Hub Context Source: https://github.com/devframes/devframe/blob/main/docs/guide/hub.md Use `mountDevframe` to register a `DevframeDefinition` as a dock and run its setup function within a hub context. This is the framework-neutral primitive for integrating devframes. ```typescript import { createHubContext, mountDevframe } from '@devframes/hub/node' const ctx = await createHubContext({ cwd, host, mode: 'dev' }) await mountDevframe(ctx, myDevframe) ``` -------------------------------- ### Define RPC Function for Listing Files Source: https://github.com/devframes/devframe/blob/main/skills/devframe/SKILL.md This snippet shows how to define a query-type RPC function named 'my-tool:list-files'. It uses a setup function to retrieve loaders from the tool's context and returns a handler that calls the list method on the loaders. ```typescript // src/rpc/functions/list-files.ts import { defineRpcFunction } from 'devframe' import { getMyToolContext } from '../../context' export const listFiles = defineRpcFunction({ name: 'my-tool:list-files', type: 'query', jsonSerializable: true, setup: (ctx) => { const { loaders } = getMyToolContext(ctx) return { handler: () => loaders.list() } }, }) ``` -------------------------------- ### CLI Distribution Directory Configuration Source: https://github.com/devframes/devframe/blob/main/docs/guide/standalone-cli.md Configure the CLI's distribution directory using Node.js's fileURLToPath for correct path resolution in Next.js SPA setups. ```typescript import { fileURLToPath } from 'node:url' defineDevframe({ id: 'my-tool', cli: { distDir: fileURLToPath(new URL('../dist/client', import.meta.url)), }, // … }) ``` -------------------------------- ### Create Shared State with Initial Value Source: https://github.com/devframes/devframe/blob/main/docs/guide/shared-state.md Use `ctx.rpc.sharedState.get` in your `setup` function to initialize shared state. Namespace keys with `:` to prevent collisions. The `initialValue` option provides a default state. ```typescript import { defineDevframe } from 'devframe' export default defineDevframe({ id: 'my-devframe', name: 'My Devframe', async setup(ctx) { const state = await ctx.rpc.sharedState.get('my-devframe:state', { initialValue: { count: 0, items: [] as { id: string, name: string }[], }, }) console.log(state.value().count) // 0 }, }) ``` -------------------------------- ### Define a Streaming Channel in Devframe Source: https://github.com/devframes/devframe/blob/main/docs/guide/streaming.md Sets up a streaming channel named 'my-devframe:chat' with a replay window. It also registers an RPC action to start a chat stream, which simulates an LLM response and writes tokens to the stream. ```typescript import { defineDevframe, defineRpcFunction } from 'devframe' import * as v from 'valibot' export default defineDevframe({ id: 'my-devframe', name: 'My Devframe', async setup(ctx) { const channel = ctx.rpc.streaming.create('my-devframe:chat', { replayWindow: 256, }) ctx.rpc.register(defineRpcFunction({ name: 'my-devframe:start-chat', type: 'action', jsonSerializable: true, args: [v.object({ prompt: v.string() })], returns: v.object({ streamId: v.string() }), handler: async ({ prompt }) => { const stream = channel.start() ;(async () => { for await (const token of fakeLLM(prompt, { signal: stream.signal })) { stream.write(token) } stream.close() })() return { streamId: stream.id } }, })) }, }) ``` -------------------------------- ### Register RPC Function in Devframe Setup Source: https://github.com/devframes/devframe/blob/main/docs/guide/rpc.md Registers the 'getModules' RPC function within the Devframe setup. Ensure each function is in its own file under 'src/rpc/functions/' and barrelled in 'src/rpc/index.ts'. ```typescript import { defineDevframe } from 'devframe' import { getModules } from './rpc/functions/get-modules' export default defineDevframe({ id: 'my-devframe', name: 'My Devframe', setup(ctx) { ctx.rpc.register(getModules) }, }) ``` -------------------------------- ### Customizing Startup Banner with onReady Source: https://github.com/devframes/devframe/blob/main/docs/adapters/cli.md Using the `onReady` callback in `createCli` to log a custom message once the dev server is listening. ```typescript await createCli(devframe, { onReady({ origin }) { console.log(`ESLint Config Inspector ready at ${origin}`) }, }).parse() ``` -------------------------------- ### Create Static Build Source: https://github.com/devframes/devframe/blob/main/docs/adapters/build.md Initiates the build process for a static deployment. Specify the output directory and the base URL the output will be served from. ```typescript import { createBuild } from 'devframe/adapters/build' import devframe from './devframe' await createBuild(devframe, { outDir: 'dist-static', base: '/', }) ``` -------------------------------- ### Peer Factory Entry Points Source: https://github.com/devframes/devframe/blob/main/docs/adapters/cli.md Overview of the peer factory entry points for integrating Devframe into existing CLI frameworks, such as `createDevServer`, `createBuild`, and `createMcpServer`. ```markdown | Building block | Entry | Purpose | |----------------|-------|---------| | [`createDevServer(def, opts?)`](./dev) | `devframe/adapters/dev` | h3 + WebSocket RPC + SPA mount | | [`createBuild(def, opts?)`](./build) | `devframe/adapters/build` | Static deploy | | [`createMcpServer(def, opts?)`](./mcp) | `devframe/adapters/mcp` | stdio MCP server | | `parseCliFlags(schema, raw)` | `devframe/adapters/cli` | Validate a flag bag against a `CliFlagsSchema` | ``` -------------------------------- ### Throwing a Diagnostic Source: https://github.com/devframes/devframe/blob/main/docs/guide/diagnostics.md Example of throwing a diagnostic to halt execution. TypeScript will narrow the lines after the throw as unreachable. ```typescript throw myDiagnostics.MYP0001({ name }) ``` -------------------------------- ### Create Dev Server Source: https://github.com/devframes/devframe/blob/main/docs/adapters/dev.md Mounts the Dev adapter using createDevServer. It configures the port, provides a callback for when the server is ready, and handles graceful shutdown via SIGINT. ```typescript import { createDevServer } from 'devframe/adapters/dev' import devframe from './devframe' const handle = await createDevServer(devframe, { port: 7777, onReady: ({ origin }) => console.log(`Ready at ${origin}`), }) // graceful shutdown — SIGINT, hot reload, test teardown process.on('SIGINT', () => handle.close().then(() => process.exit(0))) ``` -------------------------------- ### Integrate Devframe with Multiple Runtimes Source: https://github.com/devframes/devframe/blob/main/docs/guide/devframe-definition.md Demonstrates how to define a Devframe once and then wire it into multiple adapters for different runtimes, such as a standalone CLI, an offline snapshot builder, or mounting into a host like Vite DevTools. ```typescript import { createPluginFromDevframe } from '@vitejs/devtools-kit/node' import { createBuild } from 'devframe/adapters/build' import { createCli } from 'devframe/adapters/cli' const devframe = defineDevframe({ id: 'my-devframe', name: 'My Devframe', setup() {} }) // 1. Standalone CLI: await createCli(devframe).parse() // 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) ``` -------------------------------- ### Pipe Source to Streaming Channel Source: https://github.com/devframes/devframe/blob/main/skills/devframe/SKILL.md A convenience method to start a streaming channel and pipe data from a source ReadableStream in one call. ```typescript // Convenience — start + pipe in one call: await channel.pipeFrom(sourceReadable, { id: 'optional' }) ``` -------------------------------- ### Connecting to DevFrame from SPA Source: https://github.com/devframes/devframe/blob/main/skills/devframe/SKILL.md Illustrates how to establish a connection to the DevFrame backend from a client-side SPA and make RPC calls. ```APIDOC ## connectDevframe (Client) ### Description Establishes a connection to the DevFrame backend from a client-side application. ### Method `connectDevframe` ### Returns A promise that resolves to an RPC client object. ### Example ```typescript import { connectDevframe } from 'devframe/client' const rpc = await connectDevframe() // await rpc.ensureTrusted() // WS mode only — blocks until server accepts const data = await rpc.call('my-inspector:get-stats', { limit: 10 }) ``` ## rpc.call ### Description Invokes a remote procedure call. ### Method `rpc.call` ### Parameters - `methodName` (string) - Required - The name of the RPC method to call. - `args` (object) - Optional - The arguments to pass to the RPC method. ### Returns A promise that resolves with the result of the RPC call. ``` -------------------------------- ### RPC Function Declared JSON-Serializable Source: https://github.com/devframes/devframe/blob/main/docs/errors/DF0019.md This example demonstrates the fix for DF0019 by explicitly setting `jsonSerializable: true` on an RPC function that is exposed to an agent. ```typescript defineRpcFunction({ name: 'my-plugin:summary', jsonSerializable: true, agent: { description: 'Returns a summary' }, handler: () => ({ items: [1, 2, 3] }), }) ``` -------------------------------- ### Run Next.js App Router Demo Source: https://github.com/devframes/devframe/blob/main/examples/next-runtime-snapshot/README.md Commands to build the Next.js static export and run the devframe CLI for the demo. ```sh pnpm -C examples/next-runtime-snapshot run build # next build → static export → dist/client/ pnpm -C examples/next-runtime-snapshot run dev # node bin.mjs → devframe CLI ``` -------------------------------- ### Minimal Devframe Definition Source: https://github.com/devframes/devframe/blob/main/docs/guide/devframe-definition.md This is the most basic Devframe definition, including an ID, name, icon, and a setup function that registers a simple RPC function. ```typescript import { defineDevframe, defineRpcFunction } from 'devframe' import * as v from 'valibot' export default defineDevframe({ id: 'my-devframe', name: 'My Devframe', icon: 'ph:gauge-duotone', setup(ctx) { // Register your RPC functions, shared state, etc. here. ctx.rpc.register(defineRpcFunction({ name: 'my-devframe:hello', type: 'static', jsonSerializable: true, handler: () => ({ message: 'hello' }), })) }, }) ``` -------------------------------- ### Configure Vite with Vite Bridge Source: https://github.com/devframes/devframe/blob/main/docs/helpers/vite-bridge.md Integrate the viteDevBridge plugin into your Vite configuration. This snippet shows the basic setup for including the devframe plugin. ```typescript import { viteDevBridge } from 'devframe/helpers/vite' import { defineConfig } from 'vite' import devframe from './devframe' export default defineConfig({ plugins: [viteDevBridge(devframe)], }) ``` -------------------------------- ### Registering Custom Diagnostics Source: https://github.com/devframes/devframe/blob/main/docs/guide/diagnostics.md Define and register custom diagnostic codes for your plugin. This example shows how to set up messages for missing configuration and cache directories. ```typescript export function MyPlugin(): PluginWithDevTools { return { name: 'my-plugin', devtools: { setup(ctx) { const myDiagnostics = ctx.diagnostics.defineDiagnostics({ docsBase: 'https://example.com/errors', codes: { MYP0001: { why: (p: { name: string }) => `Plugin "${p.name}" is not configured`, fix: 'Add the plugin to your `vite.config.ts` and pass an options object.', }, MYP0002: { why: 'Cache directory missing — running cold.', }, }, }) ctx.diagnostics.register(myDiagnostics) // Emit through the host's shared reporter: myDiagnostics.MYP0002() }, }, } } ``` -------------------------------- ### Next.js Configuration for Static Export Source: https://github.com/devframes/devframe/blob/main/examples/next-runtime-snapshot/README.md Key Next.js configuration settings for static export and base path compatibility with devframe. ```mjs export default { output: 'export', assetPrefix: '.', trailingSlash: true, }; ``` -------------------------------- ### Register RPC Function with Force Option Source: https://github.com/devframes/devframe/blob/main/docs/errors/DF0021.md Example of registering an RPC function and overwriting a previous registration with the same name by passing `true` as the second argument. ```typescript ctx.rpc.register(defineRpcFunction({ name: 'my-plugin:fn', handler: () => 1 }), true /* force */) ``` -------------------------------- ### Using Namespaced Context Keys in When Clauses Source: https://github.com/devframes/devframe/blob/main/docs/guide/when-clauses.md Shows how to reference context keys defined by plugins using dot or colon separators, and how Devframe resolves them by checking for exact matches or nested paths. ```plaintext when: 'my-devtool.ready' when: 'my-devtool:step == build' when: 'myDevtool.ready' ``` -------------------------------- ### RPC Function Returning Non-JSON Value Source: https://github.com/devframes/devframe/blob/main/docs/errors/DF0020.md This example demonstrates an RPC function declared as `jsonSerializable: true` that returns a `Map`, which is not JSON-compatible, leading to DF0020. ```typescript defineRpcFunction({ name: 'my-plugin:graph', jsonSerializable: true, handler: () => ({ nodes: new Map([['a', 1]]), // ← throws DF0020 with type=Map, path="nodes" }), }) ``` -------------------------------- ### Configure Devframe Client Connection Source: https://github.com/devframes/devframe/blob/main/docs/guide/client.md Demonstrates how to configure the `connectDevframe` function with various options, including `baseURL`, `authToken`, and caching settings. ```typescript await connectDevframe({ baseURL: './', // string or string[] fallback list — see notes below authToken: 'user-provided-token', cacheOptions: true, // enable response caching wsOptions: { /* … */ }, rpcOptions: { /* birpc options */ }, }) ``` -------------------------------- ### Get and Mutate Shared State Source: https://github.com/devframes/devframe/blob/main/skills/devframe/SKILL.md Retrieves a shared state object with an initial value and allows for mutable updates. Mutations are synchronized across all clients. ```typescript const state = await ctx.rpc.sharedState.get('my-inspector:state', { initialValue: { count: 0, items: [] as string[] }, }) state.mutate((draft) => { draft.count += 1 draft.items.push('tick') }) ``` -------------------------------- ### devframe/utils/open Source: https://github.com/devframes/devframe/blob/main/docs/helpers/utilities.md Opens a URL, file, or other target using the operating system's default handler. It can also wait for the opened process to complete. ```APIDOC ## `devframe/utils/open` ### Description Opens a URL, file, or other target using the operating system's default handler. It can also wait for the opened process to complete. ### Usage Example ```ts import { open } from 'devframe/utils/open' await open('https://localhost:7777') await open('./report.html', { wait: true }) ``` ``` -------------------------------- ### RPC Function Missing jsonSerializable: true Source: https://github.com/devframes/devframe/blob/main/docs/errors/DF0019.md This example shows an RPC function definition that will throw DF0019 because it has an `agent` configured but is missing the `jsonSerializable: true` flag. ```typescript defineRpcFunction({ name: 'my-plugin:summary', agent: { description: 'Returns a summary' }, // missing `jsonSerializable: true` → registration throws DF0019 handler: () => ({ items: [1, 2, 3] }), }) ``` -------------------------------- ### Conditional Visibility with 'when' Clauses Source: https://github.com/devframes/devframe/blob/main/skills/devframe/SKILL.md Provides examples of using VS Code-style 'when' clauses to control the visibility of dock entries or commands based on runtime context. ```typescript when: 'clientType == embedded' when: 'dockOpen && !paletteOpen' when: 'my-inspector.ready && count >= 10' ``` -------------------------------- ### Project Pre-PR Checks Source: https://github.com/devframes/devframe/blob/main/AGENTS.md Commands to run for linting, testing, type checking, and building the project before submitting pull requests. ```shell pnpm lint && pnpm test && pnpm typecheck && pnpm build ``` -------------------------------- ### Register a Resource for Agents Source: https://github.com/devframes/devframe/blob/main/docs/guide/agent-native.md Expose readable snapshots of state as resources, identified by a URI. Resources have an ID, name, description, MIME type, and a `read` function that returns the resource content. ```typescript ctx.agent.registerResource({ id: 'current-session', name: 'Current Rolldown session', description: 'Markdown snapshot of the active build session.', mimeType: 'text/markdown', read: () => ({ text: renderMarkdown(currentSession) }), }) ``` -------------------------------- ### Registering a Command with a When Clause Source: https://github.com/devframes/devframe/blob/main/docs/guide/when-clauses.md Use the 'when' property to control command visibility and triggerability based on context. This example shows a command that only appears when the client type is 'embedded'. ```typescript ctx.commands.register({ id: 'my-devtool:embedded-only', title: 'Embedded-Only Action', when: 'clientType == embedded', handler: async () => { /* … */ }, }) ``` -------------------------------- ### RPC Function with JSON-Serializable Fix Source: https://github.com/devframes/devframe/blob/main/docs/errors/DF0020.md This example shows how to fix DF0020 by removing `jsonSerializable: true` to use the default `structured-clone-es` serialization, which supports types like Map. ```typescript defineRpcFunction({ name: 'my-plugin:graph', // jsonSerializable: false (default) — Map/Set survive the wire and the dump handler: () => ({ nodes: new Map([['a', 1]]), }), }) ``` -------------------------------- ### Make RPC Calls with Devframe Client Source: https://github.com/devframes/devframe/blob/main/docs/guide/client.md Illustrates different methods for interacting with the Devframe server via RPC: standard calls, optional calls, and event calls. ```typescript const rpc = await connectDevframe() // Standard call — awaits a response or throws. const modules = await rpc.call('my-devframe:get-modules', { limit: 10 }) // Optional — returns undefined when no handler responds (useful while HMR is restarting). const maybe = await rpc.callOptional('my-devframe:get-modules', { limit: 10 }) // Event — fire-and-forget, no response expected. rpc.callEvent('my-devframe:notify', { message: 'hello' }) ``` -------------------------------- ### Register All Open Helpers Source: https://github.com/devframes/devframe/blob/main/docs/helpers/open-helpers.md Registers all available open helper RPCs (`openInEditor`, `openInFinder`) using the `openHelpers` array for batch registration. ```typescript import { openHelpers } from 'devframe/recipes/open-helpers' defineDevframe({ id: 'my-tool', name: 'My Tool', setup(ctx) { openHelpers.forEach(fn => ctx.rpc.register(fn)) }, }) ``` -------------------------------- ### Create Error Documentation Page Structure Source: https://github.com/devframes/devframe/blob/main/AGENTS.md Structure for a Markdown documentation page for a specific error code, including message, cause, example, fix, and source call sites. ```markdown --- outline: deep --- # DF0033: Short Title ## Message > Something went wrong with "`{name}`" ## Cause When and why this occurs. ## Example Code that triggers it. ## Fix How to resolve it. ## Source - [`src/node/filename.ts`](...) — `functionName()` throws this when … ``` -------------------------------- ### Call Open RPCs from Client Source: https://github.com/devframes/devframe/blob/main/docs/helpers/open-helpers.md Demonstrates how to call the `devframe:open-in-editor` and `devframe:open-in-finder` RPCs from a client-side application using the connected RPC client. ```typescript const rpc = await connectDevframe() await rpc.call('devframe:open-in-editor', 'src/main.ts:42:7') await rpc.call('devframe:open-in-finder', '/abs/path/to/dir') ``` -------------------------------- ### Open URL or File Source: https://github.com/devframes/devframe/blob/main/docs/helpers/utilities.md Opens a specified URL or file path using the operating system's default handler. Supports an option to wait for the handler to close. ```typescript import { open } from 'devframe/utils/open' await open('https://localhost:7777') await open('./report.html', { wait: true }) ``` -------------------------------- ### Invalid RPC Function Definition (Empty Description) Source: https://github.com/devframes/devframe/blob/main/docs/errors/DF0014.md This example shows an RPC function definition with an empty agent description, which will trigger the DF0014 error. Ensure the description is non-empty. ```typescript defineRpcFunction({ name: 'rolldown-get-session-summary', type: 'query', agent: { description: '', // ❌ empty }, // ... }) ``` -------------------------------- ### Minimum Viable Devframe Definition Source: https://github.com/devframes/devframe/blob/main/skills/devframe/SKILL.md This snippet shows the basic structure for defining a devframe, including its ID, name, icon, CLI configuration, and setup for registering RPC functions. ```typescript import { defineDevframe, defineRpcFunction } from 'devframe' export default defineDevframe({ id: 'my-inspector', name: 'My Inspector', icon: 'ph:magnifying-glass-duotone', cli: { distDir: './client/dist' }, setup(ctx) { ctx.rpc.register(defineRpcFunction({ name: 'my-inspector:get-stats', type: 'static', handler: () => ({ count: 42 }), })) }, }) ``` -------------------------------- ### Minimal Devframe with CLI Adapter Source: https://github.com/devframes/devframe/blob/main/docs/guide/index.md Defines a minimal devframe with a CLI entry point and a static RPC function. This definition can be deployed through various adapters. ```ts import { defineDevframe, defineRpcFunction } from 'devframe' import { createCli } from 'devframe/adapters/cli' const devframe = defineDevframe({ id: 'my-devframe', name: 'My Devframe', icon: 'ph:gauge-duotone', cli: { distDir: 'client/dist', }, setup(ctx) { ctx.rpc.register(defineRpcFunction({ name: 'my-devframe:hello', type: 'static', jsonSerializable: true, handler: () => ({ message: 'hello' }), })) }, }) await createCli(devframe).parse() ``` -------------------------------- ### Resolve Dev Server Port Source: https://github.com/devframes/devframe/blob/main/docs/adapters/dev.md Resolves a port for the development server upfront, allowing it to be printed or logged before the server starts. It honors various configuration options for port selection. ```typescript import { resolveDevServerPort } from 'devframe/adapters/dev' const port = await resolveDevServerPort(devframe, { host: '127.0.0.1' }) // honors def.cli?.port / portRange / random ``` -------------------------------- ### Node.js Stream Interoperability with Web Streams Source: https://github.com/devframes/devframe/blob/main/docs/guide/streaming.md Provides examples for bridging Node.js Readable and Writable streams with Devframe's Web Streams-based channels using standard library converters. ```typescript import { Readable, Writable } from 'node:stream' // Pipe a Node Readable into the streaming channel sourceNodeReadable.pipe(Writable.fromWeb(stream.writable)) // Pipe the channel out to a Node Writable Readable.fromWeb(reader.readable).pipe(targetNodeWritable) ```