import { S as RpcFunctionsCollectorBase } from "./index-C7M1hnvL.mjs"; import { t as DevframeNodeRpcSessionMeta } from "./ws-server-C1LjmRnp.mjs"; import { CAC } from "cac"; import { GenericSchema, InferOutput } from "valibot"; import { BirpcReturn } from "birpc"; import { Diagnostic, DiagnosticDefinition, defineDiagnostics } from "nostics"; //#region src/adapters/flags.d.ts /** * Schema map for typed CLI flags. Keys are flag names in camelCase — * this matches CAC's parsed-flag output ( `--no-open` → `noOpen` ). Each * value is a valibot schema used to both (a) derive the CAC option type * when the flag is registered and (b) validate / coerce the parsed * value before it's forwarded to `setup(ctx, { flags })`. */ type CliFlagsSchema = Record; /** * Identity helper that preserves the literal schema-map type — use this * so `InferCliFlags` resolves to the right object shape. * * ```ts * const appFlags = defineCliFlags({ * depth: v.pipe(v.number(), v.integer()), * config: v.optional(v.string()), * }) * * defineDevframe({ * cli: { flags: appFlags }, * setup(ctx, info) { * const flags = info.flags as InferCliFlags * flags.depth // number * flags.config // string | undefined * }, * }) * ``` */ declare function defineCliFlags(flags: T): T; /** Extract the parsed-output type from a {@link CliFlagsSchema}. */ type InferCliFlags = { [K in keyof T]: InferOutput }; /** Validate and coerce the raw cac-parsed bag against a {@link CliFlagsSchema}. */ declare function parseCliFlags(schema: CliFlagsSchema, raw: Record): { flags: Record; issues?: string[]; }; //#endregion //#region src/types/events.d.ts interface EventsMap { [event: string]: any; } interface EventUnsubscribe { (): void; } interface EventEmitter { /** * Calls each of the listeners registered for a given event. * * ```js * ee.emit('tick', tickType, tickDuration) * ``` * * @param event The event name. * @param args The arguments for listeners. */ emit: (event: K, ...args: Parameters) => void; /** * Calls the listeners for a given event once and then removes the listener. * * @param event The event name. * @param args The arguments for listeners. */ emitOnce: (event: K, ...args: Parameters) => void; /** * Event names in keys and arrays with listeners in values. * * @internal */ _listeners: Partial<{ [E in keyof Events]: Events[E][] }>; /** * Add a listener for a given event. * * ```js * const unbind = ee.on('tick', (tickType, tickDuration) => { * count += 1 * }) * * disable () { * unbind() * } * ``` * * @param event The event name. * @param cb The listener function. * @returns Unbind listener from event. */ on: (event: K, cb: Events[K]) => EventUnsubscribe; /** * Add a listener for a given event once. * * ```js * const unbind = ee.once('tick', (tickType, tickDuration) => { * count += 1 * }) * * disable () { * unbind() * } * ``` * * @param event The event name. * @param cb The listener function. * @returns Unbind listener from event. */ once: (event: K, cb: Events[K]) => EventUnsubscribe; } //#endregion //#region src/types/agent.d.ts /** * Serializable description of an agent-exposed tool. This is the shape * returned by the agent host manifest and surfaced over the wire by * the `devframe:agent:list-tools` introspection RPC. * * @experimental The agent-native surface is experimental and may change * without a major version bump until it stabilizes. */ interface AgentTool { /** Stable identifier. For RPC-backed tools, matches the RPC name. */ id: string; /** `'rpc'` when backed by a registered RPC function, `'tool'` when registered via `ctx.agent.registerTool()`. */ kind: 'rpc' | 'tool'; /** Display title (falls back to `id`). */ title: string; /** Human-readable description shown to the agent. */ description: string; /** Safety classification — drives MCP hint annotations downstream. */ safety: 'read' | 'action' | 'destructive'; /** Free-form tags for grouping/filtering. */ tags?: readonly string[]; /** Present for `kind === 'rpc'` — points to the RPC function name. */ rpcName?: string; /** JSON Schema describing the input (positional args synthesized to an object). */ inputSchema?: unknown; /** JSON Schema describing the output. */ outputSchema?: unknown; /** Example invocations shown to agents. */ examples?: readonly { args: unknown[]; description?: string; }[]; } /** * Input accepted by `DevframeAgentHost.registerTool()`. Handler is * stripped from the serializable `AgentTool` projection. * * @experimental */ interface AgentToolInput { id: string; title?: string; description: string; safety?: 'read' | 'action' | 'destructive'; tags?: readonly string[]; inputSchema?: unknown; outputSchema?: unknown; examples?: readonly { args: unknown[]; description?: string; }[]; /** Invoked when the tool is called. Receives args as provided by the caller. */ handler: (args: any) => unknown | Promise; } /** * Serializable description of an agent-readable resource. Resources * surface structured or textual snapshots of devframe state. * * @experimental */ interface AgentResource { id: string; /** URI used by MCP clients. Defaults to `devframe://resource/`. */ uri: string; name: string; description?: string; /** Defaults to `application/json`. */ mimeType?: string; } /** * Input accepted by `DevframeAgentHost.registerResource()`. * * @experimental */ interface AgentResourceInput { id: string; name: string; description?: string; mimeType?: string; /** Optional URI override — if omitted, a `devframe://resource/` URI is generated. */ uri?: string; /** Snapshot reader. Called on each read. */ read: () => Promise | AgentResourceContent; } /** * Payload returned by `AgentResourceInput.read`. Either `text` or `json` must be set. * * @experimental */ interface AgentResourceContent { text?: string; json?: unknown; /** Override the resource's declared mimeType for this read. */ mimeType?: string; } /** * Unified view of the agent-exposed surface. * * @experimental */ interface AgentManifest { tools: readonly AgentTool[]; resources: readonly AgentResource[]; } /** * Handle returned by `registerTool` / `registerResource`. * * @experimental */ interface AgentHandle { unregister: () => void; } /** * Events emitted by `DevframeAgentHost`. * * @experimental */ interface DevframeAgentHostEvents { 'agent:tool:registered': (tool: AgentTool) => void; 'agent:tool:unregistered': (id: string) => void; 'agent:resource:registered': (resource: AgentResource) => void; 'agent:resource:unregistered': (id: string) => void; /** * Fires when the unified manifest changes — including when a new * RPC function with an `agent` field is registered on `ctx.rpc`. */ 'agent:manifest:changed': () => void; } /** * Host that aggregates the agent-exposed surface of a devtool: both * RPC functions flagged with `agent` and plugin-registered tools / * resources. Consumed by protocol adapters such as the devframe MCP * adapter. * * @experimental The agent-native surface is experimental and may change * without a major version bump until it stabilizes. */ interface DevframeAgentHost { readonly events: EventEmitter; /** * Register a tool not backed by an RPC function. Use this when you * want a plain agent action (e.g. a synthesized summary) that * shouldn't exist as a full RPC. */ registerTool: (tool: AgentToolInput) => AgentHandle; /** Unregister a previously registered tool by id. */ unregisterTool: (id: string) => boolean; /** Register a readable resource. */ registerResource: (resource: AgentResourceInput) => AgentHandle; /** Unregister a previously registered resource by id. */ unregisterResource: (id: string) => boolean; /** * Unified snapshot of agent-exposed surface: RPC functions with an * `agent` field (auto-discovered from `ctx.rpc.definitions`) plus * tools/resources registered on the host. */ list: () => AgentManifest; /** * Invoke any tool by id. Routes to the underlying RPC handler for * `kind === 'rpc'`, or to the registered handler for `kind === 'tool'`. */ invoke: (id: string, args: unknown) => Promise; /** Read a resource by id. */ read: (id: string) => Promise; /** Look up a tool by id (returns the serializable projection). */ getTool: (id: string) => AgentTool | undefined; /** Look up a resource by id. */ getResource: (id: string) => AgentResource | undefined; } //#endregion //#region src/types/diagnostics.d.ts /** * A diagnostics definition object built with `defineDiagnostics`. Typed as * `unknown` because each integration's definition has a distinct narrow shape * (e.g. specific code keys like `DF0001` / `MYP0001`), and TypeScript's mapped * types don't allow assigning a narrow-keyed result to a generically-keyed * one. The host stores them in a heterogeneous registry. */ type DevframeDiagnosticsDefinition = ReturnType>; /** * The shared diagnostics lookup exposed by the host. A `Proxy` that resolves * any registered code name to its `nostics` handle (a callable that builds * a diagnostic and routes it through registered reporters). Typed loosely * because it spans heterogeneous definitions registered by different * integrations. */ type DevframeDiagnosticsLogger = Record; /** * Options accepted by the host's `defineDiagnostics()` factory — mirrors * `nostics`'s shape but the host pre-wires its ANSI console reporter, so * plugins typically omit `reporters`. */ interface DevframeDefineDiagnosticsOptions> { docsBase?: string | ((code: keyof Codes) => string | undefined); codes: Codes; reporters?: ReadonlyArray<(d: Diagnostic, o?: any) => void>; } /** * Host for structured diagnostics — a thin layer over `nostics` that lets * integrations register their own coded errors/warnings into a shared * registry without taking a direct dependency on `nostics`. * * Typical usage from a plugin's `setup(ctx)`: * * ```ts * const myDiagnostics = ctx.diagnostics.defineDiagnostics({ * docsBase: 'https://example.com/errors', * codes: { * MYP0001: { why: 'Something went wrong' }, * }, * }) * ctx.diagnostics.register(myDiagnostics) * * // Through the shared lookup (loose typing): * throw ctx.diagnostics.logger.MYP0001() * * // Or directly on the typed handle returned from `defineDiagnostics`: * throw myDiagnostics.MYP0001() * ``` */ interface DevframeDiagnosticsHost { /** * Proxy-backed lookup of every registered diagnostic handle by code name. * Resolves to a `nostics` `DiagnosticHandle` — a callable that builds a * diagnostic and routes it through registered reporters; prefix with * `throw` to raise. Loosely typed — for autocompletion, keep a reference * to the typed result of `defineDiagnostics()` instead. */ readonly logger: DevframeDiagnosticsLogger; /** * Register additional diagnostic definitions with this host. After * registration, codes from the new definition are reachable via * `host.logger.CODE`. Plugins that want shared output formatting should * build their diagnostics via `host.defineDiagnostics()` first — that * factory pre-wires the host's ANSI console reporter. */ register: (definitions: Record) => void; /** * Build a typed diagnostics object with the host's ANSI console reporter * pre-wired. Mirrors `nostics`'s `defineDiagnostics` so integrations don't * need to take a direct dependency on `nostics`. */ defineDiagnostics: >(options: DevframeDefineDiagnosticsOptions) => ReturnType>; } //#endregion //#region src/types/host.d.ts interface DevframeHost { /** * Serve a static directory at the given URL base. Called by * `DevframeViewHost.hostStatic`. Implementations map this to whatever * the underlying runtime expects (Vite middleware, h3 handler, no-op * for build snapshots). */ mountStatic: (base: string, distDir: string) => void | Promise; /** * Return the public origin the host is reachable at, e.g. * `http://localhost:5173`. Used by the dock host to enrich remote * iframe URLs with a full `origin`. Called only when a dock needs an * absolute URL; hosts that never serve remote docks can return any * reasonable value. */ resolveOrigin: () => string; /** * Resolve a directory the host owns for persisted devframe state. * Each host picks its own app-name namespace so storage doesn't * collide between, say, the Vite host (`.vite/devframe`) and a * standalone CLI host (`./devframe`). * * - `workspace` — per-project state (settings, caches). Typically * under `${workspaceRoot}/node_modules/./devframe/`. * - `global` — per-user state (auth tokens, machine-wide * preferences). Typically under * `${homedir()}/./devframe/`. * * Implementations should ensure the directory exists or be safe to * pass to a downstream `createStorage(...)` call that creates it * lazily. */ getStorageDir: (scope: 'workspace' | 'global') => string; } //#endregion //#region src/types/rpc-augments.d.ts /** * To be extended */ interface DevframeRpcClientFunctions { /** * Streaming chunk pushed from server to subscribed clients. Wired by * `RpcStreamingHost`; do not register manually. * * @internal */ 'devframe:streaming:chunk': (channel: string, id: string, seq: number, chunk: any) => Promise; /** * Streaming terminator pushed from server to subscribed clients. Wired by * `RpcStreamingHost`; do not register manually. * * @internal */ 'devframe:streaming:end': (channel: string, id: string, error?: { name: string; message: string; }) => Promise; /** * Server→client cancel for an in-flight upload. Wired by * `RpcStreamingHost`; do not register manually. * * @internal */ 'devframe:streaming:upload-cancel': (channel: string, id: string) => Promise; } /** * To be extended */ interface DevframeRpcServerFunctions { /** * Subscribe a client to a shared-state key. Wired by * `RpcSharedStateHost`; do not register manually. * * @internal */ 'devframe:rpc:server-state:subscribe': (key: string) => Promise; /** * Read the current value for a shared-state key. Wired by * `RpcSharedStateHost`; do not register manually. * * @internal */ 'devframe:rpc:server-state:get': (key: string) => Promise; /** * Replace a shared-state value (from the client). Wired by * `RpcSharedStateHost`; do not register manually. * * @internal */ 'devframe:rpc:server-state:set': (key: string, value: any, syncId: string) => Promise; /** * Apply a patch to a shared-state value (from the client). Wired by * `RpcSharedStateHost`; do not register manually. * * @internal */ 'devframe:rpc:server-state:patch': (key: string, patches: any[], syncId: string) => Promise; /** * Client→server streaming subscription with optional replay cursor. * Wired by `RpcStreamingHost`; do not register manually. * * @internal */ 'devframe:streaming:subscribe': (channel: string, id: string, opts?: { afterSeq?: number; }) => Promise; /** * Client→server streaming unsubscribe. Wired by `RpcStreamingHost`; * do not register manually. * * @internal */ 'devframe:streaming:unsubscribe': (channel: string, id: string) => Promise; /** * Client→server streaming cancellation request. Wired by * `RpcStreamingHost`; do not register manually. * * @internal */ 'devframe:streaming:cancel': (channel: string, id: string) => Promise; /** * Client→server upload chunk. Wired by `RpcStreamingHost`; do not * register manually. * * @internal */ 'devframe:streaming:upload-chunk': (channel: string, id: string, seq: number, chunk: any) => Promise; /** * Client→server upload terminator. Wired by `RpcStreamingHost`; do not * register manually. * * @internal */ 'devframe:streaming:upload-end': (channel: string, id: string, error?: { name: string; message: string; }) => Promise; } /** * To be extended */ interface DevframeRpcSharedStates {} //#endregion //#region src/types/utils.d.ts type Thenable = T | Promise; type EntriesToObject = { [K in T[number] as K[0]]: K[1] }; type PartialWithoutId = Partial> & { id: string; }; //#endregion //#region src/types/views.d.ts interface DevframeViewHost { /** * @internal */ buildStaticDirs: { baseUrl: string; distDir: string; }[]; /** * Helper to host static files * - In `dev` mode, it will register middleware to `viteServer.middlewares` to host the static files * - In `build` mode, it will copy the static files to the dist directory */ hostStatic: (baseUrl: string, distDir: string) => void; } //#endregion //#region src/utils/shared-state.d.ts type ImmutablePrimitive = undefined | null | boolean | string | number | Function; type Immutable = T extends ImmutablePrimitive ? T : T extends Array ? ImmutableArray : T extends Map ? ImmutableMap : T extends Set ? ImmutableSet : ImmutableObject; type ImmutableArray = ReadonlyArray>; type ImmutableMap = ReadonlyMap, Immutable>; type ImmutableSet = ReadonlySet>; type ImmutableObject = { readonly [K in keyof T]: Immutable }; /** * Serializable patch describing a single mutation to a `SharedState`. * Structurally compatible with JSON-Patch and is safe to send over RPC. */ interface SharedStatePatch { op: 'add' | 'remove' | 'replace'; path: readonly (string | number)[]; value?: unknown; } /** * State host that is immutable by default with explicit mutate. */ interface SharedState { /** * Get the current state. Immutable. */ value: () => Immutable; /** * Subscribe to state changes. */ on: EventEmitter>['on']; /** * Mutate the state. */ mutate: (fn: (state: T) => void, syncId?: string) => void; /** * Apply patches to the state. */ patch: (patches: SharedStatePatch[], syncId?: string) => void; /** * Sync IDs that have been applied to the state. */ syncIds: Set; } interface SharedStateEvents { updated: (fullState: T, patches: SharedStatePatch[] | undefined, syncId: string) => void; } interface SharedStateOptions { /** * Initial state. */ initialValue: T; /** * Enable patches. * * @default false */ enablePatches?: boolean; } declare function createSharedState(options: SharedStateOptions): SharedState; //#endregion //#region src/utils/streaming-channel.d.ts /** * Serialized error shape sent over the wire when a stream ends with a failure. * Stays JSON-safe so the strict-JSON encoder can carry it without coercion. */ interface StreamErrorPayload { name: string; message: string; } /** * Single buffered chunk in the server-side ring buffer. * * Sequence numbers start at 1 and increment per write. Subscribers track * `lastSeenSeq` and ask for `afterSeq` on resubscribe so the server can * replay any chunks the client missed during a brief disconnect. */ interface BufferedChunk { seq: number; chunk: T; } interface StreamSinkEvents { /** Fired for each `write()`. The RPC layer subscribes and broadcasts. */ chunk: (seq: number, chunk: T) => void; /** Terminal — fired exactly once per sink lifetime. */ end: (error?: StreamErrorPayload) => void; } interface CreateStreamSinkOptions { id?: string; /** * Size of the per-stream ring buffer kept for replay-on-resubscribe. * `0` (default) disables replay. */ replayWindow?: number; } /** * Server-side producer handle. Two equivalent surfaces share one piece of * state: the imperative `write/error/close` triple, and a `WritableStream` * for `pipeTo`-style consumption. */ interface StreamSink { /** Stable id used by clients to subscribe. */ readonly id: string; /** * Aborts when the consumer cancels (server-side) or when the transport * loses every subscriber. Producers should poll `signal.aborted` and exit * cleanly. */ readonly signal: AbortSignal; /** `true` after `close()` / `error()`. Further writes throw. */ readonly closed: boolean; /** Last allocated sequence number. `0` until the first write. */ readonly lastSeq: number; write: (chunk: T) => void; error: (reason: unknown) => void; close: () => void; /** External-cancel path. Aborts the signal so handlers can short-circuit. */ abort: (reason?: unknown) => void; /** `WritableStream` adapter — same in-memory state as the imperative API. */ readonly writable: WritableStream; /** * Internal — RPC layer subscribes to receive chunk/end notifications. * Not part of the public contract; do not call directly. * * @internal */ readonly events: EventEmitter>; /** * Internal — replay buffer. RPC layer reads on (re)subscribe to feed * missed chunks before going live. * * @internal */ readonly buffer: ReadonlyArray>; } interface CreateStreamReaderOptions { id?: string; /** * Maximum number of buffered chunks held client-side while the consumer * isn't draining. On overflow, the oldest chunk is dropped. */ highWaterMark?: number; /** * Called when the chunk queue overflows the high-water mark. The RPC * layer wires this to a coded warning; the primitive itself is * RPC-agnostic. */ onOverflow?: (dropped: number) => void; /** Called when the consumer cancels — the RPC layer sends `:cancel` upstream. */ onCancel?: () => void; } /** * Client-side consumer handle. Both an `AsyncIterable` (for `for await`) * and exposes `readable: ReadableStream` (for `pipeTo`). Pick one — they * share a single internal queue, so concurrent draining will race. */ interface StreamReader extends AsyncIterable { readonly id: string; readonly cancelled: boolean; readonly done: boolean; /** Highest `seq` observed. Used for replay on reconnect. */ readonly lastSeenSeq: number; /** `ReadableStream` adapter for `pipeTo`-style consumption. */ readonly readable: ReadableStream; cancel: () => void; /** @internal */ _push: (seq: number, chunk: T) => void; /** @internal */ _end: (error?: StreamErrorPayload) => void; } /** * Build a server-side stream sink. RPC-agnostic — the RPC host wires * `events.on('chunk' | 'end')` to broadcast, and reads `buffer` to replay * for late or reconnecting subscribers. */ declare function createStreamSink(options?: CreateStreamSinkOptions): StreamSink; /** * Build a client-side stream reader. RPC-agnostic — the RPC host calls * `_push(seq, chunk)` on each incoming chunk and `_end(error?)` on the * terminal frame. Consumers iterate with `for await` or pipe `readable`. */ declare function createStreamReader(options?: CreateStreamReaderOptions): StreamReader; //#endregion //#region src/types/rpc.d.ts interface DevframeNodeRpcSession { meta: DevframeNodeRpcSessionMeta; rpc: BirpcReturn; } interface RpcBroadcastOptions { method: METHOD; args: Args; optional?: boolean; event?: boolean; filter?: (client: BirpcReturn) => boolean | void; } type RpcFunctionsHost = RpcFunctionsCollectorBase & { /** * Invoke a locally registered server RPC function directly. * * This bypasses transport and is useful for server-side cross-function calls. */ invokeLocal: >(method: T, ...args: Args) => Promise>>; /** * Broadcast a message to all connected clients */ broadcast: >(options: RpcBroadcastOptions) => Promise; /** * Get the current RPC client * * Available in RPC functions to get the current RPC client */ getCurrentRpcSession: () => DevframeNodeRpcSession | undefined; /** * The shared state host */ sharedState: RpcSharedStateHost; /** * The streaming channel host. Provides per-channel `start()` / * `pipeFrom()` producers; clients consume via `rpc.streaming.subscribe()`. * * @see RpcStreamingHost */ streaming: RpcStreamingHost; }; interface RpcSharedStateGetOptions { sharedState?: SharedState; initialValue?: T; } interface RpcSharedStateHost { get: (key: T, options?: RpcSharedStateGetOptions) => Promise>; keys: () => string[]; /** * Subscribe to new shared-state keys becoming available. Fires when * `get(key, ...)` creates a fresh entry (not on subsequent gets). * Useful for protocol adapters (e.g. MCP) that surface shared state * as dynamic resources. */ onKeyAdded: (fn: (key: string) => void) => () => void; } /** * Options for `RpcStreamingHost.create()`. */ interface RpcStreamingChannelOptions { /** * Size of the per-stream ring buffer kept on the server for * replay-on-resubscribe. `0` (default) disables replay; on reconnect * the consumer only sees chunks that arrive after subscribing. * * The buffer is per stream id, not per channel — each `channel.start()` * gets its own. */ replayWindow?: number; /** * Milliseconds a closed stream is retained on the server after its * last subscriber leaves (or if no subscriber ever arrived). During * this window, late subscribers can still join and replay the buffer * + receive the `end` frame. * * Defaults to `30_000` (30 s) when `replayWindow > 0`, else `0` * (immediate free). Set to `0` to opt out, or higher for longer * post-mortem replay. */ closedStreamRetention?: number; } /** * Channel handle returned by `ctx.rpc.streaming.create(name, opts)`. A * channel owns a wire namespace; calling `start()` produces individual * streams keyed by id. * * @see {@link https://devfra.me/guide/streaming Streaming guide} */ interface RpcStreamingChannel { /** Channel name as registered with `ctx.rpc.streaming.create()`. */ readonly name: string; /** * Start a new stream. Returns a server-side sink with both an imperative * (`write` / `close` / `error`) surface and a `WritableStream` for * `pipeTo` consumption. The sink's `signal` aborts when every subscriber * disconnects or cancels. */ start: (opts?: { id?: string; }) => StreamSink; /** * Convenience: start a stream and pipe a `ReadableStream` into it. * The pipe uses `sink.signal` so cancellation propagates upstream. * * Node-stream interop: convert a `Readable` with `Readable.toWeb(node)` * before passing it here. */ pipeFrom: (readable: ReadableStream, opts?: { id?: string; }) => Promise>; /** Look up an active stream by id. Returns `undefined` if none. */ get: (id: string) => StreamSink | undefined; /** All active outbound stream ids on this channel. */ ids: () => string[]; /** * Open an inbound stream — the server side of a client-to-server * upload. Allocates an id, returns a `StreamReader` that fills as * the client writes chunks. Typical pattern is to call this from an * action handler, kick off background processing, and return the id * so the caller can start uploading: * * ```ts * handler: async () => { * const reader = channel.openInbound() * ;(async () => { * for await (const chunk of reader) processChunk(chunk) * })() * return { uploadId: reader.id } * } * ``` * * Calling `reader.cancel()` on the server sends an `upload-cancel` to * the uploading client, which aborts its sink. */ openInbound: (opts?: { id?: string; }) => StreamReader; } /** * Server-side streaming host. Lives on `ctx.rpc.streaming` alongside * `ctx.rpc.sharedState`. Each named channel owns its own stream registry * and wire namespace. */ interface RpcStreamingHost { /** * Register a streaming channel. Names follow the `:` * convention (e.g. `'my-devtool:chat-stream'`). Throws `DF0032` if the * name is already taken. */ create: (name: string, opts?: RpcStreamingChannelOptions) => RpcStreamingChannel; /** * Adapters call this when a session disconnects so the host can drop * subscribers and abort orphaned streams. Most users do not need this; * it's wired by `startHttpAndWs` automatically. * * @internal */ _onSessionDisconnected: (meta: DevframeNodeRpcSessionMeta) => void; } //#endregion //#region src/types/context.d.ts interface DevframeCapabilities { rpc?: boolean; views?: boolean; } /** * Framework- and build-tool-agnostic node context — RPC + diagnostics + * agent + the view-host (HTTP file-serving). Host adapters can wrap this * to add their own surfaces; for example, `@vitejs/devtools-kit`'s * `createKitContext` adds `docks`, `terminals`, `messages`, and * `commands` when mounted into Vite DevTools. */ interface DevframeNodeContext { readonly workspaceRoot: string; readonly cwd: string; /** * Lifecycle distinction surfaced to plugin authors: * * - `'dev'` — long-running, interactive session. Connections come and * go; broadcasts and shared-state mutations are debounced * to keep the UI responsive. * - `'build'` — one-shot batch run. The context is set up, the devtool * collects what it needs, and a snapshot is written. No * live UI, no WS server. * * Names are inherited from Vite's serve/build dichotomy but the meaning * is general: the same distinction applies to any tool that runs in * either an interactive or a static-output mode. */ readonly mode: 'dev' | 'build'; /** * Host runtime abstraction — exposes `mountStatic` / `resolveOrigin` / * `getStorageDir`. */ host: DevframeHost; rpc: RpcFunctionsHost; views: DevframeViewHost; /** * Structured diagnostics host — wraps `nostics` and lets integrations * register their own coded errors/warnings into the shared lookup. */ diagnostics: DevframeDiagnosticsHost; /** * Agent host — aggregates the agent-exposed surface of this devtool. * * @experimental */ agent: DevframeAgentHost; } interface ConnectionMeta { backend: 'websocket' | 'static'; websocket?: number | string; /** * Names of RPC functions that have declared `jsonSerializable: true`. * Used by the WS / static client to dispatch the per-call wire * serializer (strict JSON for these methods, structured-clone for * the rest). Populated by the server / build adapter; absent on * legacy clients, in which case all outgoing messages fall back to * structured-clone. */ jsonSerializableMethods?: string[]; } //#endregion //#region src/types/devframe.d.ts type DevframeRuntime = 'cli' | 'build' | 'spa' | 'vite' | 'embedded'; /** * Classification of how a devframe is being deployed. Hosted adapters * (`vite`, `embedded`) share their origin with a host app and must * namespace their mount path under `/__/`. Standalone adapters * (`cli`, `spa`, `build`) own the origin and default to `/`. */ type DevframeDeploymentKind = 'standalone' | 'hosted'; interface DevframeCliOptions { /** Binary name; default: the devframe's `id`. */ command?: string; /** Preferred port for the dev server (default 9999). */ port?: number; /** Port scan range, forwarded to `get-port-please`. */ portRange?: [number, number]; /** Prefer a random open port. */ random?: boolean; /** Default host to bind to; `--host` overrides. */ host?: string; /** * Auto-open the browser when the dev server starts. * `true` opens the resolved origin; a string opens that relative path. * The `--open` / `--no-open` flags override this. */ open?: boolean | string; /** * Skip the RPC trust handshake. Set to `false` for trusted * single-user localhost tools. Default `true`. * * Forwarded to `startHttpAndWs` as a no-op placeholder until devframe * ships its own auth layer; `@vitejs/devtools` honors the equivalent * `devtools.clientAuth` today. */ auth?: boolean; /** Author's SPA dist directory (served as the devframe's UI). */ distDir?: string; /** * Capability-side CAC hook. Called with the CAC instance after the * adapter registers its built-in commands (`build` / `spa` / `mcp`) * but before `createCli`'s own `configureCli` caller. Use this to * contribute tool-specific flags and subcommands from the definition * itself. */ configure?: (cli: CAC) => void; /** * Typed CLI flags for the default `dev` command, backed by valibot * schemas. The adapter registers matching `--kebab-key` options on * CAC, validates the parsed values, and forwards the typed bag to * `setup(ctx, { flags })`. * * Use {@link defineCliFlags} to preserve the literal schema-map * shape, and {@link InferCliFlags} to recover the typed output at the * call site: * * ```ts * const appFlags = defineCliFlags({ * depth: v.pipe(v.number(), v.integer()), * config: v.optional(v.string()), * }) * * defineDevframe({ * cli: { flags: appFlags }, * setup(ctx, info) { * const flags = info.flags as InferCliFlags * }, * }) * ``` */ flags?: CliFlagsSchema; } interface DevframeSpaOptions { base?: string; /** * How the deployed SPA loads its data. * - `'query'` — read from URL search params. * - `'upload'` — accept a file drag-drop. * - `'none'` — use the baked RPC dump only. */ loader?: 'query' | 'upload' | 'none'; } interface DevframeBrowserContext { /** * The connected RPC client (may be write-disabled in static/spa modes). */ rpc: unknown; } /** * Runtime information threaded into `setup(ctx, info)`. Adapters * populate the fields that make sense for their deployment. In * particular, `createCli` fills `flags` with the parsed CAC bag. */ interface DevframeSetupInfo { /** Parsed CLI flags, populated by the CLI adapter. */ flags?: Record; } interface DevframeDefinition { id: string; name: string; icon?: string | { light: string; dark: string; }; version?: string; /** * Mount path override. Defaults depend on the adapter: * `/` for standalone (`cli` / `spa` / `build`), `/__/` for hosted * (`vite` / `embedded`). */ basePath?: string; capabilities?: { dev?: boolean | Record; build?: boolean | Record; spa?: boolean | Record; }; /** Server-side setup — the primary entrypoint. Runs in every runtime. */ setup: (ctx: DevframeNodeContext, info?: DevframeSetupInfo) => void | Promise; /** Browser-only setup for the SPA adapter (bundled into the client). */ setupBrowser?: (ctx: DevframeBrowserContext) => void | Promise; cli?: DevframeCliOptions; spa?: DevframeSpaOptions; } declare function defineDevframe(d: DevframeDefinition): DevframeDefinition; //#endregion export { AgentResource as $, ImmutableArray as A, EntriesToObject as B, StreamErrorPayload as C, createStreamReader as D, StreamSinkEvents as E, SharedStateEvents as F, DevframeRpcSharedStates as G, Thenable as H, SharedStateOptions as I, DevframeDiagnosticsDefinition as J, DevframeHost as K, SharedStatePatch as L, ImmutableObject as M, ImmutableSet as N, createStreamSink as O, SharedState as P, AgentManifest as Q, createSharedState as R, CreateStreamSinkOptions as S, StreamSink as T, DevframeRpcClientFunctions as U, PartialWithoutId as V, DevframeRpcServerFunctions as W, DevframeDiagnosticsLogger as X, DevframeDiagnosticsHost as Y, AgentHandle as Z, RpcStreamingChannel as _, DevframeRuntime as a, DevframeAgentHostEvents as at, BufferedChunk as b, defineDevframe as c, EventsMap as ct, DevframeNodeContext as d, defineCliFlags as dt, AgentResourceContent as et, DevframeNodeRpcSession as f, parseCliFlags as ft, RpcSharedStateHost as g, RpcSharedStateGetOptions as h, DevframeDeploymentKind as i, DevframeAgentHost as it, ImmutableMap as j, Immutable as k, ConnectionMeta as l, CliFlagsSchema as lt, RpcFunctionsHost as m, DevframeCliOptions as n, AgentTool as nt, DevframeSetupInfo as o, EventEmitter as ot, RpcBroadcastOptions as p, DevframeDefineDiagnosticsOptions as q, DevframeDefinition as r, AgentToolInput as rt, DevframeSpaOptions as s, EventUnsubscribe as st, DevframeBrowserContext as t, AgentResourceInput as tt, DevframeCapabilities as u, InferCliFlags as ut, RpcStreamingChannelOptions as v, StreamReader as w, CreateStreamReaderOptions as x, RpcStreamingHost as y, DevframeViewHost as z };