diff --git a/AGENTS.md b/AGENTS.md
index bb802995b..c579c0721 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -58,7 +58,7 @@ Ahead-of-time build artifacts that live under `src/` - the shadow-root styleshee
## Conventions
- RPC functions must use `defineRpcFunction`; always namespace IDs `devframes:plugin::` for built-in devframes (the literal `plugin:` token mirrors the `@devframes/plugin-` package name on the wire - it is npm namespacing, not a concept).
-- **No magic event names — use the centralized event maps.** Every event, broadcast, shared-state key, and channel name lives in one of two source-of-truth maps: `DEVFRAME_EVENTS` (`packages/devframe/src/events.ts`, re-exported from `devframe/constants`) for the core runtime, and `HUB_EVENTS` (`packages/hub/src/events.ts`, re-exported from `@devframes/hub/constants`) for the hub. Reference `DEVFRAME_EVENTS.*` / `HUB_EVENTS.*` at call sites (`.events.emit`/`.on`, `rpc.broadcast({ method })`, `sharedState.get(key)`, `defineHubRpcFunction({ name })`, `rpc.call`) instead of re-typing a string literal. The two maps and the [`docs/content/8.references/3.events.md`](docs/content/8.references/3.events.md) Events Reference are kept in lockstep: adding, renaming, or removing a name means editing the map **and** that page in the same change — every name in the maps appears in the tables, and vice versa. The only literals left are unavoidable type-position keys (the `EventEmitter<…>` maps in `types/*` and the `DevframeRpcClientFunctions`/`DevframeRpcServerFunctions` augmentations), which mirror the maps; a package that deliberately avoids a hub dependency (e.g. `@devframes/plugin-terminals`, which models the hub bridge structurally) keeps a local literal rather than importing `HUB_EVENTS`.
+- **No magic event names: use the centralized event maps.** Every event, broadcast, shared-state key, and channel name lives in one of two source-of-truth maps: `DEVFRAME_EVENTS` (`packages/devframe/src/events.ts`, re-exported from `devframe/constants`) for the core runtime, and `HUB_EVENTS` (`packages/hub/src/events.ts`, re-exported from `@devframes/hub/constants`) for the hub. Reference `DEVFRAME_EVENTS.*` / `HUB_EVENTS.*` at call sites (`.events.emit`/`.on`, `rpc.broadcast({ method })`, `sharedState.get(key)`, `defineHubRpcFunction({ name })`, `rpc.call`) instead of re-typing a string literal. The two maps and the [`docs/content/8.references/3.events.md`](docs/content/8.references/3.events.md) Events Reference are kept in lockstep: adding, renaming, or removing a name means editing the map **and** that page in the same change; every name in the maps appears in the tables, and vice versa. The only literals left are unavoidable type-position keys (the `EventEmitter<…>` maps in `types/*` and the `DevframeRpcClientFunctions`/`DevframeRpcServerFunctions` augmentations), which mirror the maps; a package that deliberately avoids a hub dependency (e.g. `@devframes/plugin-terminals`, which models the hub bridge structurally) keeps a local literal rather than importing `HUB_EVENTS`.
- **Stay validator-neutral.** `devframe` and every `@devframes/*` package must not introduce a preferred schema validator dependency - no `valibot`, `zod`, `arktype`, etc. in their runtime `dependencies`. `args`/`returns`/flag schemas are typed against [Standard Schema](https://standardschema.dev/) (`@standard-schema/spec`, types-only); first-party code that needs to author a schema uses the built-in zero-dep `devframe/utils/simple-schema` builder (deliberately minimal - not a general validator). JSON-schema conversion uses each schema's own Standard JSON Schema converter (`~standard.jsonSchema`, implemented by e.g. zod 4) when present and degrades to a permissive object otherwise - no converter library and no vendor dependency is required. Docs, by contrast, should point *users* at a real validator for their own integrations - recommend **valibot** (lightest) or **zod** (worth reusing if they already pull it via the JSON-render or MCP integrations).
- Shared state via `devframe/utils/shared-state`; keep values serializable.
- Utility imports use the package-path form `devframe/utils/*`, never relative `../utils/*`.
diff --git a/bump.config.ts b/bump.config.ts
index 23e9c7a70..67d43ea5b 100644
--- a/bump.config.ts
+++ b/bump.config.ts
@@ -5,10 +5,12 @@ import { syncStarterVersion } from './scripts/sync-starter-version.ts'
export default defineConfig({
all: true,
- // `starter/` pins real `devframe`/`@devframes/*` versions (it's a
- // copy-paste-ready template, not a workspace member consuming
- // `catalog:`/`workspace:*`), so `bumpp -r` can't reach it on its own -
- // sync it here, before the version-bump commit is made.
+ /**
+ * `starter/` pins real `devframe`/`@devframes/*` versions (it's a
+ * copy-paste-ready template, not a workspace member consuming
+ * `catalog:`/`workspace:*`), so `bumpp -r` can't reach it on its own -
+ * sync it here, before the version-bump commit is made.
+ */
execute: async (operation) => {
await syncStarterVersion(operation.state.newVersion)
await x('pnpm', ['install', '--frozen-lockfile=false'], { nodeOptions: { stdio: 'inherit', cwd: process.cwd() } })
diff --git a/design/build-shadow-css.ts b/design/build-shadow-css.ts
index f364265f5..68f410d84 100644
--- a/design/build-shadow-css.ts
+++ b/design/build-shadow-css.ts
@@ -38,7 +38,7 @@ export interface BuildShadowCssOptions {
userStylePath?: string | readonly string[]
/**
* Prefix Wind's `--un-*` custom properties are renamed to (see
- * `namespaceShadowCssVars`) — unique per shadow-root surface so two
+ * `namespaceShadowCssVars`), unique per shadow-root surface so two
* shadow trees on the same host page never collide.
*/
varPrefix: string
@@ -51,15 +51,17 @@ export interface BuildShadowCssResult {
css: string
}
-// Compile a shadow-root surface's UnoCSS output ahead of time into a plain
-// string module (`/.generated/css.ts`) that the surface adopts into
-// its shadow root — fully styled inside any host page without a global
-// stylesheet, and immune to the host page's own styles leaking in. Shared by
-// `@devframes/hub-ui`'s dock and `@devframes/json-render-ui`'s renderer
-// module: same pipeline, same two shadow-root gotchas (see the root
-// AGENTS.md "Design system" section), different source globs. Writes the
-// generated file itself; returns stats so each caller (a `scripts/` entry,
-// exempt from the `no-console` lint rule) prints its own summary line.
+/**
+ * Compile a shadow-root surface's UnoCSS output ahead of time into a plain
+ * string module (`/.generated/css.ts`) that the surface adopts into
+ * its shadow root, fully styled inside any host page without a global
+ * stylesheet, and immune to the host page's own styles leaking in. Shared by
+ * `@devframes/hub-ui`'s dock and `@devframes/json-render-ui`'s renderer
+ * module: same pipeline, same two shadow-root gotchas (see the root
+ * AGENTS.md "Design system" section), different source globs. Writes the
+ * generated file itself; returns stats so each caller (a `scripts/` entry,
+ * exempt from the `no-console` lint rule) prints its own summary line.
+ */
export async function buildShadowCss(options: BuildShadowCssOptions): Promise {
const { srcDir, globs, config, primaryRampPath, userStylePath, varPrefix } = options
const generatedCss = join(srcDir, '.generated/css.ts')
@@ -75,7 +77,7 @@ export async function buildShadowCss(options: BuildShadowCssOptions): Promise, { label: s
error: { label: 'error', dot: 'bg-error' },
}
-// The shared top-nav connection indicator: a small status dot + label. Returns
-// `null` when the client is `connected`, so every surface renders the indicator
-// only while the connection is not live.
+/**
+ * The shared top-nav connection indicator: a small status dot + label. Returns
+ * `null` when the client is `connected`, so every surface renders the indicator
+ * only while the connection is not live.
+ */
export function connectionIndicator(status: ConnectionStatus, extra?: string): ConnectionIndicator | null {
if (status === 'connected')
return null
@@ -167,18 +171,22 @@ const CONNECTION_STATE: Record, Connectio
},
}
-// The shared full-panel connection state copy: shown whenever the client isn't
-// `connected`, so a surface never sits on an infinite spinner without saying
-// why. Returns `null` when connected. Pair with the `connection*` class builders
-// below so every surface renders the identical centered glyph + title + body.
+/**
+ * The shared full-panel connection state copy: shown whenever the client isn't
+ * `connected`, so a surface never sits on an infinite spinner without saying
+ * why. Returns `null` when connected. Pair with the `connection*` class builders
+ * below so every surface renders the identical centered glyph + title + body.
+ */
export function connectionState(status: ConnectionStatus): ConnectionStateCopy | null {
if (status === 'connected')
return null
return CONNECTION_STATE[status]
}
-// Centered fill for the full-panel state; each surface adds its own fill
-// strategy (`h-full`, `h-svh w-full`, `absolute inset-0`, …) via `extra`.
+/**
+ * Centered fill for the full-panel state; each surface adds its own fill
+ * strategy (`h-full`, `h-svh w-full`, `absolute inset-0`, …) via `extra`.
+ */
export function connectionPanel(extra?: string): string {
return cx('flex flex-col items-center justify-center gap-4 bg-base p-8 text-center', extra)
}
diff --git a/design/dock-icon.ts b/design/dock-icon.ts
index 7a9836afa..8e77fe2ff 100644
--- a/design/dock-icon.ts
+++ b/design/dock-icon.ts
@@ -5,7 +5,7 @@
// `ph:git-branch-duotone`) to its live, sanitized SVG markup, fetched from the
// public `api.iconify.design` CDN. Unlike a UnoCSS `preset-icons` class, this
// needs no `@iconify-json/*` collection installed and no hand-maintained
-// id -> class table — any Iconify id just works, at the cost of a network
+// id -> class table, since any Iconify id just works, at the cost of a network
// round-trip on first render. We reuse @antfu/design's own fetcher, cache and
// sanitizer (`utils/iconify.ts`) rather than reimplementing them; only the id
// parsing and light/dark selection below are devframe-specific, mirroring the
@@ -19,7 +19,7 @@ const ICONIFY_ID = /^(?:i-)?([\w-]+):([\w-]+)$/
/**
* Resolve a dock icon (a `collection:icon` string, or a `{ light, dark }`
- * pair — the `light` variant is fetched) to its sanitized SVG markup.
+ * pair whose `light` variant is fetched) to its sanitized SVG markup.
*
* Returns `undefined` when the id doesn't parse or the fetch fails, so the
* caller can fall back to a text initial.
diff --git a/design/uno.config.ts b/design/uno.config.ts
index 617f876a5..297cad0a4 100644
--- a/design/uno.config.ts
+++ b/design/uno.config.ts
@@ -17,7 +17,7 @@ export interface CreateDesignConfigOptions {
* json-render renderer module) pass `presetWind3()` instead: Wind4 registers
* its theme + `--un-*` custom properties via `@property { inherits: false }`
* and keeps them in a document `:root {}` block, neither of which reaches a
- * shadow tree — so its `color-mix(var(--colors-*))` utilities resolve to
+ * shadow tree, so its `color-mix(var(--colors-*))` utilities resolve to
* nothing there. Wind3 bakes the same `@antfu/design` semantic utilities to
* concrete `rgb()` + `.dark` variants, which are self-contained inside a
* shadow root.
@@ -25,17 +25,19 @@ export interface CreateDesignConfigOptions {
base?: Preset | Preset[]
}
-// Shared devframe UnoCSS base. Every plugin and example composes `@antfu/design`
-// the same way — its preset (tuned to devframe's sage green) over a Wind base,
-// Phosphor icons, DM Sans/Mono web fonts, and the directive/variant-group
-// transformers — so the surfaces look and feel like one product across
-// frameworks. Each app extends this via `mergeConfigs([designConfig, { … }])`
-// and contributes only its own extraction globs (and any safelist).
-//
-// The shared web fonts (`sans`/`mono`), the named `z-*` layers and the `h-nav`
-// navbar height live here so every surface shares one font stack, one z-index
-// scale and one fixed navbar height. The `@antfu/design` preset blocks plain
-// `z-`, so the layers are named on purpose.
+/**
+ * Shared devframe UnoCSS base. Every plugin and example composes `@antfu/design`
+ * the same way: its preset (tuned to devframe's sage green) over a Wind base,
+ * Phosphor icons, DM Sans/Mono web fonts, and the directive/variant-group
+ * transformers, so the surfaces look and feel like one product across
+ * frameworks. Each app extends this via `mergeConfigs([designConfig, { … }])`
+ * and contributes only its own extraction globs (and any safelist).
+ *
+ * The shared web fonts (`sans`/`mono`), the named `z-*` layers and the `h-nav`
+ * navbar height live here so every surface shares one font stack, one z-index
+ * scale and one fixed navbar height. The `@antfu/design` preset blocks plain
+ * `z-`, so the layers are named on purpose.
+ */
export function createDesignConfig(options: CreateDesignConfigOptions = {}) {
const base = options.base ?? presetWind4()
return defineConfig({
@@ -45,19 +47,23 @@ export function createDesignConfig(options: CreateDesignConfigOptions = {}) {
presetIcons({ scale: 1.1 }),
],
transformers: [transformerDirectives(), transformerVariantGroup()],
- // The shared class-helper builders (`design/design.ts`) assemble their class
- // chains at runtime, so every app scans that one file (it carries
- // `@unocss-include`) for extraction regardless of its own framework globs.
+ /**
+ * The shared class-helper builders (`design/design.ts`) assemble their class
+ * chains at runtime, so every app scans that one file (it carries
+ * `@unocss-include`) for extraction regardless of its own framework globs.
+ */
content: {
filesystem: [fileURLToPath(new URL('./design.ts', import.meta.url))],
},
- // Wind leaves bare `border`/`border-b` at currentColor; restore the subtle
- // shared border color (matching `border-base`) for unqualified borders.
+ /**
+ * Wind leaves bare `border`/`border-b` at currentColor; restore the subtle
+ * shared border color (matching `border-base`) for unqualified borders.
+ */
preflights: [{ getCSS: () => '*,::before,::after{border-color:#8882}' }],
shortcuts: {
- // Fixed navbar height, shared by every surface's top nav.
+ /** Fixed navbar height, shared by every surface's top nav. */
'h-nav': 'h-10',
- // Named z-index layers, shared across every surface.
+ /** Named z-index layers, shared across every surface. */
'z-nav': 'z-[30]',
'z-dropdown': 'z-[40]',
'z-tooltip': 'z-[45]',
@@ -70,7 +76,7 @@ export function createDesignConfig(options: CreateDesignConfigOptions = {}) {
})
}
-// The default shared base (Wind4), consumed by every plugin and example.
+/** The default shared base (Wind4), consumed by every plugin and example. */
export const designConfig = createDesignConfig()
/**
@@ -91,7 +97,7 @@ export const designConfig = createDesignConfig()
* declared, so a host page built with Wind4 registers `--un-bg-opacity` /
* `--un-border-opacity` / `--un-text-opacity` (et al.) as
* `@property { syntax: ''; inherits: false }` for the whole
- * document — including inside our shadow tree. Our shadow CSS is Wind3, which
+ * document, including inside our shadow tree. Our shadow CSS is Wind3, which
* sets those same vars **unitless** (`--un-border-opacity: 0.13`), so the
* global `` registration makes every such declaration invalid and
* the dependent `color-mix()` / `rgb(… / var(--un-*))` value collapses (a
@@ -100,9 +106,9 @@ export const designConfig = createDesignConfig()
* The shadow stylesheet sets and reads these vars entirely within itself, so
* renaming every `--un-` to a per-surface prefix (`--un-jr-`, `--un-hub-`)
* keeps it self-consistent while making it immune to whatever the host page
- * registered — the renamed names are distinct properties the host's
+ * registered, since the renamed names are distinct properties the host's
* `@property --un-*` rules never match. Apply only to shadow-injected CSS
- * (`hub-ui` dock, `json-render-ui` renderer module) — the Vite-served SPAs own
+ * (`hub-ui` dock, `json-render-ui` renderer module); the Vite-served SPAs own
* their whole document and need no rename.
*
* @param css - The compiled shadow-root stylesheet.
@@ -145,15 +151,15 @@ function hexToRgbTriplet(hex: string): string | undefined {
* variables `primary-ramp.css` derives from `--devframe-primary`.
*
* Wind3 (unlike Wind4) resolves each theme color to a literal `rgb(r g b /
- * )` at compile time — the `` slot is already dynamic (a slash
+ * )` at compile time, and the `` slot is already dynamic (a slash
* literal, or the utility's own `--un-*-opacity` variable), but the base `r g
* b` triplet is baked in, so every `primary`-based utility (`text-primary`,
* `bg-primary`, `btn-primary`, `ring-primary-500`, …) ignores
- * `--devframe-primary` entirely — only hand-written rules that already
+ * `--devframe-primary` entirely; only hand-written rules that already
* reference `--colors-primary-*` directly (the dock's glow gradient,
* `primary-ramp.css` itself) retint. Swapping the baked triplet for `from
* var(--colors-primary-, ) r g b` keeps that exact alpha
- * mechanism intact while sourcing the base color from the variable — a
+ * mechanism intact while sourcing the base color from the variable, so a
* rebrand's `--devframe-primary` now reaches every baked utility too.
*
* Call once per generated pass, after `generator.generate(...)`, passing the
diff --git a/docs/app/app.config.ts b/docs/app/app.config.ts
index f4ffc6ef4..72499d530 100644
--- a/docs/app/app.config.ts
+++ b/docs/app/app.config.ts
@@ -66,8 +66,10 @@ export default defineAppConfig({
},
docs: {
- // Labeled sidebar groups per content section, consumed by the shadowed
- // `useFilteredNavigation` composable (mirrors the old VitePress sidebar).
+ /**
+ * Labeled sidebar groups per content section, consumed by the shadowed
+ * `useFilteredNavigation` composable (mirrors the old VitePress sidebar).
+ */
sidebarGroups: {
guide: [
{
@@ -132,11 +134,11 @@ export default defineAppConfig({
},
llms: {
description:
- 'Framework-neutral foundation for building devtools — one definition becomes a Web Standard handler, a CLI, a static report, an MCP server, or a hub dock.',
+ 'Framework-neutral foundation for building devtools: one definition becomes a Web Standard handler, a CLI, a static report, an MCP server, or a hub dock.',
},
schemaOrg: {
description:
- 'Framework-neutral foundation for building devtools — RPC layer, hosts, and adapters.',
+ 'Framework-neutral foundation for building devtools: RPC layer, hosts, and adapters.',
applicationCategory: 'DeveloperApplication',
operatingSystem: 'Any',
license: 'https://github.com/devframes/devframe/blob/main/LICENSE.md',
diff --git a/docs/app/components/global/GettingStartedWizard.vue b/docs/app/components/global/GettingStartedWizard.vue
index 9058d7900..aafc25dbe 100644
--- a/docs/app/components/global/GettingStartedWizard.vue
+++ b/docs/app/components/global/GettingStartedWizard.vue
@@ -3,8 +3,8 @@
* Interactive "what should I read" wizard for the Getting Started guide.
*
* Every question is a grid of selectable cards (multiple answers allowed per
- * question, since a real devtool usually spans more than one answer — e.g.
- * it reads from both the node side and the user's web app). Selections
+ * question, since a real devtool usually spans more than one answer: for
+ * example, it reads from both the node side and the user's web app). Selections
* persist to `localStorage` so a reader can leave the page and pick up where
* they left off; the recommended reading list at the bottom recomputes from
* whatever is currently checked.
@@ -126,22 +126,22 @@ const DOC_CATALOG: Record = {
'/guide/rpc': { title: 'RPC', description: 'Type-safe, bidirectional calls between the node side and the browser side.', icon: 'i-lucide-cable' },
'/guide/shared-state': { title: 'Shared State', description: 'Observable state synced between the node side and every RPC client.', icon: 'i-lucide-refresh-cw' },
'/guide/streaming': { title: 'Streaming', description: 'Push chunk-style data from the node side to the browser side.', icon: 'i-lucide-radio' },
- '/guide/client-assets': { title: 'Client Assets', description: 'Where a devframe\'s built SPA lives — a local directory or an npm package.', icon: 'i-lucide-folder-tree' },
+ '/guide/client-assets': { title: 'Client Assets', description: 'Where a devframe\'s built SPA lives: a local directory or an npm package.', icon: 'i-lucide-folder-tree' },
'/guide/client': { title: 'Client', description: 'Connects any surface to a devframe\'s node side with RPC and shared state.', icon: 'i-lucide-plug' },
'/guide/transports': { title: 'Transports', description: 'Live RPC over WebSocket or SSE, transparent to your RPC code.', icon: 'i-lucide-waypoints' },
'/guide/security': { title: 'Security', description: 'Localhost binding and a trust handshake before a browser can call RPC.', icon: 'i-lucide-shield-check' },
'/guide/agent-native': { title: 'Agent-Native Devframe', description: 'Expose RPC functions, resources, and shared state to coding agents over MCP.', icon: 'i-lucide-bot' },
- '/guide/hub': { title: 'Hub', description: 'Orchestrate many devtools sharing one UI — docks, terminals, messages, commands.', icon: 'i-lucide-layout-dashboard' },
+ '/guide/hub': { title: 'Hub', description: 'Orchestrate many devtools sharing one UI: docks, terminals, messages, commands.', icon: 'i-lucide-layout-dashboard' },
'/guide/client-context': { title: 'Client Scripts & Client Context', description: 'How a dock client script runs a devframe\'s code inside the host page.', icon: 'i-lucide-code' },
'/guide/hub-initiate': { title: 'Serve a Hub Anywhere', description: 'initHub() serves a whole multi-devframe install from one handler.', icon: 'i-lucide-server-cog' },
'/guide/services': { title: 'Cross-Devframe Services', description: 'Expose a typed, namespaced capability to every devframe in a hub.', icon: 'i-lucide-share-2' },
'/guide/deep-linking': { title: 'Deep Linking', description: 'Send a user to a specific view inside a devframe from a URL or an agent.', icon: 'i-lucide-link' },
- '/guide/json-render': { title: 'JSON-Render', description: 'Describe a UI as data — a serializable component spec any frontend renders.', icon: 'i-lucide-braces' },
+ '/guide/json-render': { title: 'JSON-Render', description: 'Describe a UI as data: a serializable component spec any frontend renders.', icon: 'i-lucide-braces' },
'/guide/build-your-own-json-render-frontend': { title: 'Build Your Own JSON-Render Frontend', description: 'Implement the renderer contract in your own framework instead of the reference one.', icon: 'i-lucide-component' },
- '/guide/build-your-own-hub-ui': { title: 'Build Your Own Hub UI', description: 'The two contracts a hub UI provider implements — node side and browser side.', icon: 'i-lucide-layout-panel-left' },
+ '/guide/build-your-own-hub-ui': { title: 'Build Your Own Hub UI', description: 'The two contracts a hub UI provider implements: node side and browser side.', icon: 'i-lucide-layout-panel-left' },
'/guide/standalone-cli': { title: 'Standalone CLI with Devframe', description: 'npx my-tool starts a dev server serving your SPA over type-safe RPC.', icon: 'i-lucide-terminal' },
'/references/interactive-auth': { title: 'Interactive Auth', description: 'An OTP auth layer over devframe\'s node-side primitives.', icon: 'i-lucide-key-round' },
- '/references/utilities': { title: 'Utilities', description: 'Small, stable helpers bundled into devframe — no npm install.', icon: 'i-lucide-wrench' },
+ '/references/utilities': { title: 'Utilities', description: 'Small, stable helpers bundled into devframe, no npm install.', icon: 'i-lucide-wrench' },
'/adapters': { title: 'Adapters', description: 'Every path from a DevframeDefinition to a running devframe.', icon: 'i-lucide-shuffle' },
'/adapters/initiate': { title: 'The Standard Handler', description: 'initDevframe() turns a definition into a Web Standard Request → Response handler.', icon: 'i-lucide-server' },
'/adapters/cac': { title: 'CLI (cac)', description: 'A cac CLI around a DevframeDefinition with dev, build, and mcp commands.', icon: 'i-lucide-square-terminal' },
diff --git a/docs/content/1.guide/1.tutorial-server-data-inspector.md b/docs/content/1.guide/1.tutorial-server-data-inspector.md
index 6e75b06f1..48cfbe90b 100644
--- a/docs/content/1.guide/1.tutorial-server-data-inspector.md
+++ b/docs/content/1.guide/1.tutorial-server-data-inspector.md
@@ -13,7 +13,7 @@ You'll need [Node 24+](https://nodejs.org/) and a terminal. Every code block is
A devframe is two halves talking over a typed connection: the **node side** exposes functions, and the **browser side** calls them and renders the results. Devframe is everything in between: the wire, the UI hosting, auth, builds, and a CLI.
-## Step 1 — Define the tool
+## Step 1: Define the tool
Everything starts with `defineDevframe`: your tool's name, plus a `setup` where you register what it can do. Create the project and the definition:
@@ -26,7 +26,7 @@ npm install devframe && npm install -D typescript
```ts [src/data-inspector.ts]
import { defineDevframe } from 'devframe'
-// Some example server-side data — whatever you want to peek at while your
+// Some example server-side data, whatever you want to peek at while your
// user app runs: config, a cache, a DB handle.
const serverState = {
config: { name: 'Acme', port: 3000, debug: false },
@@ -86,9 +86,9 @@ export default dataInspectorFrame
`ctx.rpc.register` publishes a function the browser side can call: a namespaced `name`, a `type` (`query` is read-only), and a `handler` that takes the call's arguments and returns JSON. That's the whole node side. ([RPC](/guide/rpc) has the other types; [Devframe Definition](/guide/devframe-definition) has every field.)
-## Step 2 — Add a UI
+## Step 2: Add a UI
-Now the browser side. We'll use React here, but any framework works — the only devframe-specific line is `connectDevframe`, which opens the connection back to the node side.
+Now the browser side. We'll use React here, but any framework works; the only devframe-specific line is `connectDevframe`, which opens the connection back to the node side.
```sh
npm install react react-dom @devframes/vite
@@ -167,9 +167,9 @@ export function App() {
}
```
-`client.call(name, ...args)` reaches your handlers. (We cast `.call` and call by name here; wire up a typed registry and every call is checked end to end — see [RPC](/guide/rpc).)
+`client.call(name, ...args)` reaches your handlers. (We cast `.call` and call by name here; wire up a typed registry and every call is checked end to end; see [RPC](/guide/rpc).)
-## Step 3 — Run it in development
+## Step 3: Run it in development
To try what we've built, let Vite serve the UI and hand RPC traffic to devframe:
@@ -199,20 +199,20 @@ npx vite --config vite.client.config.ts
Open the printed URL. The three keys and their types show up, and typing `config.port` or `users.0.name` and hitting **Query** prints the value. Button → `call` → your `handler` → back to the page: that's the whole devframe working.
> [!WARNING]
-> `auth: false` trusts anything that can reach the port. It's off here to keep the tutorial simple — turn it on for anything you publish or expose beyond localhost. See [Security](/guide/security).
+> `auth: false` trusts anything that can reach the port. It's off here to keep the tutorial simple; turn it on for anything you publish or expose beyond localhost. See [Security](/guide/security).
From here on we reuse this same `src/data-inspector.ts` and `client/` unchanged; all that changes is where they run.
-## Step 4 — Dock it in a hub
+## Step 4: Dock it in a hub
-A [hub](/guide/hub) puts many devframes behind one interface, each a **dock entry** you switch between — the tool's own UI in an iframe. Since our SPA uses a bare `connectDevframe()`, it already works anywhere; the hub just needs the built UI, so point the definition at it:
+A [hub](/guide/hub) puts many devframes behind one interface, each a **dock entry** you switch between, the tool's own UI in an iframe. Since our SPA uses a bare `connectDevframe()`, it already works anywhere; the hub just needs the built UI, so point the definition at it:
```ts [src/data-inspector.ts]
import { fileURLToPath } from 'node:url'
// …
const dataInspectorFrame = defineDevframe({
id: 'data-inspector',
- // …
+ /** … */
clientAssets: fileURLToPath(new URL('../dist/client', import.meta.url)),
setup(ctx) { /* unchanged */ },
})
@@ -245,11 +245,11 @@ export default defineConfig({
npx vite --config vite.hub.config.ts
```
-Your inspector now sits in the hub's dock rail as a dock entry. Add more to `devframes: [...]` — your own or the [built-in devframes](/add-ons) — and each gets its own. (The hub prints a code to authorize on first connect.)
+Your inspector now sits in the hub's dock rail as a dock entry. Add more to `devframes: [...]` (your own or the [built-in devframes](/add-ons)) and each gets its own. (The hub prints a code to authorize on first connect.)
-## Step 5 — Build a static version
+## Step 5: Build a static version
-Some tools should work with no node side at all — a report you can drop on any static hosting. `createBuild` renders the UI and **bakes in** the results of read-only calls. Opt one in with `snapshot: true`:
+Some tools should work with no node side at all: a report you can drop on any static hosting. `createBuild` renders the UI and **bakes in** the results of read-only calls. Opt one in with `snapshot: true`:
```ts
ctx.rpc.register({
@@ -275,9 +275,9 @@ npx vite build # refresh dist/client
node scripts/build.mjs # → dist-static/
```
-Serve `dist-static/` anywhere and the meta list renders from the baked snapshot, no Node in sight. `query` takes an argument, so it still needs the live node side (next) — or you can bake specific inputs ([Client Assets](/guide/client-assets)).
+Serve `dist-static/` anywhere and the meta list renders from the baked snapshot, no Node in sight. `query` takes an argument, so it still needs the live node side (next), or you can bake specific inputs ([Client Assets](/guide/client-assets)).
-## Step 6 — Run it standalone
+## Step 6: Run it standalone
The definition never depended on Vite. `createDevServer` runs the tool on its own, serving the UI from `clientAssets` and answering RPC live:
@@ -293,9 +293,9 @@ npx vite build
node scripts/serve.mjs
```
-Same UI, same live calls, no bundler in the loop — this is what you'd drop into your own Node program.
+Same UI, same live calls, no bundler in the loop: this is what you'd drop into your own Node program.
-## Step 7 — Give it a CLI
+## Step 7: Give it a CLI
Finally, wrap that dev server in a CLI. `devframe/adapters/cac` turns a devframe into a CLI with `dev`, `build`, and `mcp` commands:
@@ -321,7 +321,7 @@ That's it for this tutorial. For a full-featured version, there's a ready-to-use
## What's next
-- [RPC](/guide/rpc) — `action` and `event` calls, end-to-end types, schema validation
-- [Shared State](/guide/shared-state) — push live changes to the UI without polling
-- [Hub](/guide/hub) — docks, commands, terminals across many tools
-- [Agent-Native](/guide/agent-native) — expose your tool to coding agents over MCP
+- [RPC](/guide/rpc): `action` and `event` calls, end-to-end types, schema validation
+- [Shared State](/guide/shared-state): push live changes to the UI without polling
+- [Hub](/guide/hub): docks, commands, terminals across many tools
+- [Agent-Native](/guide/agent-native): expose your tool to coding agents over MCP
diff --git a/docs/content/1.guide/10.standalone-cli.md b/docs/content/1.guide/10.standalone-cli.md
index 99fe7531d..908f75d12 100644
--- a/docs/content/1.guide/10.standalone-cli.md
+++ b/docs/content/1.guide/10.standalone-cli.md
@@ -131,7 +131,7 @@ defineDevframe({
})
```
-Call `connectDevframe()` in a Client Component — see [Client](/guide/client) and [`examples/next-runtime-snapshot`](https://github.com/devframes/devframe/tree/main/examples/next-runtime-snapshot).
+Call `connectDevframe()` in a Client Component; see [Client](/guide/client) and [`examples/next-runtime-snapshot`](https://github.com/devframes/devframe/tree/main/examples/next-runtime-snapshot).
## Connecting from the browser side
@@ -144,7 +144,7 @@ export async function fetchPayload() {
}
```
-Otherwise call `connectDevframe()`, which auto-resolves the connection descriptor relative to the page — dev (WebSocket) and static snapshot alike:
+Otherwise call `connectDevframe()`, which auto-resolves the connection descriptor relative to the page, whether dev (WebSocket) or static snapshot:
```ts
import { connectDevframe } from 'devframe/client'
@@ -235,7 +235,7 @@ defineDevframe({
## Live-reload on config changes
-Filesystem watching is your tool's job — wire chokidar, signal the browser side via shared state.
+Filesystem watching is your tool's job: wire chokidar, signal the browser side via shared state.
```ts [src/cli.ts]
defineDevframe({
@@ -274,7 +274,7 @@ version.on('updated', () => fetchPayload().then(setData))
## Use your own CLI framework
-Own a CLI framework (commander, yargs, oclif)? Use the three factories `createCac` wraps against one `DevframeDefinition`: `createDevServer` (`devframe/adapters/dev`), `createBuild` (`devframe/adapters/build`), and `createMcpServer` (`devframe/adapters/mcp`) — see the [CLI adapter](/adapters/cac#use-your-own-cli-framework).
+Own a CLI framework (commander, yargs, oclif)? Use the three factories `createCac` wraps against one `DevframeDefinition`: `createDevServer` (`devframe/adapters/dev`), `createBuild` (`devframe/adapters/build`), and `createMcpServer` (`devframe/adapters/mcp`); see the [CLI adapter](/adapters/cac#use-your-own-cli-framework).
```ts [src/cli.ts]
import process from 'node:process'
@@ -319,7 +319,7 @@ await program.parseAsync()
## See also
- [Devframe Definition](/guide/devframe-definition)
-- [Adapters → CLI (cac)](/adapters/cac) — `configureCli`, mount-path rules
+- [Adapters → CLI (cac)](/adapters/cac): `configureCli`, mount-path rules
- [Adapters → Dev](/adapters/dev)
- [Client](/guide/client)
- [Agent-Native](/guide/agent-native)
diff --git a/docs/content/1.guide/11.client.md b/docs/content/1.guide/11.client.md
index 18f792002..f38a7558c 100644
--- a/docs/content/1.guide/11.client.md
+++ b/docs/content/1.guide/11.client.md
@@ -2,10 +2,10 @@
title: 'Client'
navigation:
icon: i-lucide-globe
-description: 'The RPC client connects any surface — dock iframe, remote page, standalone SPA — to a devframe''s node side with type-safe RPC, shared state, and a trust handshake.'
+description: 'The RPC client connects any surface (dock iframe, remote page, standalone SPA) to a devframe''s node side with type-safe RPC, shared state, and a trust handshake.'
---
-The RPC client connects any surface — dock iframe, remote page, standalone SPA — to a devframe's node side with type-safe RPC, shared state, and a trust handshake.
+The RPC client connects any surface (dock iframe, remote page, standalone SPA) to a devframe's node side with type-safe RPC, shared state, and a trust handshake.
## Connecting
@@ -19,11 +19,11 @@ const rpc = await connectDevframe()
const modules = await rpc.call('my-tool:get-modules', { limit: 10 })
```
-At the default mount path, `connectDevframe` needs no arguments — it auto-detects the backend via `__devframe/__connection.json`.
+At the default mount path, `connectDevframe` needs no arguments; it auto-detects the backend via `__devframe/__connection.json`.
### Runtime basePath discovery
-One SPA artifact serves at `/`, `/__/`, or any subpath, no rebuild. Build with relative asset paths — Vite `base: './'`, Nuxt `vite.base: './'` + `app.baseURL: './'`.
+One SPA artifact serves at `/`, `/__/`, or any subpath, no rebuild. Build with relative asset paths: Vite `base: './'`, Nuxt `vite.base: './'` + `app.baseURL: './'`.
### Sharing a connection with an external viewer
@@ -57,7 +57,7 @@ await registerDevframeViewerOrigin(connection)
### Options
-`baseURL` points at the mount path to probe for `__connection.json` (default `'./'`, relative to `document.baseURI`); `connection` adopts one prepared by `setupDevframeConnection()`. The rest cover auth (`authToken`), [caching](#caching) (`cacheOptions`), timeouts (`callTimeout`), transport hooks (`wsOptions`), `birpc` passthrough (`rpcOptions`), and discovery override (`connectionMeta`) — every option is in the [Browser-Side API reference](/references/browser-api#connectdevframe-options).
+`baseURL` points at the mount path to probe for `__connection.json` (default `'./'`, relative to `document.baseURI`); `connection` adopts one prepared by `setupDevframeConnection()`. The rest cover auth (`authToken`), [caching](#caching) (`cacheOptions`), timeouts (`callTimeout`), transport hooks (`wsOptions`), `birpc` passthrough (`rpcOptions`), and discovery override (`connectionMeta`); every option is in the [Browser-Side API reference](/references/browser-api#connectdevframe-options).
## Modes
@@ -66,7 +66,7 @@ Per the `__devframe/__connection.json` backend:
| Backend | When | Capabilities |
|---------|------|--------------|
| `websocket` | Dev mode (`createCac`, Kit) | Full read/write, broadcasts, shared-state mutation. Requires auth. |
-| `static` | Build / SPA output | Read-only — all calls resolve against the baked RPC dump. |
+| `static` | Build / SPA output | Read-only: all calls resolve against the baked RPC dump. |
## Trust & auth (WebSocket mode)
@@ -115,13 +115,13 @@ Derive a [scoped client](/guide/scoped-context) for namespaced ids:
```ts
const my = (await connectDevframe()).scope('my-tool')
-// Standard call — awaits a response or throws.
+// Standard call: awaits a response or throws.
const modules = await my.rpc.call('get-modules', { limit: 10 })
-// Optional — returns undefined when no handler responds (useful while HMR is restarting).
+// Optional: returns undefined when no handler responds (useful while HMR is restarting).
const maybe = await my.rpc.callOptional('get-modules', { limit: 10 })
-// Event — fire-and-forget, no response expected.
+// Event: fire-and-forget, no response expected.
my.rpc.callEvent('notify', { message: 'hello' })
```
@@ -264,7 +264,7 @@ rpc.events.on('rpc:is-trusted:updated', (isTrusted) => {
### Connection status
-`rpc.status` collapses transport and trust into one value; `rpc.connectionError` holds the last connection-level `Error` (`null` when healthy). It moves through `connecting` (calls queue until open), `connected` (calls are served), `unauthorized` (socket open, trust refused — prompt for [authentication](#authenticating-with-a-one-time-code)), `disconnected`, and `error`; each value's meaning is in the [Browser-Side API reference](/references/browser-api#connection-statuses).
+`rpc.status` collapses transport and trust into one value; `rpc.connectionError` holds the last connection-level `Error` (`null` when healthy). It moves through `connecting` (calls queue until open), `connected` (calls are served), `unauthorized` (socket open, trust refused; prompt for [authentication](#authenticating-with-a-one-time-code)), `disconnected`, and `error`; each value's meaning is in the [Browser-Side API reference](/references/browser-api#connection-statuses).
A `static` backend has no live socket, so `rpc.status` stays `connected`.
@@ -272,9 +272,9 @@ A `static` backend has no live socket, so `rpc.status` stays `connected`.
When the socket closes or trust is refused, in-flight and new `rpc.call` promises reject with a `DevframeConnectionError`, its `kind`:
-- `'connection'` — the transport is down (`disconnected` / `error`).
-- `'auth'` — the RPC client is `unauthorized`.
-- `'timeout'` — the call outlived `callTimeout`.
+- `'connection'`: the transport is down (`disconnected` / `error`).
+- `'auth'`: the RPC client is `unauthorized`.
+- `'timeout'`: the call outlived `callTimeout`.
Set `callTimeout` to cap an unresponsive node side:
@@ -296,7 +296,7 @@ function render() {
switch (rpc.status) {
case 'connected': return renderApp()
case 'connecting': return renderSpinner('Connecting…')
- case 'unauthorized': return renderMessage('Not authorized — reopen the link from your dev server.')
+ case 'unauthorized': return renderMessage('Not authorized. Reopen the link from your dev server.')
case 'disconnected': return renderMessage('Disconnected.', { onRetry: reconnect })
case 'error': return renderMessage(rpc.connectionError?.message ?? 'Connection failed.', { onRetry: reconnect })
}
@@ -311,17 +311,17 @@ async function loadModules() {
}
catch (error) {
if (error instanceof DevframeConnectionError) {
- // 'connection' | 'auth' | 'timeout' — the UI already reflects rpc.status.
+ // 'connection' | 'auth' | 'timeout': the UI already reflects rpc.status.
return null
}
- throw error // a real server-side error — surface it.
+ throw error // a real server-side error; surface it.
}
}
```
### Recovering
-The RPC client doesn't reconnect on its own — reload or re-run your connect routine:
+The RPC client doesn't reconnect on its own; reload or re-run your connect routine:
```ts
async function reconnect() {
diff --git a/docs/content/1.guide/12.in-page-channel.md b/docs/content/1.guide/12.in-page-channel.md
index 0aa3f8dc6..9f0403613 100644
--- a/docs/content/1.guide/12.in-page-channel.md
+++ b/docs/content/1.guide/12.in-page-channel.md
@@ -2,10 +2,10 @@
title: 'In-Page Channel'
navigation:
icon: i-lucide-message-square-code
-description: 'The in-page channel connects a devframe''s page script to its panels entirely in the browser — typed events, calls, and page-script-authoritative shared state, with no server involved.'
+description: 'The in-page channel connects a devframe''s page script to its panels entirely in the browser: typed events, calls, and page-script-authoritative shared state, with no server involved.'
---
-The in-page channel (`devframe/in-page-channel`) connects a devframe's page script to its panels entirely in the browser — typed events, calls, and page-script-authoritative shared state, with no server involved. It is how a live inspect-the-page loop (like the [a11y inspector](/add-ons/devframes/a11y)'s scan/highlight cycle) works identically in dev and in a static build.
+The in-page channel (`devframe/in-page-channel`) connects a devframe's page script to its panels entirely in the browser: typed events, calls, and page-script-authoritative shared state, with no server involved. It is how a live inspect-the-page loop (like the [a11y inspector](/add-ons/devframes/a11y)'s scan/highlight cycle) works identically in dev and in a static build.
## Overview
@@ -24,11 +24,11 @@ flowchart LR
PB <-->|"MessageChannel port"| PS
```
-The panel finds the page script with a same-origin `postMessage` handshake: it posts a versioned hello to its ancestor chain and `opener`, retrying with backoff until the page script answers by transferring a dedicated `MessageChannel` port. Boot order never matters, a reload of either side is just a re-handshake, and each connected panel gets its own port — a dock iframe and a picture-in-picture window can watch the same page script at once.
+The panel finds the page script with a same-origin `postMessage` handshake: it posts a versioned hello to its ancestor chain and `opener`, retrying with backoff until the page script answers by transferring a dedicated `MessageChannel` port. Boot order never matters, a reload of either side is just a re-handshake, and each connected panel gets its own port, so a dock iframe and a picture-in-picture window can watch the same page script at once.
## The protocol
-Declare the contract once, in a shared file both sides import — a pure type plus the channel-name constant:
+Declare the contract once, in a shared file both sides import: a pure type plus the channel-name constant:
```ts
// shared/protocol.ts
@@ -50,7 +50,7 @@ export interface MyChannelProtocol extends InPageChannelProtocol {
}
```
-Channel names are namespaced with the devframe id, like RPC ids. Function names stay bare — the channel name already scopes them.
+Channel names are namespaced with the devframe id, like RPC ids. Function names stay bare; the channel name already scopes them.
## The page script endpoint
@@ -58,7 +58,7 @@ Functions use the same authoring metadata as `defineRpcFunction` (`type`, Standa
```ts
import type { MyChannelProtocol } from '../shared/protocol'
-// inject/index.ts — runs in the user app's page
+// inject/index.ts: runs in the user app's page
import { createPageScriptChannel } from 'devframe/in-page-channel'
import { MY_CHANNEL } from '../shared/protocol'
@@ -84,13 +84,13 @@ channel.events.on('panel:connected', panel => console.log(panel.id))
channel.events.on('panel:disconnected', () => pauseWorkIfNobodyWatches())
```
-`callEvent` on the page script is 1:N — it fans out to every connected panel, and panels that don't implement the function ignore it. Request/response *to* a panel goes through an explicit peer handle: `channel.panels[0].call('flash', '…')`.
+`callEvent` on the page script is 1:N: it fans out to every connected panel, and panels that don't implement the function ignore it. Request/response *to* a panel goes through an explicit peer handle: `channel.panels[0].call('flash', '…')`.
## The panel endpoint
```ts
import type { MyChannelProtocol } from '../shared/protocol'
-// spa/main.ts — the devtools SPA (dock iframe, popup, or PiP)
+// spa/main.ts: the devtools SPA (dock iframe, popup, or PiP)
import { connectPanelChannel } from 'devframe/in-page-channel'
import { MY_CHANNEL } from '../shared/protocol'
@@ -109,31 +109,31 @@ const size = await channel.call('measure', '.hero')
## Shared state
-The channel's shared-state layer mirrors [`rpc.sharedState`](/guide/shared-state) — same `SharedState` handle, same accessor — with the page script playing the server's role as rendezvous and authority. Its first `get` of a key must provide the initial value; panels are seeded automatically on connect (including late joiners and re-connects) and converge through syncId-deduplicated patches.
+The channel's shared-state layer mirrors [`rpc.sharedState`](/guide/shared-state) (same `SharedState` handle, same accessor), with the page script playing the server's role as rendezvous and authority. Its first `get` of a key must provide the initial value; panels are seeded automatically on connect (including late joiners and re-connects) and converge through syncId-deduplicated patches.
```ts
-// Page script — the authority:
+// Page script (the authority):
const state = await channel.sharedState.get('state', { initialValue: { selections: [] } })
state.mutate((draft) => {
draft.selections.push('.hero')
})
-// Panel — a live mirror:
+// Panel (a live mirror):
const state = await channel.sharedState.get('state')
state.on('updated', fullState => render(fullState))
state.value() // Immutable snapshot
```
-Without an `initialValue`, a panel's `get` resolves once the first replay arrives — so `render(state.value())` never sees a half-initialized value. Keep values serializable: they cross a structured-clone boundary on every sync.
+Without an `initialValue`, a panel's `get` resolves once the first replay arrives, so `render(state.value())` never sees a half-initialized value. Keep values serializable: they cross a structured-clone boundary on every sync.
## Errors and fallbacks
-Every failure mode is a coded `InPageChannelError` (`error.code`) with a message that explains itself: `timeout` (a call or `whenConnected(ms)` outlived its deadline), `closed` (endpoint torn down with calls pending), `not-serializable` / `not-cloneable` (a payload the port can't carry — the message names the offending path), `invalid-args` (Standard-Schema validation failed), and `state-uninitialized` (a shared state read before its `initialValue`). Causes and fixes per code are in the [Browser-Side API reference](/references/browser-api#in-page-channel-error-codes).
+Every failure mode is a coded `InPageChannelError` (`error.code`) with a message that explains itself: `timeout` (a call or `whenConnected(ms)` outlived its deadline), `closed` (endpoint torn down with calls pending), `not-serializable` / `not-cloneable` (a payload the port can't carry; the message names the offending path), `invalid-args` (Standard-Schema validation failed), and `state-uninitialized` (a shared state read before its `initialValue`). Causes and fixes per code are in the [Browser-Side API reference](/references/browser-api#in-page-channel-error-codes).
The panel endpoint's connection lifecycle is explicit, so a panel renders a useful fallback instead of hanging:
- `channel.status` is `connecting` → `connected` → (`connecting` on port loss) → `closed`, with `events.on('status:updated', …)` for reactivity.
-- While `connecting`, `call()` is queued (and still subject to its deadline) and `callEvent()` is buffered (up to `eventBufferLimit`, oldest dropped with a warning) — both flush on connect.
+- While `connecting`, `call()` is queued (and still subject to its deadline) and `callEvent()` is buffered (up to `eventBufferLimit`, oldest dropped with a warning); both flush on connect.
- A page script may legitimately never appear (the panel opened standalone, the user app not instrumented). Race `whenConnected(timeoutMs)` to show a "load the page script" empty state:
```ts
@@ -149,7 +149,7 @@ Recovery is automatic: a dead port (detected by the port's `close` event or the
## Reactivity and serialization
-Payloads cross the port with structured clone. Framework reactivity wrappers don't survive it — unwrap them before sending, either in handlers or once per endpoint with the `serialize`/`deserialize` hooks:
+Payloads cross the port with structured clone. Framework reactivity wrappers don't survive it; unwrap them before sending, either in handlers or once per endpoint with the `serialize`/`deserialize` hooks:
```ts
import { toRaw } from 'vue'
@@ -164,7 +164,7 @@ Declaring a function `jsonSerializable: true` additionally enforces strict JSON
## Multiple tabs
-The same app open in two tabs means two page scripts on one origin. Each page script carries a per-tab instance id (persisted in `sessionStorage`), and handshakes are targeted `postMessage` — so a dock panel always pairs with its own tab's page script. A panel can also pin explicitly:
+The same app open in two tabs means two page scripts on one origin. Each page script carries a per-tab instance id (persisted in `sessionStorage`), and handshakes are targeted `postMessage`, so a dock panel always pairs with its own tab's page script. A panel can also pin explicitly:
```ts
connectPanelChannel({ name: MY_CHANNEL, instanceId })
@@ -172,7 +172,7 @@ connectPanelChannel({ name: MY_CHANNEL, instanceId })
## Custom transports
-Both endpoints accept a pre-established `MessagePort`, bypassing the handshake — for custom topologies and tests:
+Both endpoints accept a pre-established `MessagePort` that bypasses the handshake, for custom topologies and tests:
```ts
const { port1, port2 } = new MessageChannel()
diff --git a/docs/content/1.guide/13.transports.md b/docs/content/1.guide/13.transports.md
index 1e03ca3c7..c8369a5fb 100644
--- a/docs/content/1.guide/13.transports.md
+++ b/docs/content/1.guide/13.transports.md
@@ -2,17 +2,17 @@
title: 'Transports'
navigation:
icon: i-lucide-cable
-description: 'Devframe serves live RPC over two interchangeable transports — WebSocket and SSE — so an RPC client connects even where the WebSocket upgrade is unavailable (serverless, buffering proxies). Both speak the identical birpc wire protocol, transparent to your RPC code.'
+description: 'Devframe serves live RPC over two interchangeable transports, WebSocket and SSE, so an RPC client connects even where the WebSocket upgrade is unavailable (serverless, buffering proxies). Both speak the identical birpc wire protocol, transparent to your RPC code.'
---
-Devframe serves live RPC over two interchangeable transports — WebSocket and SSE — so an RPC client connects even where the WebSocket upgrade is unavailable (serverless, buffering proxies). Both speak the identical birpc wire protocol, transparent to your RPC code.
+Devframe serves live RPC over two interchangeable transports, WebSocket and SSE, so an RPC client connects even where the WebSocket upgrade is unavailable (serverless, buffering proxies). Both speak the identical birpc wire protocol, transparent to your RPC code.
## What the node side binds
A live instance binds both by default:
-- **WebSocket** at `__ws` — primary, one full-duplex socket.
-- **SSE** at `__sse` — one method-dispatched route: `GET` opens the server→client stream, `POST` carries client→server frames. It rides the same HTTP routes as `__connection.json`, so wherever discovery works SSE works — including middleware-only host frameworks (the Vite bridge, `initDevframe`'s `handler` / `nodeMiddleware`).
+- **WebSocket** at `__ws`: primary, one full-duplex socket.
+- **SSE** at `__sse`, one method-dispatched route: `GET` opens the server→client stream, `POST` carries client→server frames. It rides the same HTTP routes as `__connection.json`, so wherever discovery works SSE works, including middleware-only host frameworks (the Vite bridge, `initDevframe`'s `handler` / `nodeMiddleware`).
`__connection.json` advertises what's bound; `backend` is the primary:
@@ -29,11 +29,11 @@ The SSE stream sends a keep-alive comment every 30 seconds. Both endpoints share
### Configuring
```ts
-// SSE-only — host frameworks/proxies where the upgrade can't happen.
+// SSE-only: host frameworks/proxies where the upgrade can't happen.
// RPC clients connect over SSE automatically (backend: 'sse').
initDevframe(def, { base: '/__my-tool/', ws: false })
-// WebSocket-only — opt out of the SSE endpoint.
+// WebSocket-only: opt out of the SSE endpoint.
initDevframe(def, { base: '/__my-tool/', server, sse: false })
// Rename the SSE route.
@@ -46,12 +46,12 @@ initDevframe(def, { base: '/__my-tool/', server, sse: { route: '__events' } })
`connectDevframe` connects over the declared primary, preferring WebSocket when both are present; a socket-less server advertises SSE as primary, so the RPC client lands there directly.
-Pin a transport when you know better — e.g. an intermediary that silently strips WS upgrades:
+Pin a transport when you know better, e.g. an intermediary that silently strips WS upgrades:
```ts
const client = await connectDevframe({ transport: 'sse' })
-client.transport // 'websocket' | 'sse' | 'static' — what actually connected
+client.transport // 'websocket' | 'sse' | 'static': what actually connected
```
Pinning an unadvertised transport rejects. SSE follows the same proxy-safe rules as WebSocket: relative paths against `__connection.json`'s URL, explicit `host`/`port` only for a cross-origin endpoint.
diff --git a/docs/content/1.guide/14.security.md b/docs/content/1.guide/14.security.md
index df9a91ff4..371c9737a 100644
--- a/docs/content/1.guide/14.security.md
+++ b/docs/content/1.guide/14.security.md
@@ -9,7 +9,7 @@ Devframe tools are secure by default: connections bind to `localhost`, and dev-m
## Trust model
-An RPC handler runs with the full privileges of its Node process — filesystem, child processes, network — and a trusted connection can call any registered function. The boundary that matters is *who may connect*:
+An RPC handler runs with the full privileges of its Node process (filesystem, child processes, network), and a trusted connection can call any registered function. The boundary that matters is *who may connect*:
- **Authenticated (default).** `auth` defaults to `true`; the browser authenticates before calls are accepted, then reconnects with a node-issued bearer token. `createInteractiveAuth` (`devframe/recipes/interactive-auth`) packages the protocol into one `DevframeAuthHandler` the adapters wire for you (pass it to `initDevframe` / `initHub` via `auth`).
- **Unauthenticated opt-out.** `auth: false` starts the server with an auto-trust handshake, for single-user tools on their own `localhost`.
@@ -19,14 +19,14 @@ An RPC handler runs with the full privileges of its Node process — filesystem,
## The pre-trust gate
-One rule decides what an untrusted connection may call: **a method is reachable before trust iff its name starts with `anonymous:`** (`isAnonymousRpcMethod`, from `devframe/constants`) — only the two handshake methods below.
+One rule decides what an untrusted connection may call: **a method is reachable before trust iff its name starts with `anonymous:`** (`isAnonymousRpcMethod`, from `devframe/constants`); only the two handshake methods below qualify.
The RPC server binding enforces this: pass `auth: authHandler` (its `.authorize` becomes the gate) or your own `authorize(methodName, session)`. Every other call from an untrusted session throws [`DF0036`](/errors/DF0036). `rpc.call` / `rpc.callOptional` / `rpc.callEvent` hold calls issued during the first handshake and release them once it settles.
## Authentication flow
1. A fresh RPC client calls `anonymous:devframe:auth` with its stored token (empty on first run); the server returns `{ isTrusted: false }` and the UI prompts for a code.
-2. The dev server shows a 6-digit code in the terminal — `auth.printBanner()` once listening.
+2. The dev server shows a 6-digit code in the terminal (`auth.printBanner()` once listening).
3. The developer enters it; the browser calls `requestTrustWithCode(code)`.
4. The server verifies the code, mints a high-entropy bearer token, trusts the session, and returns it.
5. The browser persists the token and presents it on reconnect (or via a `?devframe_auth_token=` query param the connect-time hook checks first); sibling tabs receive it over the `devframe-auth` channel and become trusted.
@@ -53,7 +53,7 @@ Pass `clientAuthTokens` for CI/shared machines to skip the prompt, or a custom `
The two `anonymous:`-prefixed handshake methods re-authenticate a stored token (`anonymous:devframe:auth`) and exchange a one-time code for a token (`anonymous:devframe:auth:exchange`); `devframe:auth:revoke` self-revokes, and the `devframe:auth:revoked` event drops affected RPC clients to untrusted. Wire shapes are in the [Node-Side API reference](/references/node-api#auth-methods).
-Node primitives in `devframe/node/auth` — `getTempAuthCode` / `refreshTempAuthCode`, `exchangeTempAuthCode`, `verifyAuthToken`, `buildOtpAuthUrl`, and `revokeAuthToken` — implement the same flow for a host framework wiring its own gate; signatures are in the [reference](/references/node-api#node-auth-primitives).
+Node primitives in `devframe/node/auth` (`getTempAuthCode` / `refreshTempAuthCode`, `exchangeTempAuthCode`, `verifyAuthToken`, `buildOtpAuthUrl`, and `revokeAuthToken`) implement the same flow for a host framework wiring its own gate; signatures are in the [reference](/references/node-api#node-auth-primitives).
RPC client methods (`devframe/client`): `requestTrustWithCode(code)`, `requestTrustWithToken(token)`, and `ensureTrusted(timeout?)` / `isTrusted` (the trust gate).
@@ -62,12 +62,12 @@ RPC client methods (`devframe/client`): `requestTrustWithCode(code)`, `requestTr
The standalone CLI (`createCac` / `createDevServer`) prints a link embedding the code for `--open`, so the launched tab lands authenticated with no prompt. Build it yourself with `buildOtpAuthUrl(origin)`:
```
-Devtools ready — authenticate this browser: http://localhost:3000/#devframe_otp=123456
+Devtools ready. Authenticate this browser: http://localhost:3000/#devframe_otp=123456
```
The code rides the URL **fragment** (`#devframe_otp=…`), which browsers never send to the server, keeping the single-use code out of access logs and `Referer` headers. `connectDevframe` reads it, exchanges it, and strips it from the URL. Because the link grants trust to whoever opens it within the code's lifetime, print it only to a trusted channel (the terminal).
-The link points at the **public origin**. A standalone dev server derives it from its own bound address; an owned listener uses that address regardless of any inbound `Host` header. A handler or middleware without an explicit `origin` derives one from a request only when the request's own origin is loopback or exactly matches an `allowedOrigins` entry — a raw inbound authority and forwarded headers are never trusted. Set `origin` explicitly for non-loopback handler deployments (behind a proxy, on a LAN, or on a public host) so the magic link always resolves to the address you intend.
+The link points at the **public origin**. A standalone dev server derives it from its own bound address; an owned listener uses that address regardless of any inbound `Host` header. A handler or middleware without an explicit `origin` derives one from a request only when the request's own origin is loopback or exactly matches an `allowedOrigins` entry; a raw inbound authority and forwarded headers are never trusted. Set `origin` explicitly for non-loopback handler deployments (behind a proxy, on a LAN, or on a public host) so the magic link always resolves to the address you intend.
For your own auth UI, disable built-in handling with `otpParam: false`, then call `authenticateWithUrlOtp(rpc)` or `consumeOtpFromUrl()` from `devframe/client`.
@@ -75,7 +75,7 @@ For your own auth UI, disable built-in handling with `otpParam: false`, then cal
- **Stay on loopback.** Bind to a routable address only intentionally, and require authentication when you do.
- **Keep `auth: false` local.** The hosted bridges (`devframeViteBridge`, `@devframes/next`'s handler) gate their side-car by default; opt out with an explicit `auth: false` only when the host framework owns the trust boundary another way.
-- **The MCP route requires an origin.** The route-based MCP server rejects requests without a loopback or allow-listed `Origin`, so an arbitrary local process can't reach it — see [MCP](/adapters/mcp).
+- **The MCP route requires an origin.** The route-based MCP server rejects requests without a loopback or allow-listed `Origin`, so an arbitrary local process can't reach it; see [MCP](/adapters/mcp).
- **Treat tokens as secrets.** Never log the bearer token or the one-time code, or bake either into build output.
- **Authorize every handler.** Validate inputs, and mark state-changing functions `type: 'destructive'` so MCP and agent clients prompt before invoking them.
- **Origin-lock remote docks.** When a hub embeds a remote-UI dock, keep `originLock` on (the default) so its session token is only honored on a connection whose `Origin` matches the dock's own.
diff --git a/docs/content/1.guide/15.agent-native.md b/docs/content/1.guide/15.agent-native.md
index d63633362..63adc378c 100644
--- a/docs/content/1.guide/15.agent-native.md
+++ b/docs/content/1.guide/15.agent-native.md
@@ -2,10 +2,10 @@
title: 'Agent-Native Devframe'
navigation:
icon: i-lucide-bot
-description: 'Devframe exposes its browser-side API — RPC functions, resources, shared state — to coding agents over MCP, opt-in per function.'
+description: 'Devframe exposes its browser-side API (RPC functions, resources, shared state) to coding agents over MCP, opt-in per function.'
---
-Devframe exposes its browser-side API — RPC functions, resources, shared state — to coding agents over MCP, opt-in per function.
+Devframe exposes its browser-side API (RPC functions, resources, shared state) to coding agents over MCP, opt-in per function.
## How it works
@@ -36,8 +36,8 @@ export const getSessionSummary = defineRpcFunction({
## Tool ids and wire names
-- **The id** — registers/invokes in devframe, colon-namespaced: `devframes:plugin::` (built-in devframe RPCs), `devframe::` (built-ins), command ids.
-- **The wire name** — what MCP clients call, constrained to `^[a-zA-Z0-9_-]{1,128}$`; runs outside that set collapse to `_`, truncated to 128.
+- **The id** registers/invokes in devframe, colon-namespaced: `devframes:plugin::` (built-in devframe RPCs), `devframe::` (built-ins), command ids.
+- **The wire name** is what MCP clients call, constrained to `^[a-zA-Z0-9_-]{1,128}$`; runs outside that set collapse to `_`, truncated to 128.
```
devframe:state:read → devframe_state_read
@@ -147,7 +147,7 @@ Describe *when* to use a tool, not just its return:
// ✗ Bad: describes the mechanism
agent: { description: 'Returns the session summary object.' }
// ✓ Good: tells the agent when and why
-agent: { description: 'Summarize the current build session — durations, chunk counts, warnings. Call this before proposing any build-config change.' }
+agent: { description: 'Summarize the current build session: durations, chunk counts, warnings. Call this before proposing any build-config change.' }
```
## Gateway tools
@@ -178,7 +178,7 @@ Prefer coded diagnostics anywhere agent-reachable: agents act on `fix` and follo
## Safety model
-- **`safety`** — `'read'`, `'action'`, or `'destructive'`. Inferred from the RPC `type` (`static`/`query` → `read`, `action`/`event` → `action`), overridable.
+- **`safety`**: `'read'`, `'action'`, or `'destructive'`. Inferred from the RPC `type` (`static`/`query` → `read`, `action`/`event` → `action`), overridable.
- The adapter maps `safety` to tool annotations (`readOnlyHint`, `destructiveHint`).
## CLI
diff --git a/docs/content/1.guide/16.hub.md b/docs/content/1.guide/16.hub.md
index 6f274c176..8a1916847 100644
--- a/docs/content/1.guide/16.hub.md
+++ b/docs/content/1.guide/16.hub.md
@@ -2,10 +2,10 @@
title: 'Hub'
navigation:
icon: i-lucide-layout-dashboard
-description: '@devframes/hub orchestrates many devtools sharing a UI: a dock registry, terminal aggregation, message/toast queue, and command palette. It ships no UI — hub UI providers provide their own atop the hub''s RPC + shared-state protocol.'
+description: '@devframes/hub orchestrates many devtools sharing a UI: a dock registry, terminal aggregation, message/toast queue, and command palette. It ships no UI; hub UI providers provide their own atop the hub''s RPC + shared-state protocol.'
---
-`@devframes/hub` orchestrates many devtools sharing a UI: a dock registry, terminal aggregation, message/toast queue, and command palette. It ships no UI — hub UI providers provide their own atop the hub's RPC + shared-state protocol.
+`@devframes/hub` orchestrates many devtools sharing a UI: a dock registry, terminal aggregation, message/toast queue, and command palette. It ships no UI; hub UI providers provide their own atop the hub's RPC + shared-state protocol.

@@ -21,10 +21,10 @@ Data-driven UI panels are an opt-in [JSON-Render](/guide/json-render) package (a
Every hub context auto-registers these functions, callable from any RPC client:
-- `hub:commands:execute` — invoke a server command by id.
-- `hub:docks:activate` — switch the active dock ([Cross-iframe dock activation](#cross-iframe-dock-activation)).
-- `hub:messages:add` / `update` / `remove` / `clear` — write the messages feed.
-- `hub:terminals:write` / `resize` — drive a PTY session by id.
+- `hub:commands:execute`: invoke a server command by id.
+- `hub:docks:activate`: switch the active dock ([Cross-iframe dock activation](#cross-iframe-dock-activation)).
+- `hub:messages:add` / `update` / `remove` / `clear`: write the messages feed.
+- `hub:terminals:write` / `resize`: drive a PTY session by id.
Host-framework-specific capabilities (open in editor, reveal in finder) ship as kit-registered functions.
@@ -100,7 +100,7 @@ async function runBuild() {
## Mounting a devframe into a hub
-`ctx.install(def)` registers a `DevframeDefinition` as a dock and runs its `setup(ctx)` — the imperative counterpart to `initHub`'s `devframes` list.
+`ctx.install(def)` registers a `DevframeDefinition` as a dock and runs its `setup(ctx)`, the imperative counterpart to `initHub`'s `devframes` list.
```ts
import { createHubContext } from '@devframes/hub/node'
@@ -113,7 +113,7 @@ Framework kits and hub UI providers wrap this (e.g. `@vitejs/devtools-kit`'s `cr
### Connecting embedded SPAs
-A mounted SPA loads at `/__/` and calls `connectDevframe()`, which fetches `./__connection.json` — served by the host framework's `mountConnectionMeta(base)`:
+A mounted SPA loads at `/__/` and calls `connectDevframe()`, which fetches `./__connection.json`, served by the host framework's `mountConnectionMeta(base)`:
```ts
const host: DevframeHost = {
@@ -144,7 +144,7 @@ const pkgs = ['@devframes/plugin-git', '@devframes/plugin-terminals']
const defs = await Promise.all(
pkgs.map(p => import(/* webpackIgnore: true */ /* turbopackIgnore: true */ p)),
// Each package's default export is its `createDevframe` factory, not a
- // pre-built instance — call it to get one.
+ // pre-built instance; call it to get one.
).then(mods => mods.map(m => m.default()))
for (const def of defs)
@@ -154,7 +154,7 @@ for (const def of defs)
SPAs serve at `/__/` with relative assets; set `skipTrailingSlashRedirect`:
```js
-// next.config.mjs
+/** next.config.mjs */
export default { skipTrailingSlashRedirect: true }
```
@@ -165,7 +165,7 @@ When a devframe shares an already-mounted `id`, `duplicationStrategy` decides: `
```ts
defineDevframe({
id: 'my-tool',
- // …
+ /** … */
duplicationStrategy: 'duplicate',
})
```
@@ -194,7 +194,7 @@ ctx.docks.register({
})
```
-Group and members stay independent top-level entries in `devframe:docks`. Activating the group reopens the member last opened in it (remembered per tab), and `defaultChildId` before any member has been opened. Grouping affects the dock rail, not iframes — to share **one** soft-navigated iframe, give docks a shared `frameId` and mark the anchor with `subTabs` ([Shared-iframe soft navigation](/guide/client-context#shared-iframe-soft-navigation)).
+Group and members stay independent top-level entries in `devframe:docks`. Activating the group reopens the member last opened in it (remembered per tab), and `defaultChildId` before any member has been opened. Grouping affects the dock rail, not iframes; to share **one** soft-navigated iframe, give docks a shared `frameId` and mark the anchor with `subTabs` ([Shared-iframe soft navigation](/guide/client-context#shared-iframe-soft-navigation)).
### The dual role of `category`
@@ -208,7 +208,7 @@ Framework kits can interleave category ids or override weights; an unknown categ
## The hub UI protocol
-A hub UI provider imports no hub classes; it renders from four shared-state slots — `devframe:docks` (every registered dock entry), `devframe:commands` (the serializable command list), `devframe:user-settings` (persisted hub settings), and `devframe:docks:active` (the most recent [dock activation](#cross-iframe-dock-activation) request) — and dispatches through two RPC methods, `hub:commands:execute` and `hub:docks:activate`. Types and payloads are in the [Hub API reference](/references/hub-api#hub-ui-protocol).
+A hub UI provider imports no hub classes; it renders from four shared-state slots and dispatches through two RPC methods. The slots are `devframe:docks` (every registered dock entry), `devframe:commands` (the serializable command list), `devframe:user-settings` (persisted hub settings), and `devframe:docks:active` (the most recent [dock activation](#cross-iframe-dock-activation) request); the methods are `hub:commands:execute` and `hub:docks:activate`. Types and payloads are in the [Hub API reference](/references/hub-api#hub-ui-protocol).
Broadcast notifications (`devframe:docks:activate`, `devframe:terminals:updated`, `devframe:messages:updated`) arrive via `rpc.client.register(...)`; the client runtime registers `devframe:docks:activate` for you ([Events Reference](/references/events)).
@@ -220,9 +220,9 @@ The hub ships a headless client runtime, `createDevframeClientRuntime()` (`@devf
Two minimal hubs mount every built-in devframe behind an icon dock, plus a "Tabbed Tool" demonstrating [shared-iframe soft navigation](/guide/client-context#shared-iframe-soft-navigation):
-- [`examples/hub-vite/`](https://github.com/devframes/devframe/tree/main/examples/hub-vite) — a ~120-line Vite host with a vanilla DOM UI.
-- [`examples/hub-next/`](https://github.com/devframes/devframe/tree/main/examples/hub-next) — the same, from a Next.js App Router app.
+- [`examples/hub-vite/`](https://github.com/devframes/devframe/tree/main/examples/hub-vite): a ~120-line Vite host with a vanilla DOM UI.
+- [`examples/hub-next/`](https://github.com/devframes/devframe/tree/main/examples/hub-next): the same, from a Next.js App Router app.
## Diagnostics
-Hub-side diagnostic codes live in the `DF8xxx` range — see the [error reference](/errors).
+Hub-side diagnostic codes live in the `DF8xxx` range; see the [error reference](/errors).
diff --git a/docs/content/1.guide/17.client-context.md b/docs/content/1.guide/17.client-context.md
index b6df07c60..5538fbfe1 100644
--- a/docs/content/1.guide/17.client-context.md
+++ b/docs/content/1.guide/17.client-context.md
@@ -15,7 +15,7 @@ A dock **client script** runs a devframe's code inside the **host page**; the **
`createDevframeClientRuntime()` (`@devframes/hub/client`) boots the host page: it connects (or adopts) an RPC client, publishes the `DevframeClientContext`, and imports each dock's client script:
```ts
-// main.ts — the host page's browser entry
+// main.ts: the host page's browser entry
import { connectDevframe, createDevframeClientRuntime } from '@devframes/hub/client'
const rpc = await connectDevframe({ baseURL: '/__hub/' })
@@ -24,7 +24,7 @@ const { context, dispose } = await createDevframeClientRuntime({ rpc })
### Options
-Pass an already-connected `rpc` (or `connect` options for `connectDevframe`), the page's `clientType` (`'standalone'` by default, `'embedded'` inside a user app), `loadClientScripts: false` to skip dock client scripts, and boot-time `renderers` (which win over the hub's [renderer manifest](/guide/hub-initiate#renderer-modules)) — see the [Hub API reference](/references/hub-api#client-runtime-options).
+Pass an already-connected `rpc` (or `connect` options for `connectDevframe`), the page's `clientType` (`'standalone'` by default, `'embedded'` inside a user app), `loadClientScripts: false` to skip dock client scripts, and boot-time `renderers` (which win over the hub's [renderer manifest](/guide/hub-initiate#renderer-modules)); see the [Hub API reference](/references/hub-api#client-runtime-options).
A second boot replaces the context and warns; `dispose()` tears down listeners and unpublishes it.
@@ -61,18 +61,18 @@ The custom RPC keeps node-side reporting opt-in.
### Client-only docks
-A client runtime can register a dock local to the host page (unlike [node hub context](/guide/hub) docks synced via `devframe:docks`). `ctx.docks.register(entry)` — e.g. `type: 'custom-render'` with `renderer: { importFrom }` — returns a handle whose `update({ badge })` patches in place (id immutable) and `dispose()` removes it. One sharing a server dock's id overrides it locally; re-registering an owned id throws unless you pass `register(entry, true)`.
+A client runtime can register a dock local to the host page (unlike [node hub context](/guide/hub) docks synced via `devframe:docks`). `ctx.docks.register(entry)` (e.g. `type: 'custom-render'` with `renderer: { importFrom }`) returns a handle whose `update({ badge })` patches in place (id immutable) and `dispose()` removes it. One sharing a server dock's id overrides it locally; re-registering an owned id throws unless you pass `register(entry, true)`.
A client-only dock can also carry `type: 'json-render'` with an inline [JSON-render](/guide/json-render) `view: { spec }` (a `DevframeJsonRenderSpec` built in-browser), rendered when a `json-render` renderer is registered at boot. `view` also accepts `{ stateKey }` for live shared state (from `createJsonRenderView`).
## Dock client scripts
-A client script is a `ClientScriptEntry` — `{ importFrom, importName? }` (`importName` defaults `'default'`). The field varies by entry kind: an `action` entry's `action` runs when the dock button is activated, a `custom-render` entry's `renderer` renders its panel, and an `iframe` entry's optional `clientScript` runs alongside the iframe panel inside the host page ([Hub API reference](/references/hub-api#dock-client-script-fields)).
+A client script is a `ClientScriptEntry`: `{ importFrom, importName? }` (`importName` defaults `'default'`). The field varies by entry kind: an `action` entry's `action` runs when the dock button is activated, a `custom-render` entry's `renderer` renders its panel, and an `iframe` entry's optional `clientScript` runs alongside the iframe panel inside the host page ([Hub API reference](/references/hub-api#dock-client-script-fields)).
The exported function (`DockClientScriptContext`) receives the client context and two dock-scoped extras:
-- **`current`** — this entry's state: `entryMeta`, `isActive`, `domElements`, `events` (`entry:activated`, `entry:deactivated`, `entry:updated`, `dom:panel:mounted`, `dom:iframe:mounted`).
-- **`messages`** — an entry-scoped messages client (`category` defaults to the entry id; `info`/`warn`/`error`/`success`/`debug` shortcuts for `add()`).
+- **`current`** holds this entry's state: `entryMeta`, `isActive`, `domElements`, `events` (`entry:activated`, `entry:deactivated`, `entry:updated`, `dom:panel:mounted`, `dom:iframe:mounted`).
+- **`messages`**: an entry-scoped messages client (`category` defaults to the entry id; `info`/`warn`/`error`/`success`/`debug` shortcuts for `add()`).
A failed import retries on the next dock update.
@@ -80,8 +80,8 @@ A failed import retries on the next dock update.
`importFrom` accepts three shapes:
-- **A URL served by the host framework** — a self-contained ES module; works on every host framework.
-- **A bare npm specifier** (`'vite-plugin-vue-tracer/client/vite-devtools'`) — resolved through the host framework.
+- **A URL served by the host framework**: a self-contained ES module; works on every host framework.
+- **A bare npm specifier** (`'vite-plugin-vue-tracer/client/vite-devtools'`): resolved through the host framework.
- **An absolute filesystem path**, declared on the definition's `dock.clientScript`. The hub serves its directory under `__page-script/` and rewrites `importFrom` to that URL, so mounting by package name needs no host wiring.
Per-mount, attach a URL via `ctx.install(myDevframe, { dock: { clientScript: { importFrom } } })`; under Vite `/@fs/` serves it, and other host frameworks mount the directory statically.
@@ -98,11 +98,11 @@ One bundle can serve as both a client script (default export) and, via a globall
## Iframe panels
-Dock iframes are their own documents: the panel calls `connectDevframe()`, discovering `./__connection.json` from its base. A client script and an iframe panel share the node side via RPC and shared state, or talk directly — server-free, static-build-friendly — over the [in-page channel](/guide/in-page-channel).
+Dock iframes are their own documents: the panel calls `connectDevframe()`, discovering `./__connection.json` from its base. A client script and an iframe panel share the node side via RPC and shared state, or talk directly (server-free, static-build-friendly) over the [in-page channel](/guide/in-page-channel).
## Shared-iframe soft navigation
-A tool with many internal views (Nuxt DevTools' tabs) can surface each as a hub dock sharing **one** live iframe — the **anchor** owns a `frameId` and opts in via `ctx.install(…, { dock: { frameId, subTabs: { protocol: 'postmessage' } } })`. On mount, the client runtime attaches a **frame-nav adapter** speaking an origin-locked `postMessage` protocol on `devframe:frame-nav`: the iframe reports its tab list (`ready` / `manifest`), the host page requests a view (`navigate`), and the iframe reports internal navigation back (`navigated`). Message shapes are in the [Hub API reference](/references/hub-api#frame-nav-messages).
+A tool with many internal views (Nuxt DevTools' tabs) can surface each as a hub dock sharing **one** live iframe: the **anchor** owns a `frameId` and opts in via `ctx.install(…, { dock: { frameId, subTabs: { protocol: 'postmessage' } } })`. On mount, the client runtime attaches a **frame-nav adapter** speaking an origin-locked `postMessage` protocol on `devframe:frame-nav`: the iframe reports its tab list (`ready` / `manifest`), the host page requests a view (`navigate`), and the iframe reports internal navigation back (`navigated`). Message shapes are in the [Hub API reference](/references/hub-api#frame-nav-messages).
It materializes a [client-only dock](#client-only-docks) per tab (id `:`) sharing the anchor's `frameId` and a `navTarget`, independent of [`groupId`](/guide/hub#grouping-dock-entries).
diff --git a/docs/content/1.guide/18.hub-initiate.md b/docs/content/1.guide/18.hub-initiate.md
index 29095a713..461eee45a 100644
--- a/docs/content/1.guide/18.hub-initiate.md
+++ b/docs/content/1.guide/18.hub-initiate.md
@@ -14,7 +14,7 @@ import { createInspectDevframe } from '@devframes/plugin-inspect'
import { createTerminalsDevframe } from '@devframes/plugin-terminals'
export const hub = initHub({
- base: DEVFRAMES_HUB_BASE, // required — the conventional `/__devframes/`
+ base: DEVFRAMES_HUB_BASE, // required: the conventional `/__devframes/`
devframes: [createInspectDevframe(), createTerminalsDevframe()],
ui: createUi(),
configure(ctx) {
@@ -23,11 +23,11 @@ export const hub = initHub({
})
```
-`base` is required (echoed as `hub.base`); each mounted devframe runs `setup()` against the **shared hub context**. The instance mirrors `initDevframe`'s API — see [The Standard Handler](/adapters/initiate#mount-the-handler).
+`base` is required (echoed as `hub.base`); each mounted devframe runs `setup()` against the **shared hub context**. The instance mirrors `initDevframe`'s API; see [The Standard Handler](/adapters/initiate#mount-the-handler).
## The shared socket
-One transport serves the namespace, chosen in precedence: `ws.port` pins a side-car; `server` shares the host framework's `node:http` upgrade at `__ws`; `ws: { sidecar: true }` takes a free port; none leaves the socket to the host framework — Node uses `hub.attach(server)`, Bun/Deno `attachBunWsTransport` / `attachDenoWsTransport`.
+One transport serves the namespace, chosen in precedence: `ws.port` pins a side-car; `server` shares the host framework's `node:http` upgrade at `__ws`; `ws: { sidecar: true }` takes a free port; none leaves the socket to the host framework: Node uses `hub.attach(server)`, Bun/Deno `attachBunWsTransport` / `attachDenoWsTransport`.
The advertised path is hub-base-absolute (`/__devframes/__ws`). Dev-reevaluated host frameworks (Next, Nitro) memoize it on `globalThis`.
@@ -52,13 +52,13 @@ interface DevframeHubUi {
`@devframes/hub-ui`'s `createUi()` is the reference (standalone `viewer` SPA + floating dock); its `setup(ctx)` publishes config to `ctx.staticConfig.ui` (`ConnectionMeta.configs.ui`):
-- **`viewer`** — set to `false` to disable the standalone viewer.
-- **`branding`** — rebrand the UI (logo, name, primary color). `background` accepts any CSS `background` value (color, gradient, image, or `transparent`) or `{ light, dark }` variants. These flat forms apply everywhere. Use `{ standalone, iframe? }` to specialize the framed viewer; an omitted `iframe` value falls back to `standalone`.
-- **`dockPreferences`** — dock-rail: `categoryOrder`, floating-dock `maxVisibleItems`, first-run `defaultMode` (`'float'`/`'edge'`) and `defaultPosition`.
-- **`embeddedVisibility`** — the floating dock's reveal policy:
- - `'normal'` (default) — shows immediately.
- - `'passive'` — hidden until `Shift+Alt+D`, then persisted per-origin (later browser sessions start shown).
- - `'hidden'` — hidden until `Shift+Alt+D`, that browser session only.
+- **`viewer`**: set to `false` to disable the standalone viewer.
+- **`branding`**: rebrand the UI (logo, name, primary color). `background` accepts any CSS `background` value (color, gradient, image, or `transparent`) or `{ light, dark }` variants. These flat forms apply everywhere. Use `{ standalone, iframe? }` to specialize the framed viewer; an omitted `iframe` value falls back to `standalone`.
+- **`dockPreferences`** tunes the dock rail: `categoryOrder`, floating-dock `maxVisibleItems`, first-run `defaultMode` (`'float'`/`'edge'`) and `defaultPosition`.
+- **`embeddedVisibility`** sets the floating dock's reveal policy:
+ - `'normal'` (default): shows immediately.
+ - `'passive'`: hidden until `Shift+Alt+D`, then persisted per-origin (later browser sessions start shown).
+ - `'hidden'`: hidden until `Shift+Alt+D`, that browser session only.
## Renderer modules
@@ -93,7 +93,7 @@ A devframe's SPA and RPC client are byte-identical in both cases; only the envir
| RPC registry | this devframe's functions | merged: all mounted devframes + hub built-ins, cross-devframe |
| Shared state | own context's slots | all mounted devframes' slots + hub slots |
| Auth | own gate, own token | the single hub Auth |
-| Hub subsystems | — | docks, terminals, messages, commands; the devframe is also an iframe dock |
+| Hub subsystems | none | docks, terminals, messages, commands; the devframe is also an iframe dock |
| MCP | `__mcp`, this devframe's tools | the hub-level aggregate |
| Isolation | hard (own context, own transport) | cooperative (shared context) |
diff --git a/docs/content/1.guide/19.services.md b/docs/content/1.guide/19.services.md
index 44eb12742..97f9c0d91 100644
--- a/docs/content/1.guide/19.services.md
+++ b/docs/content/1.guide/19.services.md
@@ -29,7 +29,7 @@ export function setup(ctx: DevframeNodeContext) {
}
```
-Service ids prefix the provider's id (`:`), unique per context — a second `provide()` under a taken id throws [`DF0037`](https://devfra.me/errors/DF0037). `provide()` returns a revoke; guard idempotent setup with `has(id)`.
+Service ids prefix the provider's id (`:`), unique per context; a second `provide()` under a taken id throws [`DF0037`](https://devfra.me/errors/DF0037). `provide()` returns a revoke; guard idempotent setup with `has(id)`.
## Consuming a service
@@ -75,10 +75,10 @@ Two declaration merges type it: RPC ids into `DevframeRpcServerFunctions`, packa
### Declaring
-Services are **declarative**: a devframe lists what it consumes; a hub, shared ones on `initHub`. The adapter resolves each package — for a devframe, **against its own dependencies** via [`importMetaUrl`](/guide/devframe-definition#resolving-against-the-devframes-own-dependencies).
+Services are **declarative**: a devframe lists what it consumes; a hub, shared ones on `initHub`. The adapter resolves each package: for a devframe, **against its own dependencies** via [`importMetaUrl`](/guide/devframe-definition#resolving-against-the-devframes-own-dependencies).
```ts
-// devframe side — on the definition
+// devframe side: on the definition
defineDevframe({
importMetaUrl: import.meta.url, // resolution base for the declared packages
services: [
@@ -94,7 +94,7 @@ Entries are optional; uninstalled packages are skipped (`has() === false`). Mark
### Lifecycle: ready before setup
-The hub constructs every declared service (all devframes plus `initHub`) **once** — deep-merging option sets (objects recurse, arrays union-dedupe, scalars later-win; override with `mergeOptions`) — **before any `setup(ctx)` runs**, so setup consumes services synchronously via `ctx.services.get(pkg)`.
+The hub constructs every declared service (all devframes plus `initHub`) **once**, deep-merging option sets (objects recurse, arrays union-dedupe, scalars later-win; override with `mergeOptions`), **before any `setup(ctx)` runs**, so setup consumes services synchronously via `ctx.services.get(pkg)`.
For a runtime-only service, `ctx.services.install(input)` builds immediately; re-installing a constructed package returns the existing API, warning [`DF0066`](https://devfra.me/errors/DF0066) if options can't merge.
@@ -117,14 +117,14 @@ A reactive UI subscribes via `rpc.services.state()`. `has()`/`get()`/`keys()` ar
Three first-party wire services ship ready to install, each with its own page under [Add-ons › Services](/add-ons/services):
-- **[`@devframes/service-open`](/add-ons/services/open)** (`devframes:service:open`) — open files in an editor or OS explorer, refusing paths outside the workspace root.
-- **[`@devframes/service-git`](/add-ons/services/git)** (`devframes:service:git`) — typed read/write git operations on one repo.
-- **[`@devframes/service-shiki`](/add-ons/services/shiki)** (`devframes:service:shiki`) — node-side [Shiki](https://shiki.style) highlighting, LRU-cached and dual-theme.
+- **[`@devframes/service-open`](/add-ons/services/open)** (`devframes:service:open`): open files in an editor or OS explorer, refusing paths outside the workspace root.
+- **[`@devframes/service-git`](/add-ons/services/git)** (`devframes:service:git`): typed read/write git operations on one repo.
+- **[`@devframes/service-shiki`](/add-ons/services/shiki)** (`devframes:service:shiki`): node-side [Shiki](https://shiki.style) highlighting, LRU-cached and dual-theme.
## Services, RPC, or shared state?
-- **Services** — node-to-node in-process live references, never crossing a wire.
-- **[RPC](/guide/rpc)** — browser-to-node: an RPC client calls a named function.
-- **[Shared state](/guide/shared-state)** — serializable data synced node side ↔ RPC clients.
+- **Services**: node-to-node in-process live references, never crossing a wire.
+- **[RPC](/guide/rpc)**: browser-to-node calls to a named function.
+- **[Shared state](/guide/shared-state)**: serializable data synced node side ↔ RPC clients.
A service serves *other devframes*, RPC *surfaces or coding agents*, a [wire service](#wire-services) both.
diff --git a/docs/content/1.guide/2.devframe-definition.md b/docs/content/1.guide/2.devframe-definition.md
index 3316e1e1d..14c171332 100644
--- a/docs/content/1.guide/2.devframe-definition.md
+++ b/docs/content/1.guide/2.devframe-definition.md
@@ -66,12 +66,14 @@ export default defineDevframe({
```ts
export default defineDevframe({
- // …metadata as above
+ /** …metadata as above */
importMetaUrl: import.meta.url,
- // Served from the locally installed `my-tool--assets`, resolved via
- // `importMetaUrl` — works under pnpm's strict layout with zero network.
+ /**
+ * Served from the locally installed `my-tool--assets`, resolved via
+ * `importMetaUrl`; it works under pnpm's strict layout with zero network.
+ */
clientAssets: { package: `${pkg.name}--assets`, version: pkg.version },
- // Imported from `my-tool`'s own dependency graph.
+ /** Imported from `my-tool`'s own dependency graph. */
services: [{ package: '@scope/my-service', version: pkg.version }],
setup(ctx) { /* … */ },
})
@@ -85,16 +87,18 @@ For remote assets, `importMetaUrl` is the default `resolveFrom`; a per-source va
import { fileURLToPath } from 'node:url'
export default defineDevframe({
- // …metadata as above
+ /** …metadata as above */
importMetaUrl: import.meta.url,
- // A local build resolved from the module — works from source and the
- // published package.
+ /**
+ * A local build resolved from the module; it works from source and the
+ * published package.
+ */
clientAssets: fileURLToPath(new URL('../dist/spa', import.meta.url)),
setup(ctx) { /* … */ },
})
```
-For assets you host yourself, call `ctx.views.hostStatic` in `setup` — [Client Assets](/guide/client-assets#programmatic-hosting-from-setup).
+For assets you host yourself, call `ctx.views.hostStatic` in `setup`; see [Client Assets](/guide/client-assets#programmatic-hosting-from-setup).
### Runtime flags
@@ -106,10 +110,12 @@ defineDevframe({
name: 'My Tool',
setup(ctx) {
if (ctx.mode === 'build') {
- // Static-only work — baked into the RPC dump.
+ // Static-only work, baked into the RPC dump.
+ ctx.rpc.addFunctions(staticFunctions)
}
else {
// Dev-mode wiring, file watchers, etc.
+ watchProject(ctx)
}
},
})
@@ -141,7 +147,7 @@ interface DevframeNodeContext {
### Cross-devframe services
-`ctx.services` is a typed, namespaced registry — one devframe exposes a capability, others consume it ([Cross-Devframe Services](/guide/services)).
+`ctx.services` is a typed, namespaced registry: one devframe exposes a capability, others consume it ([Cross-Devframe Services](/guide/services)).
```ts
ctx.services.provide('my-plugin:sources', sources)
@@ -153,7 +159,7 @@ ctx.services.whenAvailable('my-plugin:sources', (sources) => {
### Static connection configs
-`ctx.staticConfig` is this context's own `ConnectionMeta.configs` — read-only boot-time data from the connection handshake; write it during `setup(ctx)`. Contrast `ctx.scope(id).settings` (mutable, synced).
+`ctx.staticConfig` is this context's own `ConnectionMeta.configs`: read-only boot-time data from the connection handshake; write it during `setup(ctx)`. Contrast `ctx.scope(id).settings` (mutable, synced).
```ts
declare module 'devframe/types' {
@@ -171,7 +177,7 @@ ctx.staticConfig['my-plugin'] = { featureFlag: true }
`ctx.scope(id)` returns a namespace-scoped view ([Scoped Context](/guide/scoped-context)) auto-prefixing every RPC id, shared-state key, and streaming channel, plus a persisted `settings` store (`project`/`global` scopes use the matching storage classes).
-Hosted adapters can augment `ctx` — e.g. the [`vite` adapter](/adapters/vite)'s dock, command, message, and terminal hosts.
+Hosted adapters can augment `ctx`, e.g. the [`vite` adapter](/adapters/vite)'s dock, command, message, and terminal hosts.
## CLI options
@@ -195,7 +201,7 @@ defineDevframe({
},
},
setup(ctx, { flags }) {
- // `flags` carries the parsed cac bag — contains built-in flags
+ // `flags` carries the parsed cac bag: the built-in flags
// (`--port`, `--host`, `--open`, `--no-open`) and anything you added
// in `configure`.
},
@@ -221,12 +227,12 @@ await createCac(myDevframe).parse()
// 2. Offline snapshot:
await createBuild(myDevframe, { outDir: 'dist-static' })
-// 3. Mount into a host framework (Vite DevTools shown — others can implement equivalents):
+/** 3. Mount into a host framework (Vite DevTools shown; others can implement equivalents): */
export const myPlugin = () => createPluginFromDevframe(myDevframe)
```
## What's next
-- [Adapters](/adapters) — deployment targets
-- [RPC](/guide/rpc) — register node-side functions
-- [`vite` adapter](/adapters/vite) — mount into a host framework
+- [Adapters](/adapters): deployment targets
+- [RPC](/guide/rpc): register node-side functions
+- [`vite` adapter](/adapters/vite): mount into a host framework
diff --git a/docs/content/1.guide/20.deep-linking.md b/docs/content/1.guide/20.deep-linking.md
index c33eec976..89a95afcb 100644
--- a/docs/content/1.guide/20.deep-linking.md
+++ b/docs/content/1.guide/20.deep-linking.md
@@ -2,10 +2,10 @@
title: 'Deep Linking'
navigation:
icon: i-lucide-link
-description: 'Send a user to a view inside a devframe — from another dock, a coding agent, or a copied URL — two ways: the hub relays a dock activation to focus a dock in place; a standalone SPA reads its URL hash to restore the view.'
+description: 'Send a user to a view inside a devframe (from another dock, a coding agent, or a copied URL) two ways: the hub relays a dock activation to focus a dock in place; a standalone SPA reads its URL hash to restore the view.'
---
-Send a user to a view inside a devframe — from another dock, a coding agent, or a copied URL — two ways: the hub relays a **dock activation** to focus a dock in place; a standalone SPA reads its **URL hash** to restore the view.
+Send a user to a view inside a devframe (from another dock, a coding agent, or a copied URL) two ways: the hub relays a **dock activation** to focus a dock in place; a standalone SPA reads its **URL hash** to restore the view.
## Focusing a dock inside a hub
@@ -18,7 +18,7 @@ await rpc.call('hub:docks:activate', {
})
```
-The hub broadcasts the request and mirrors it into the [`devframe:docks:active`](/guide/shared-state) slot, so a dock mounting *because* of the switch converges on it. The target subscribes, filters on its `dockId`, and reads `params` — see [Cross-iframe dock activation](/guide/hub#cross-iframe-dock-activation).
+The hub broadcasts the request and mirrors it into the [`devframe:docks:active`](/guide/shared-state) slot, so a dock mounting *because* of the switch converges on it. The target subscribes, filters on its `dockId`, and reads `params`; see [Cross-iframe dock activation](/guide/hub#cross-iframe-dock-activation).
Focus is one-shot: the [terminals dock](/add-ons/devframes/terminals#focusing-a-session) reads `params.sessionId`, the [Data Inspector](/add-ons/devframes/data-inspector#deep-linking) `params.sourceId`; a target naming something unregistered waits, then fires once. An id that never arrives is a no-op; an unknown `dockId` warns ([DF8107](/errors/DF8107)).
diff --git a/docs/content/1.guide/21.build-your-own-json-render-frontend.md b/docs/content/1.guide/21.build-your-own-json-render-frontend.md
index 57efb4970..6eb9dd852 100644
--- a/docs/content/1.guide/21.build-your-own-json-render-frontend.md
+++ b/docs/content/1.guide/21.build-your-own-json-render-frontend.md
@@ -25,32 +25,32 @@ const renderer: JsonRenderDockRenderer = async ({ entry, container, context }) =
Resolve the entry's `view`:
-- `{ stateKey }` — subscribe via `context.rpc.sharedState.get(stateKey)`, render
+- `{ stateKey }`: subscribe via `context.rpc.sharedState.get(stateKey)`, render
it as the live spec, re-render on `'updated'`. **Unsubscribe in `dispose`.**
-- `{ spec }` — render the embedded spec directly.
+- `{ spec }`: render the embedded spec directly.
Detect static output via `context.rpc.connectionMeta.backend === 'static'`,
disabling action dispatch there.
## Behavior expectations
-- **Actions** — a spec action name dispatches the same-named RPC call. Never
+- **Actions**: a spec action name dispatches the same-named RPC call. Never
bridge the reserved built-ins (`setState`, `pushState`, `removeState`,
`validateForm`) or promise probes (`then`/`catch`/`finally`); surface failures
to the view.
-- **Validation** — validate element props against `basePropSchemas` from
+- **Validation**: validate element props against `basePropSchemas` from
`@devframes/json-render`; swap an invalid element for an error placeholder.
-- **Unknown components** — a component your registry lacks renders as a
+- **Unknown components**: a component your registry lacks renders as a
placeholder (type + prop-key gist) with a `console.warn`; the rest renders.
-- **State reset** — reseed spec state only when the view identity changes, not
+- **State reset**: reseed spec state only when the view identity changes, not
on every update.
## Plugging it in
-- **Local registration** — a hub UI provider bundling its own client runtime passes
+- **Local registration**: a hub UI provider bundling its own client runtime passes
`createDevframeClientRuntime({ renderers: { 'json-render': myRenderer } })`;
local registrations win over the manifest.
-- **A prebuilt renderer module** — bundle your renderer as one self-contained
+- **A prebuilt renderer module**: bundle your renderer as one self-contained
browser ES module (framework and styles included), default-exporting the
renderer, plus a node helper returning the registration:
diff --git a/docs/content/1.guide/22.build-your-own-hub-ui.md b/docs/content/1.guide/22.build-your-own-hub-ui.md
index a1a10f61e..25618ff88 100644
--- a/docs/content/1.guide/22.build-your-own-hub-ui.md
+++ b/docs/content/1.guide/22.build-your-own-hub-ui.md
@@ -2,10 +2,10 @@
title: 'Build Your Own Hub UI'
navigation:
icon: i-lucide-palette
-description: 'A hub UI provider implements two contracts — the node-side ui slot and the browser-side context. @devframes/hub-ui is the reference.'
+description: 'A hub UI provider implements two contracts, the node-side ui slot and the browser-side context. @devframes/hub-ui is the reference.'
---
-A hub UI provider implements two contracts — the node-side `ui` slot and the browser-side context. `@devframes/hub-ui` is the reference.
+A hub UI provider implements two contracts, the node-side `ui` slot and the browser-side context. `@devframes/hub-ui` is the reference.
## The node seam: `DevframeHubUi`
@@ -56,8 +56,8 @@ report it unreachable: its fallback page posts a `RemoteAssetsErrorMessage`
### The renderer registry and its fallback
-**Every other dock type routes through the dock-renderer registry** — build it
-with `createDockRenderersContext()` (`@devframes/hub/client`), wiring local
+**Every other dock type routes through the dock-renderer registry**: build it
+ with `createDockRenderersContext()` (`@devframes/hub/client`), wiring local
registrations and the hub's [renderer manifest](/guide/hub-initiate#renderer-modules):
```ts
@@ -73,22 +73,22 @@ const result = await renderers.mount(entry, container)
Show a state per mount-result variant:
-- `{ status: 'mounted', dispose }` — the renderer owns the container; call
+- `{ status: 'mounted', dispose }`: the renderer owns the container; call
`dispose` on unmount.
-- `{ status: 'missing-renderer' }` — render a fallback (`renderers.has(type)`
+- `{ status: 'missing-renderer' }`: render a fallback (`renderers.has(type)`
answers up front).
-- `{ status: 'load-error', error }` — import failed or the renderer threw;
+- `{ status: 'load-error', error }`: import failed or the renderer threw;
render the error with retry.
### The theme contract for renderers
Renderer modules self-style (sometimes via a shadow root). Keep a live
-`dark` class on the mount container and let CSS custom properties inherit — a
+`dark` class on the mount container and let CSS custom properties inherit; a
`--devframe-primary` ancestor rebrands rendered content.
## Reference points
-- `packages/hub-ui` — the full reference hub UI provider (Vue, `@antfu/design`).
+- `packages/hub-ui`: the full reference hub UI provider (Vue, `@antfu/design`).
- [`examples/hub-vite`](https://github.com/devframes/devframe/tree/main/examples/hub-vite) and
- [`examples/hub-next`](https://github.com/devframes/devframe/tree/main/examples/hub-next) — hand-rolled
+ [`examples/hub-next`](https://github.com/devframes/devframe/tree/main/examples/hub-next): hand-rolled
hub UI providers in vanilla DOM and React.
diff --git a/docs/content/1.guide/23.built-with.md b/docs/content/1.guide/23.built-with.md
index 88548964c..f3d08e837 100644
--- a/docs/content/1.guide/23.built-with.md
+++ b/docs/content/1.guide/23.built-with.md
@@ -2,14 +2,14 @@
title: 'Built with Devframe'
navigation:
icon: i-lucide-blocks
-description: 'Real-world devtools and hub UI providers built on devframe — from Vite DevTools to ESLint Config Inspector.'
+description: 'Real-world devtools and hub UI providers built on devframe, from Vite DevTools to ESLint Config Inspector.'
---
## Real-world DevTools
-- [**Vite DevTools**](https://devtools.vite.dev/) — bundles many devframes into one UI. Mount your own via the [`vite` adapter](/adapters/vite).
-- [**ESLint Config Inspector**](https://github.com/eslint/config-inspector) — inspects flat configs.
-- [**node-modules-inspector**](https://github.com/antfu/node-modules-inspector) — visualizes your `node_modules` dependency graph.
+- [**Vite DevTools**](https://devtools.vite.dev/) bundles many devframes into one UI. Mount your own via the [`vite` adapter](/adapters/vite).
+- [**ESLint Config Inspector**](https://github.com/eslint/config-inspector) inspects flat configs.
+- [**node-modules-inspector**](https://github.com/antfu/node-modules-inspector) visualizes your `node_modules` dependency graph.
## Built-in Devframes
diff --git a/docs/content/1.guide/3.rpc.md b/docs/content/1.guide/3.rpc.md
index 0765de9da..929074d3f 100644
--- a/docs/content/1.guide/3.rpc.md
+++ b/docs/content/1.guide/3.rpc.md
@@ -14,7 +14,7 @@ import { defineRpcFunction } from 'devframe'
import * as v from 'valibot' // npm i valibot (or use zod / arktype)
export const getModules = defineRpcFunction({
- name: 'get-modules', // bare — the scope namespaces it to `my-tool:get-modules`
+ name: 'get-modules', // bare: the scope namespaces it to `my-tool:get-modules`
type: 'query',
args: [v.object({ limit: v.number() })],
returns: v.array(v.object({ id: v.string(), size: v.number() })),
@@ -27,7 +27,7 @@ export const getModules = defineRpcFunction({
})
```
-Register it via a [scoped context](/guide/scoped-context) — `ctx.scope(id)` auto-namespaces ids:
+Register it via a [scoped context](/guide/scoped-context); `ctx.scope(id)` auto-namespaces ids:
```ts
import { defineDevframe } from 'devframe'
@@ -79,7 +79,7 @@ defineDevframe({
})
```
-Beyond `method` and `args`, `optional` skips throwing when no RPC client is listening, `event` makes the broadcast fire-and-forget, and `filter` skips specific RPC clients — see the [Node-Side API reference](/references/node-api#broadcast-options).
+Beyond `method` and `args`, `optional` skips throwing when no RPC client is listening, `event` makes the broadcast fire-and-forget, and `filter` skips specific RPC clients; see the [Node-Side API reference](/references/node-api#broadcast-options).
## Streaming
@@ -122,7 +122,7 @@ Browser-side registration (node side → browser side) uses `my.rpc.register()`.
## Type-safe RPC-client registry
-Two augmentable interfaces — `DevframeRpcServerFunctions` (client→server) and `DevframeRpcClientFunctions` (server→client) — type each registered name on the RPC client via `declare module 'devframe'`. Feed a const array through `RpcDefinitionsToFunctionsWithNamespace`, which prefixes each bare name with your id:
+Two augmentable interfaces, `DevframeRpcServerFunctions` (client→server) and `DevframeRpcClientFunctions` (server→client), type each registered name on the RPC client via `declare module 'devframe'`. Feed a const array through `RpcDefinitionsToFunctionsWithNamespace`, which prefixes each bare name with your id:
```ts
import type { RpcDefinitionsToFunctionsWithNamespace } from 'devframe/rpc'
@@ -183,7 +183,7 @@ The WS transport picks one of two encoders per function:
| `false` (default) | `structured-clone-es` | `s:` | `Map`, `Set`, `Date`, `BigInt`, cycles, class instances |
| `true` (opt-in) | strict `JSON.stringify` | _(unprefixed)_ | JSON-only |
-When every function is JSON-flagged, the wire stays plain JSON. A `jsonSerializable: true` handler must return JSON-only values — `Map`, `Date`, and friends won't round-trip.
+When every function is JSON-flagged, the wire stays plain JSON. A `jsonSerializable: true` handler must return JSON-only values; `Map`, `Date`, and friends won't round-trip.
## Agent exposure
@@ -211,6 +211,6 @@ Exposing a function over MCP requires `jsonSerializable: true`.
## What's next
-- [Shared State](/guide/shared-state) — state synced across RPC clients
-- [Client](/guide/client) — connecting from the browser
-- [Agent-Native](/guide/agent-native) — exposing RPCs to coding agents
+- [Shared State](/guide/shared-state): state synced across RPC clients
+- [Client](/guide/client): connecting from the browser
+- [Agent-Native](/guide/agent-native): exposing RPCs to coding agents
diff --git a/docs/content/1.guide/4.shared-state.md b/docs/content/1.guide/4.shared-state.md
index 81bd88a26..276c60254 100644
--- a/docs/content/1.guide/4.shared-state.md
+++ b/docs/content/1.guide/4.shared-state.md
@@ -2,10 +2,10 @@
title: 'Shared State'
navigation:
icon: i-lucide-database-zap
-description: 'Shared state is observable, immutable-by-default state synced between the node side and every RPC client, surviving reconnects — a new RPC client gets the snapshot.'
+description: 'Shared state is observable, immutable-by-default state synced between the node side and every RPC client, surviving reconnects: a new RPC client gets the snapshot.'
---
-Shared state is observable, immutable-by-default state synced between the node side and every RPC client, surviving reconnects — a new RPC client gets the snapshot.
+Shared state is observable, immutable-by-default state synced between the node side and every RPC client, surviving reconnects: a new RPC client gets the snapshot.
## Overview
@@ -58,7 +58,7 @@ The scope prefixes `:` (wrapping `ctx.rpc.sharedState.get(...)`), s
```ts
const current = state.value()
console.log(current.count)
-// current.count = 1 // ✗ TypeScript error — snapshot is Immutable
+// current.count = 1 // ✗ TypeScript error: snapshot is Immutable
```
## Mutating
@@ -81,7 +81,7 @@ Enable patches for minimal network diffs; `updated` then carries `Patch[]`:
```ts
const state = await ctx.rpc.sharedState.get('my-tool:big-state', {
initialValue: largeTree,
- // sharedState-level enablePatches is opt-in:
+ /** sharedState-level enablePatches is opt-in: */
sharedState: createSharedState({ initialValue: largeTree, enablePatches: true }),
})
```
diff --git a/docs/content/1.guide/5.streaming.md b/docs/content/1.guide/5.streaming.md
index 6876c0d49..5aea18a35 100644
--- a/docs/content/1.guide/5.streaming.md
+++ b/docs/content/1.guide/5.streaming.md
@@ -61,22 +61,22 @@ export default defineDevframe({
})
```
-## Producing — three APIs, one stream
+## Producing: three APIs, one stream
```ts
const stream = channel.start({ id: 'optional-explicit-id' })
-// Imperative — minimal, hand-rolled producers
+// Imperative: minimal, hand-rolled producers
stream.write(chunk)
stream.error(err) // terminal failure
stream.close() // terminal success
-stream.signal // AbortSignal — flips when consumers cancel
-stream.id // string — what RPC clients subscribe to
+stream.signal // AbortSignal: flips when consumers cancel
+stream.id // string: what RPC clients subscribe to
-// Web Streams — pipe any ReadableStream in:
+// Web Streams: pipe any ReadableStream in:
sourceReadable.pipeTo(stream.writable, { signal: stream.signal })
-// Convenience — start + pipe in one call:
+// Convenience: start + pipe in one call:
const stream = await channel.pipeFrom(sourceReadable)
```
@@ -94,7 +94,7 @@ sourceNodeReadable.pipe(Writable.fromWeb(stream.writable))
Readable.fromWeb(reader.readable).pipe(targetNodeWritable)
```
-## Consuming — `for await` or `pipeTo`
+## Consuming: `for await` or `pipeTo`
The reader is an `AsyncIterable` also exposing `.readable` (`ReadableStream`), one per reader.
@@ -108,7 +108,7 @@ const { streamId } = await my.rpc.call('start-chat', {
const reader = my.rpc.streaming.subscribe('chat', streamId) // -> my-tool:chat
-// Async iterable — the simplest consumer pattern
+// Async iterable: the simplest consumer pattern
for await (const token of reader)
appendToken(token)
@@ -120,14 +120,14 @@ reader.cancel() // sends cancel upstream; the node-side stream.signal flips
## Lifecycle and cancellation
-`stream.close()` / `stream.error(err)` broadcast `end`, resolving (or throwing inside) the browser-side `for await`. Cancellation flows upstream: `reader.cancel()` — or the **last** subscriber's WS dropping — aborts `stream.signal`; a disconnected reader survives and resubscribes on re-trust. The event-by-event matrix is in the [Node-Side API reference](/references/node-api#streaming-lifecycle).
+`stream.close()` / `stream.error(err)` broadcast `end`, resolving (or throwing inside) the browser-side `for await`. Cancellation flows upstream: `reader.cancel()`, or the **last** subscriber's WS dropping, aborts `stream.signal`; a disconnected reader survives and resubscribes on re-trust. The event-by-event matrix is in the [Node-Side API reference](/references/node-api#streaming-lifecycle).
## Browser-to-node uploads
In reverse: an RPC call allocates the id; events carry chunks.
```ts
-// Node side — typically inside an action handler
+// Node side: typically inside an action handler
ctx.rpc.register(defineRpcFunction({
name: 'my-tool:upload-file',
type: 'action',
@@ -136,7 +136,7 @@ ctx.rpc.register(defineRpcFunction({
handler: async ({ name }) => {
const reader = channel.openInbound()
- // Process chunks asynchronously — the action returns immediately
+ // Process chunks asynchronously; the action returns immediately
// so the browser side can start uploading.
;(async () => {
const file = createWriteStream(name)
@@ -166,7 +166,7 @@ upload.close()
fileReadable.pipeTo(upload.writable, { signal: upload.signal })
```
-Lifecycle mirrors outbound: `upload.signal` aborts on `reader.cancel()` (broadcasting `upload-cancel`), `upload.error(err)` throws inside its `for await`, and an RPC-client disconnect exits with `UploadDisconnected`. Each `openInbound()` id is point-to-point — one producer, no fan-in or replay.
+Lifecycle mirrors outbound: `upload.signal` aborts on `reader.cancel()` (broadcasting `upload-cancel`), `upload.error(err)` throws inside its `for await`, and an RPC-client disconnect exits with `UploadDisconnected`. Each `openInbound()` id is point-to-point: one producer, no fan-in or replay.
## Replay on reconnect
diff --git a/docs/content/1.guide/6.client-assets.md b/docs/content/1.guide/6.client-assets.md
index 6107159d8..24d64a631 100644
--- a/docs/content/1.guide/6.client-assets.md
+++ b/docs/content/1.guide/6.client-assets.md
@@ -2,10 +2,10 @@
title: 'Client Assets'
navigation:
icon: i-lucide-folder
-description: 'A devframe''s UI is a built SPA; clientAssets says where it lives — a local directory or published npm package.'
+description: 'A devframe''s UI is a built SPA; clientAssets says where it lives: a local directory or published npm package.'
---
-A devframe's UI is a built SPA; `clientAssets` says where it lives — a **local directory** or **published npm package**.
+A devframe's UI is a built SPA; `clientAssets` says where it lives: a **local directory** or **published npm package**.
## Mounting a local build
@@ -49,7 +49,7 @@ export default defineDevframe({
fileURLToPath(new URL('../dist/docs', import.meta.url)),
)
- // A remote source works here too — same shape as `clientAssets`.
+ // A remote source works here too, same shape as `clientAssets`.
ctx.views.hostStatic('/legacy/', {
package: '@acme/my-tool-legacy-ui',
version: pkg.version,
@@ -92,19 +92,19 @@ The definition's [`importMetaUrl`](/guide/devframe-definition#resolving-against-
Per request, resolution tries in order:
-1. **Locally installed package** — resolved from `resolveFrom` (default `importMetaUrl`); served with no network.
-2. **On-disk cache** — files already fetched, under the project's storage directory.
-3. **CDN back-proxy** — [jsDelivr](https://www.jsdelivr.com/) by default; exact-version URLs are immutable, so caches never stale.
+1. **Locally installed package**: resolved from `resolveFrom` (default `importMetaUrl`); served with no network.
+2. **On-disk cache**: files already fetched, under the project's storage directory.
+3. **CDN back-proxy**: [jsDelivr](https://www.jsdelivr.com/) by default; exact-version URLs are immutable, so caches never stale.
### Options
-`package` and `version` (exact) name the published assets; `resolveFrom`, `path`, `provider`, and `offline` tune resolution — every field is in the [Node-Side API reference](/references/node-api#remote-assets-options).
+`package` and `version` (exact) name the published assets; `resolveFrom`, `path`, `provider`, and `offline` tune resolution; every field is in the [Node-Side API reference](/references/node-api#remote-assets-options).
An invalid npm name or non-exact version throws [`DF0065`](/errors/DF0065).
### Offline and air-gapped use
-Install the assets package explicitly — step 1 serves it locally. Set `offline: true` to never contact the CDN, or point `provider` at a mirror:
+Install the assets package explicitly; step 1 serves it locally. Set `offline: true` to never contact the CDN, or point `provider` at a mirror:
```sh
npm install @acme/my-tool-assets
diff --git a/docs/content/1.guide/7.scoped-context.md b/docs/content/1.guide/7.scoped-context.md
index 3f79c4b23..de0d40502 100644
--- a/docs/content/1.guide/7.scoped-context.md
+++ b/docs/content/1.guide/7.scoped-context.md
@@ -21,7 +21,7 @@ export default defineDevframe({
const my = ctx.scope('my-plugin')
my.rpc.register(defineRpcFunction({
- name: 'get-modules', // bare name — stored as `my-plugin:get-modules`
+ name: 'get-modules', // bare name: stored as `my-plugin:get-modules`
type: 'query',
handler: () => loadModules(),
}))
@@ -41,7 +41,7 @@ declare function loadModules(): { id: string }[]
Bare names are prefixed `:` (`call('get-modules')` → `my-plugin:get-modules`); a name with `:` passes through unchanged to another tool (`call('other-plugin:status')`).
-`register` accepts only bare names; an already-namespaced one throws [`DF0034`](/errors/DF0034) — use `ctx.base.rpc.register`.
+`register` accepts only bare names; an already-namespaced one throws [`DF0034`](/errors/DF0034); use `ctx.base.rpc.register`.
Bare names stay typed: `call('get-modules')` resolves to your [RPC registry](/guide/rpc#type-safe-rpc-client-registry) entry, `sharedState('selection')` to the matching [`DevframeRpcSharedStates`](/guide/shared-state#type-safe-keys) key.
@@ -49,8 +49,8 @@ Bare names stay typed: `call('get-modules')` resolves to your [RPC registry](/gu
`my.settings` is a persisted key-value store (alongside `my.rpc`), with two scopes:
-- **`project`** — per-checkout values, under the `workspace` storage dir.
-- **`global`** — per-user values, under the `global` storage dir.
+- **`project`**: per-checkout values, under the `workspace` storage dir.
+- **`global`**: per-user values, under the `global` storage dir.
Both are file-backed and synced to the browser over the shared-state protocol; a `set` propagates to peers, surviving restarts.
@@ -58,8 +58,8 @@ Both are file-backed and synced to the browser over the shared-state protocol; a
const { settings } = my
await settings.project.set('theme', 'dark')
-await settings.project.get('theme') // 'dark'
-await settings.project.all() // { theme: 'dark' }
+await settings.project.get('theme') // => 'dark'
+await settings.project.all() // => theme is 'dark'
await settings.project.delete('theme')
const off = await settings.global.onChange((value) => {
diff --git a/docs/content/1.guide/8.json-render.md b/docs/content/1.guide/8.json-render.md
index 9bafe2b1f..05e798226 100644
--- a/docs/content/1.guide/8.json-render.md
+++ b/docs/content/1.guide/8.json-render.md
@@ -2,17 +2,17 @@
title: 'JSON-Render'
navigation:
icon: i-lucide-braces
-description: 'JSON-render describes a UI as data — a serializable component spec any frontend renders. Opt-in: a plain devframe pulls zero JSON-render dependencies. Two packages:'
+description: 'JSON-render describes a UI as data: a serializable component spec any frontend renders. Opt-in: a plain devframe pulls zero JSON-render dependencies. Two packages:'
---
-JSON-render describes a UI as **data** — a serializable component spec any
+JSON-render describes a UI as **data**: a serializable component spec any
frontend renders. **Opt-in**: a plain devframe pulls zero JSON-render
dependencies. Two packages:
-- **`@devframes/json-render`** — framework-neutral protocol layer (spec/catalog
+- **`@devframes/json-render`**: framework-neutral protocol layer (spec/catalog
types, prop schemas, view refs, node runtime), built on
[`@json-render/core`](https://www.npmjs.com/package/@json-render/core).
-- **`@devframes/json-render-ui`** — reference Vue frontend implementing the
+- **`@devframes/json-render-ui`**: reference Vue frontend implementing the
base catalog with [`@antfu/design`](https://github.com/antfu/design).
## Authoring a view
@@ -23,7 +23,7 @@ dependencies. Two packages:
import { createJsonRenderView } from '@devframes/json-render/node'
export default defineDevframe({
- // …
+ /** … */
setup(ctx) {
const view = createJsonRenderView(ctx, {
id: 'metrics', // stable, unique within the scope
@@ -56,7 +56,7 @@ use ([DF0040](/errors/DF0040)), non-serializable spec
## The base catalog
-Catalog v1 ships fourteen components — `Stack`, `Card`, `Text`, `Badge`,
+Catalog v1 ships fourteen components: `Stack`, `Card`, `Text`, `Badge`,
`Button`, `Icon`, `Divider`, `TextInput`, `Switch`, `KeyValueTable`,
`DataTable`, `CodeBlock`, `Progress`, `Tree`. A spec **is** an `@json-render/core`
`Spec` plus a per-component Zod prop schema (`basePropSchemas`), validated at
@@ -68,7 +68,7 @@ bindings work on scalar props.
- **State** is a JSON-serializable `Record` addressed by JSON
Pointer.
- **Actions** are unrestricted: an element event dispatches an RPC call of the
- same name — no allowlist.
+ same name, with no allowlist.
- **Reserved built-ins** (`setState`, `pushState`, `removeState`,
`validateForm`) are handled client-side, never bridged to RPC.
@@ -104,7 +104,7 @@ view renders full-bleed, multiple get a `title`-labeled switcher.
A custom frontend renders from shared state: connect with `connectDevframe()`,
read the view's state (keyed `devframe:json-render::`), subscribe to
-`updated` events, and render with your registry — the [Next
+`updated` events, and render with your registry; the [Next
hub example](https://github.com/devframes/devframe/tree/main/examples/hub-next) has a React renderer. In a
**static** build spec + state are read-only: actions unavailable, local
state and bindings still work.
@@ -118,7 +118,7 @@ state and bindings still work.
`@devframes/json-render/hub` adds a `json-render` dock type:
```ts
-// node side — register a dock entry carrying the view's serializable reference,
+// node side: register a dock entry carrying the view's serializable reference,
// and compose the frontend as a prebuilt renderer module
import { jsonRenderUiRenderer } from '@devframes/json-render-ui/hub'
import { toJsonRenderDockEntry } from '@devframes/json-render/hub'
@@ -142,7 +142,7 @@ missing-renderer fallback). A host page can register a
`JsonRenderDockRenderer` **locally** instead, overriding the manifest:
```ts
-// host page — a locally-bundled frontend wins over the manifest module
+// host page: a locally-bundled frontend wins over the manifest module
import { createDevframeClientRuntime } from '@devframes/hub/client'
import { myJsonRenderDockRenderer } from './my-renderer'
@@ -162,7 +162,7 @@ for a browser-synthesized [client-only dock](/guide/client-context#client-only-d
## Swapping the frontend
-`@devframes/json-render/hub` exports the contract — `JsonRenderDockRenderer` and
+`@devframes/json-render/hub` exports the contract, `JsonRenderDockRenderer` and
`JsonRenderDockMountOptions`; `@devframes/json-render-ui` is the pluggable
reference implementation.
See [Build your own JSON-Render frontend](/guide/build-your-own-json-render-frontend)
diff --git a/docs/content/1.guide/9.diagnostics.md b/docs/content/1.guide/9.diagnostics.md
index 666c167bc..39fc4dc5d 100644
--- a/docs/content/1.guide/9.diagnostics.md
+++ b/docs/content/1.guide/9.diagnostics.md
@@ -10,7 +10,7 @@ description: 'ctx.diagnostics is a thin layer over nostics for author-defined co
| Surface | Purpose | Example |
|---------|---------|---------|
| `ctx.diagnostics` | Coded errors and warnings emitted from node-side code | `MYP0001: Plugin foo not configured` |
-| [`ctx.messages`](https://devtools.vite.dev/kit/messages) | Free-form, user-facing notifications shown in the Messages panel | `'Audit complete — 3 issues found'` |
+| [`ctx.messages`](https://devtools.vite.dev/kit/messages) | Free-form, user-facing notifications shown in the Messages panel | `'Audit complete: 3 issues found'` |
## Shape
@@ -45,7 +45,7 @@ export function MyPlugin(): PluginWithDevTools {
fix: 'Add the plugin to your `vite.config.ts` and pass an options object.',
},
MYP0002: {
- why: 'Cache directory missing — running cold.',
+ why: 'Cache directory missing; running cold.',
},
},
})
@@ -70,10 +70,10 @@ A definition takes a `why` (message) and optional `fix` (resolution), string or
## Emit a diagnostic
-Each registered code becomes a callable `DiagnosticHandle` — call it to report, or `throw` to raise.
+Each registered code becomes a callable `DiagnosticHandle`: call it to report, or `throw` to raise.
```ts
-// Throw — control flow stops here
+// Throw: control flow stops here
throw myDiagnostics.MYP0001({ name: 'foo' })
// Report without throwing (default console method: `warn`)
@@ -82,7 +82,7 @@ myDiagnostics.MYP0002()
// Override the console method per call
myDiagnostics.MYP0002({}, { method: 'error' })
-// Attach a `cause` — merged into the params object
+// Attach a `cause`: merged into the params object
throw myDiagnostics.MYP0001({ name: 'foo', cause: error })
```
diff --git a/docs/content/1.guide/index.md b/docs/content/1.guide/index.md
index 7bb58f446..bc2fbc86a 100644
--- a/docs/content/1.guide/index.md
+++ b/docs/content/1.guide/index.md
@@ -9,13 +9,13 @@ description: 'Devframe is a framework-neutral foundation for building a devtool
## Why it exists
-Most devtools rebuild the same plumbing — node–browser communication, state synchronization, serialization, static-asset hosting, a web interface — and wire it to one framework's dev server. The same idea then gets rebuilt, slightly differently, for the next framework, so effort fragments across the ecosystem instead of compounding.
+Most devtools rebuild the same plumbing (node–browser communication, state synchronization, serialization, static-asset hosting, a web interface) and wire it to one framework's dev server. The same idea then gets rebuilt, slightly differently, for the next framework, so effort fragments across the ecosystem instead of compounding.
Devframe moves that boundary. A capability is defined once against a stable interface and runs on every supported host framework, so a good tool can be built once, travel further, and improve through the work of more communities.
## Who it's for
-- **Devtool authors** who want one tool to run standalone, embed in a host framework, ship as a CLI or static report, and answer to a coding agent — without maintaining a separate version per environment.
+- **Devtool authors** who want one tool to run standalone, embed in a host framework, ship as a CLI or static report, and answer to a coding agent, without maintaining a separate version per environment.
- **Framework and build-tool teams** who want to offer devtools without rebuilding shared infrastructure, and to inherit capabilities other communities already built.
- **Anyone** who wants a tool's state and actions available to both a human UI and a coding agent from one source of truth.
@@ -34,7 +34,7 @@ import { inspectProject } from './rpc'
export default defineDevframe({
id: 'my-tool',
name: 'My Tool',
- // package metadata and client entry omitted…
+ /** package metadata and client entry omitted… */
setup(ctx) {
ctx.scope('my-tool').rpc.register(inspectProject)
},
@@ -53,7 +53,7 @@ devtools.handler
// (request: Request) => Promise
devtools.nodeMiddleware
-// (req, res, next) => void — for Connect-style servers (Vite, Rsbuild)
+// (req, res, next) => void, for Connect-style servers (Vite, Rsbuild)
```
The handler serves the web interface, connection metadata, live RPC, authentication, and optional MCP endpoint under one namespace. Hono and Nitro take Web Standard requests directly; Next.js and SvelteKit expose route handlers; Vite and Rsbuild accept its `nodeMiddleware`. The live RPC connection attaches via a shared HTTP server, upgrade events, or a side-car server, advertised through `__connection.json`. See [The Standard Handler](/adapters/initiate).
@@ -70,7 +70,7 @@ import { createDevServer } from 'devframe/adapters/dev'
import { createMcpServer } from 'devframe/adapters/mcp'
import devframe from './devframe'
-// Pick the entry points your package ships:
+/** Pick the entry points your package ships: */
export const runCli = () => createCac(devframe).parse()
export const startServer = () => createDevServer(devframe)
export const vitePlugin = createPluginFromDevframe(devframe)
@@ -84,7 +84,7 @@ One source of truth feeds a visual panel and programmatic consumers. RPC functio
## From one devframe to a hub
-[`@devframes/hub`](/guide/hub) is the composition layer, providing shared concepts — docks, commands, messages, terminals — against a shared context. [`initHub()`](/guide/hub-initiate) puts many devframes behind one Web Standard handler:
+[`@devframes/hub`](/guide/hub) is the composition layer, providing shared concepts (docks, commands, messages, terminals) against a shared context. [`initHub()`](/guide/hub-initiate) puts many devframes behind one Web Standard handler:
```ts
import { createUi } from '@devframes/hub-ui'
@@ -106,7 +106,7 @@ The mounted devframes share one RPC registry, state store, connection, auth gate
## Inheriting the ecosystem
-[Vite DevTools](https://devtools.vite.dev/) is the first flagship hub UI provider, using `initHub()` alongside its own Vite, Rolldown, Vitest, and Oxc tooling. The [framework kits](/frameworks) — [`@devframes/vite`](/frameworks/vite), [`@devframes/nuxt`](/frameworks/nuxt), [`@devframes/next`](/frameworks/next) — add conventions over the same handler. See [Built with Devframe](/guide/built-with).
+[Vite DevTools](https://devtools.vite.dev/) is the first flagship hub UI provider, using `initHub()` alongside its own Vite, Rolldown, Vitest, and Oxc tooling. The [framework kits](/frameworks) ([`@devframes/vite`](/frameworks/vite), [`@devframes/nuxt`](/frameworks/nuxt), [`@devframes/next`](/frameworks/next)) add conventions over the same handler. See [Built with Devframe](/guide/built-with).
## Install
@@ -163,18 +163,18 @@ The CLI adapter serves the SPA at `/`; embedded in a host framework (`vite`, `em
| **[Devframe Definition](/guide/devframe-definition)** | One `defineDevframe` call describes your tool; adapters deploy it anywhere. |
| **[RPC](/guide/rpc)** | Type-safe bidirectional calls on birpc, validated against any Standard Schema validator. `query`, `static`, `action`, `event` types. |
| **[Shared State](/guide/shared-state)** | Observable, patch-synced state surviving reconnects, node side ↔ browser side. |
-| **[JSON-Render](/guide/json-render)** | Opt-in data-driven UI — a serializable view spec, rendered standalone or in a hub dock. |
+| **[JSON-Render](/guide/json-render)** | Opt-in data-driven UI: a serializable view spec, rendered standalone or in a hub dock. |
| **[Diagnostics](/guide/diagnostics)** | Coded warnings/errors via `nostics`, in the host framework's shared lookup. |
| **[Streaming](/guide/streaming)** | One-way (RPC streaming) and two-way (uploads) channel primitives. |
| **[When Clauses](/references/when-clauses)** | VS Code-style conditional expressions for docks, commands, and custom UI. |
-| **[The Standard Handler](/adapters/initiate)** | `initDevframe()` — the Web Standard `Request → Response` boundary. |
+| **[The Standard Handler](/adapters/initiate)** | `initDevframe()`: the Web Standard `Request → Response` boundary. |
| **[Client](/guide/client)** | Browser RPC client (`connectDevframe`), auto-auth, WebSocket / static modes. |
| **[Agent-Native](/guide/agent-native)** | Opt-in exposure of your tool's capabilities to coding agents over MCP. |
## What's next
-- [Tutorial: Build a Server Data Inspector](/guide/tutorial-server-data-inspector) — go from an empty folder to a shippable devtool, one capability at a time
-- [Devframe Definition](/guide/devframe-definition) — `defineDevframe` and `DevframeNodeContext`
-- [The Standard Handler](/adapters/initiate) — mount into any host framework
-- [Adapters](/adapters) — convenience entry points
-- [Hub](/guide/hub) — compose many devframes
+- [Tutorial: Build a Server Data Inspector](/guide/tutorial-server-data-inspector): go from an empty folder to a shippable devtool, one capability at a time
+- [Devframe Definition](/guide/devframe-definition): `defineDevframe` and `DevframeNodeContext`
+- [The Standard Handler](/adapters/initiate): mount into any host framework
+- [Adapters](/adapters): convenience entry points
+- [Hub](/guide/hub): compose many devframes
diff --git a/docs/content/2.adapters/1.initiate.md b/docs/content/2.adapters/1.initiate.md
index 145d45a63..4150487c7 100644
--- a/docs/content/2.adapters/1.initiate.md
+++ b/docs/content/2.adapters/1.initiate.md
@@ -2,10 +2,10 @@
title: 'The Standard Handler'
navigation:
icon: i-lucide-webhook
-description: 'initDevframe() turns a DevframeDefinition into a running devframe whose .handler — a Web Standard (request: Request) => Promise — carries everything a devframe serves (SPA, __connection.json discovery, RPC socket, auth gate, MCP route) under one mount base. Every other serving path — adapters,…'
+description: 'initDevframe() turns a DevframeDefinition into a running devframe whose .handler (a Web Standard (request: Request) => Promise) carries everything a devframe serves (SPA, __connection.json discovery, RPC socket, auth gate, MCP route) under one mount base. Every other serving path (adapters,…'
---
-`initDevframe()` turns a `DevframeDefinition` into a running devframe whose `.handler` — a Web Standard `(request: Request) => Promise` — carries everything a devframe serves (SPA, `__connection.json` discovery, RPC socket, auth gate, MCP route) under one mount base. Every other serving path — [adapters](/adapters), [framework kits](/frameworks), [hub](/guide/hub-initiate) — is assembled from it. Mount it with a catch-all route.
+`initDevframe()` turns a `DevframeDefinition` into a running devframe whose `.handler` (a Web Standard `(request: Request) => Promise`) carries everything a devframe serves (SPA, `__connection.json` discovery, RPC socket, auth gate, MCP route) under one mount base. Every other serving path ([adapters](/adapters), [framework kits](/frameworks), [hub](/guide/hub-initiate)) is assembled from it. Mount it with a catch-all route.
```ts
import { initDevframe } from 'devframe/initiate'
@@ -17,7 +17,7 @@ const devtools = initDevframe(myDevframe, { base: '/__my-tool/' })
// devtools.connectionMeta(), devtools.close()
```
-`base` is required — pass `resolveBasePath(def, 'hosted')` (`def.basePath ?? /__/`) to default it; the running devframe echoes it back as `devtools.base`. `handler`/`nodeMiddleware` await readiness internally. The running devframe binds no port — [the WebSocket binding](#the-websocket-binding) is the host framework's call.
+`base` is required: pass `resolveBasePath(def, 'hosted')` (`def.basePath ?? /__/`) to default it, and the running devframe echoes it back as `devtools.base`. `handler`/`nodeMiddleware` await readiness internally. The running devframe binds no port, so [the WebSocket binding](#the-websocket-binding) is the host framework's call.
## Mount the handler
@@ -92,7 +92,7 @@ import { devtools } from '../devtools'
export default defineEventHandler((event) => {
const { pathname } = new URL(toWebRequest(event).url)
- // `devtools.base` is the normalized mount base — no repeated string.
+ // `devtools.base` is the normalized mount base; no repeated string.
if (pathname.startsWith(devtools.base) || pathname === devtools.base.slice(0, -1))
return devtools.handler(toWebRequest(event))
})
@@ -118,18 +118,18 @@ Host frameworks with dev-time module reloading (Next, Nitro, SvelteKit) re-evalu
Fetch handlers only hand over `Request`s, so the host framework binds the RPC socket. The **local binding** resolves in this order:
-1. **`ws.port`** — a side-car server on that exact port.
-2. **`server`** — share the host framework's `node:http` server; the upgrade binds at `__ws`. No extra ports.
-3. **`ws: { sidecar: true }`** — a side-car server on a free port, for host frameworks whose handlers never see upgrades (Next.js route handlers, Nitro, Rsbuild).
-4. **The host framework's own upgrades** — with none set, the socket waits: `devtools.attach(server)` routes a server's `upgrade` events (returning a detach fn); `devtools.handleUpgrade(req, socket, head)` completes a single one from a listener you own.
+1. **`ws.port`**: a side-car server on that exact port.
+2. **`server`**: share the host framework's `node:http` server; the upgrade binds at `__ws`. No extra ports.
+3. **`ws: { sidecar: true }`**: a side-car server on a free port, for host frameworks whose handlers never see upgrades (Next.js route handlers, Nitro, Rsbuild).
+4. **The host framework's own upgrades.** With none set, the socket waits: `devtools.attach(server)` routes a server's `upgrade` events (returning a detach fn); `devtools.handleUpgrade(req, socket, head)` completes a single one from a listener you own.
-`ws.url` controls the *advertisement* instead — the browser dials it verbatim. Alone, an external WebSocket server owns the transport and its auth (wire the running devframe's `context` via `createContextRpcServer` + a WS transport); alongside a local binding it overrides only the advertisement (the tunnel pattern).
+`ws.url` controls the *advertisement* instead, so the browser dials it verbatim. Alone, an external WebSocket server owns the transport and its auth (wire the running devframe's `context` via `createContextRpcServer` + a WS transport); alongside a local binding it overrides only the advertisement (the tunnel pattern).
`__connection.json` describes the active combination. Asking a configured running devframe to take over the host framework's upgrades reports `DF0055` (a local binding owns the socket) or `DF0056` (`ws.url` handed it off).
## Auth
-The running devframe **gates by default**. The interactive OTP handler wires automatically, printing its code/magic-link banner once the public origin is known — from the `origin` option, or derived from a request whose own origin is loopback or exactly matches an `allowedOrigins` entry. A non-loopback deployment (behind a proxy, on a LAN, on a public host) sets `origin` explicitly so the magic link resolves to the intended address; a raw inbound `Host` header and forwarded headers are never trusted. Pass `auth: false` for single-user localhost, or a `DevframeAuthHandler` for a custom scheme.
+The running devframe **gates by default**. The interactive OTP handler wires automatically, printing its code/magic-link banner once the public origin is known, whether from the `origin` option or derived from a request whose own origin is loopback or exactly matches an `allowedOrigins` entry. A non-loopback deployment (behind a proxy, on a LAN, on a public host) sets `origin` explicitly so the magic link resolves to the intended address; a raw inbound `Host` header and forwarded headers are never trusted. Pass `auth: false` for single-user localhost, or a `DevframeAuthHandler` for a custom scheme.
## Relation to the other adapters
diff --git a/docs/content/2.adapters/2.cac.md b/docs/content/2.adapters/2.cac.md
index e2a179247..249c38bb3 100644
--- a/docs/content/2.adapters/2.cac.md
+++ b/docs/content/2.adapters/2.cac.md
@@ -44,14 +44,14 @@ The SPA serves at `/` standalone, `/__my-tool/` hosted ([Mount paths](/adapters/
| Option | Default | Description |
|--------|---------|-------------|
| `defaultPort` | `9999` (or `def.cli?.port`) | Dev port if `--port` unset. |
-| `configureCli` | — | `(cli: CAC) => void` — add commands/flags. |
-| `onReady` | — | `(info: { origin, port, app }) => void \| Promise` — once listening. |
+| `configureCli` | none | `(cli: CAC) => void` to add commands/flags. |
+| `onReady` | none | `(info: { origin, port, app }) => void \| Promise`, called once listening. |
Returns a `CacHandle`:
```ts
interface CacHandle {
- cli: CAC // raw cac instance — mutate before calling parse()
+ cli: CAC // raw cac instance; mutate before calling parse()
parse: (argv?: string[]) => Promise
}
```
@@ -75,7 +75,7 @@ defineDevframe({
},
},
setup(ctx, { flags }) {
- // `flags` is the parsed cac flag bag — includes both devframe's
+ // `flags` is the parsed cac flag bag, holding both devframe's
// built-ins (`--port`, `--host`, `--open`) and anything declared in
// `cli.configure` or `configureCli`.
},
diff --git a/docs/content/2.adapters/3.dev.md b/docs/content/2.adapters/3.dev.md
index 00144dbc3..4e8234f4c 100644
--- a/docs/content/2.adapters/3.dev.md
+++ b/docs/content/2.adapters/3.dev.md
@@ -16,7 +16,7 @@ const handle = await createDevServer(myDevframe, {
onReady: ({ origin }) => console.log(`Ready at ${origin}`),
})
-// graceful shutdown — SIGINT, hot reload, test teardown
+// graceful shutdown: SIGINT, hot reload, test teardown
process.on('SIGINT', () => handle.close().then(() => process.exit(0)))
```
@@ -31,8 +31,8 @@ Returns a `StartedServer`: origin, port, h3 app, WS server, RPC group, `close()`
| `basePath` | `resolveBasePath(def, 'standalone')` | Mount override. |
| `app` | fresh h3 app | Mount onto. |
| `openBrowser` | resolves from `flags.open` / `def.cli?.open` | `false` off; string opens a path. |
-| `ws` | `def.cli?.ws` | RPC WebSocket — see below. |
-| `onReady` | — | WS-bind callback. |
+| `ws` | `def.cli?.ws` | RPC WebSocket; see below. |
+| `onReady` | none | WS-bind callback. |
## WebSocket endpoint
diff --git a/docs/content/2.adapters/5.vite.md b/docs/content/2.adapters/5.vite.md
index 0252866db..99ef2aca4 100644
--- a/docs/content/2.adapters/5.vite.md
+++ b/docs/content/2.adapters/5.vite.md
@@ -23,4 +23,4 @@ The returned object has the shape `{ name, devtools: { setup, capabilities } }`.
| `name` | `devframe:` | Plugin name. |
| `base` | `def.basePath ?? /.${id}/` | Mount path override. |
| `dock` | `{}` | Overrides for the iframe dock entry (category, icon, when). |
-| `setup` | — | Setup hook run only in the Vite host; receives the kit-augmented context. |
+| `setup` | none | Setup hook run only in the Vite host; receives the kit-augmented context. |
diff --git a/docs/content/2.adapters/6.embedded.md b/docs/content/2.adapters/6.embedded.md
index 12f826eca..59bb90f1a 100644
--- a/docs/content/2.adapters/6.embedded.md
+++ b/docs/content/2.adapters/6.embedded.md
@@ -2,10 +2,10 @@
title: 'Embedded'
navigation:
icon: i-lucide-box
-description: 'Register a devframe into an already-running context at runtime — dynamic, post-startup registration (unlike vite''s plugin-scan). Inherits the hosted /__/ default.'
+description: 'Register a devframe into an already-running context at runtime: dynamic, post-startup registration (unlike vite''s plugin-scan). Inherits the hosted /__/ default.'
---
-Register a devframe into an already-running context at runtime — dynamic, post-startup registration (unlike [`vite`](/adapters/vite)'s plugin-scan). Inherits the hosted `/__/` default.
+Register a devframe into an already-running context at runtime: dynamic, post-startup registration (unlike [`vite`](/adapters/vite)'s plugin-scan). Inherits the hosted `/__/` default.
```ts
import { createEmbedded } from 'devframe/adapters/embedded'
diff --git a/docs/content/2.adapters/7.mcp.md b/docs/content/2.adapters/7.mcp.md
index 17c2edfdf..454d904de 100644
--- a/docs/content/2.adapters/7.mcp.md
+++ b/docs/content/2.adapters/7.mcp.md
@@ -24,7 +24,7 @@ The dev server exposes the same MCP API over HTTP, live. Enable with `cli.mcp`:
import { defineDevframe } from 'devframe'
export default defineDevframe({
- // …
+ /** … */
cli: {
mcp: true,
},
@@ -33,7 +33,7 @@ export default defineDevframe({
The endpoint speaks Streamable-HTTP at `/__mcp` (`/__/__mcp` under a host framework), sharing its origin/port. `--mcp` / `--no-mcp` override; `__connection.json` advertises it.
-The endpoint is **stateless**: it serves the [2026-07-28 revision](https://modelcontextprotocol.io/specification/2026-07-28) per request through the SDK's `createMcpHandler`, building a fresh MCP server for each request — every HTTP request stands alone, with no `Mcp-Session-Id` to correlate. 2025-era clients are still served through the SDK's stateless legacy path. An origin gate requires `Origin` be loopback (or allow-listed) and rejects `Origin`-less requests. Widen for a tunnel/LAN origin with `cli: { mcp: { allowedOrigins: ['https://tunnel.example.com'] } }`.
+The endpoint is **stateless**: it serves the [2026-07-28 revision](https://modelcontextprotocol.io/specification/2026-07-28) per request through the SDK's `createMcpHandler`, building a fresh MCP server for each request, so every HTTP request stands alone, with no `Mcp-Session-Id` to correlate. 2025-era clients are still served through the SDK's stateless legacy path. An origin gate requires `Origin` be loopback (or allow-listed) and rejects `Origin`-less requests. Widen for a tunnel/LAN origin with `cli: { mcp: { allowedOrigins: ['https://tunnel.example.com'] } }`.
### Hosted bridges
@@ -49,7 +49,7 @@ createDevframeNextHandler(myDevframe, { mcp: true })
## Custom host frameworks
-`createMcpFetchHandler(ctx, options)` returns the endpoint as a `Request → Response` handler plus a `dispose()` — mount on any fetch server.
+`createMcpFetchHandler(ctx, options)` returns the endpoint as a `Request → Response` handler plus a `dispose()`; mount it on any fetch server.
```ts
import { createMcpFetchHandler } from 'devframe/adapters/mcp'
@@ -74,10 +74,10 @@ The `devframe` bin ships an MCP **connector** ([next-devtools-mcp](https://githu
}
```
-Two gateway tools (`devframe:connect:*` ids — see [tool ids and wire names](/guide/agent-native#tool-ids-and-wire-names)):
+Two gateway tools (`devframe:connect:*` ids; see [tool ids and wire names](/guide/agent-native#tool-ids-and-wire-names)):
-- **`devframe_connect_list-instances`** — list running dev servers and their MCP tools.
-- **`devframe_connect_call-tool`** — invoke one tool on a running devframe (`{ port, tool, args }`) over Streamable-HTTP.
+- **`devframe_connect_list-instances`**: list running dev servers and their MCP tools.
+- **`devframe_connect_call-tool`**: invoke one tool on a running devframe (`{ port, tool, args }`) over Streamable-HTTP.
Discovery reads the **instance registry**: every `createDevServer` writes `~/.devframe/instances/-.json`, dialed with a loopback origin. In-process host frameworks register via `registerDevframeInstance` (`devframe/node`). `--port ` probes a port; `DEVFRAME_INSTANCES_DIR` relocates the registry, `DEVFRAME_DISABLE_INSTANCE_REGISTRY=1` opts out.
diff --git a/docs/content/2.adapters/index.md b/docs/content/2.adapters/index.md
index 8b32d59f8..15748c657 100644
--- a/docs/content/2.adapters/index.md
+++ b/docs/content/2.adapters/index.md
@@ -2,10 +2,10 @@
title: 'Adapters'
navigation:
icon: i-lucide-plug
-description: 'The lowest-level path is the standard handler, initDevframe(def, { base }) — a Web Standard (request: Request) => Promise for any catch-all route. Every path below builds on it.'
+description: 'The lowest-level path is the standard handler, initDevframe(def, { base }): a Web Standard (request: Request) => Promise for any catch-all route. Every path below builds on it.'
---
-The lowest-level path is [the standard handler](/adapters/initiate), `initDevframe(def, { base })` — a Web Standard `(request: Request) => Promise` for any catch-all route. Every path below builds on it.
+The lowest-level path is [the standard handler](/adapters/initiate), `initDevframe(def, { base })`: a Web Standard `(request: Request) => Promise` for any catch-all route. Every path below builds on it.
Adapters wrap it as `createXxx(def, options?)` at `devframe/adapters/`. `cac` and `mcp` need an optional peer ([`cac`](https://github.com/cacjs/cac), [`@modelcontextprotocol/server`](https://github.com/modelcontextprotocol/typescript-sdk)).
@@ -40,4 +40,4 @@ defineDevframe({
})
```
-The SPA discovers its base at runtime — see [Client](/guide/client#runtime-basepath-discovery).
+The SPA discovers its base at runtime; see [Client](/guide/client#runtime-basepath-discovery).
diff --git a/docs/content/3.frameworks/1.vite.md b/docs/content/3.frameworks/1.vite.md
index 8b57bb4cf..f2f32801e 100644
--- a/docs/content/3.frameworks/1.vite.md
+++ b/docs/content/3.frameworks/1.vite.md
@@ -15,15 +15,15 @@ import { defineConfig } from 'vite'
import myDevframe from './my-tool'
export default defineConfig({
- // Statically mounts the built SPA at `/__/` — no RPC server:
+ /** Statically mounts the built SPA at `/__/`, with no RPC server: */
plugins: [devframeVitePlugin(myDevframe)],
- // Or bridge the RPC/WS backend into this dev server instead — the
+ // Or bridge the RPC/WS backend into this dev server instead, so the
// user app owns the SPA:
// plugins: [devframeViteBridge(myDevframe)],
})
```
-## `devframeVitePlugin` — static mount
+## `devframeVitePlugin`: static mount
Mounts `def.clientAssets` at `options.base` (`/__/` default) with SPA fallback. `clientAssets` accepts a local directory or [remote assets](/guide/client-assets).
@@ -31,7 +31,7 @@ Mounts `def.clientAssets` at `options.base` (`/__/` default) with SPA fallba
|--------|---------|-------------|
| `base` | `def.basePath ?? '/__/'` | Mount path. |
-## `devframeViteBridge` — RPC bridge
+## `devframeViteBridge`: RPC bridge
Devframe spawns a separate RPC + WS server and registers Vite middleware at `__connection.json`. To share Vite's port, pass its HTTP server to [`initDevframe`](/adapters/initiate) / `initHub` via `server`.
@@ -40,11 +40,11 @@ Devframe spawns a separate RPC + WS server and registers Vite middleware at `/'` | Mount path. |
| `port` | share Vite's HTTP server | Pin a side-car RPC port instead. |
| `host` | `def.cli?.host ?? 'localhost'` | Bind host for a pinned side-car. |
-| `flags` | — | To `def.setup(ctx, { flags })`. |
+| `flags` | none | To `def.setup(ctx, { flags })`. |
| `auth` | gated (interactive OTP) | `false` to opt out, or a `DevframeAuthHandler` for a custom scheme. |
| `mcp` | `def.cli?.mcp` | `true` or `McpRouteOptions` to expose the MCP route at `__mcp`. |
-## `devframeVite` — convenience wrapper
+## `devframeVite`: convenience wrapper
`devframeVite(def, { bridge, ...opts })` forwards to `devframeViteBridge` when `bridge: true`, else `devframeVitePlugin`; use them directly when a devframe needs both.
diff --git a/docs/content/3.frameworks/2.nuxt.md b/docs/content/3.frameworks/2.nuxt.md
index 453d67aad..77fcce46a 100644
--- a/docs/content/3.frameworks/2.nuxt.md
+++ b/docs/content/3.frameworks/2.nuxt.md
@@ -99,7 +99,7 @@ my-tool/
├── bin.mjs # createCac(myDevframe).parse()
├── src/
│ ├── my-tool.ts # defineDevframe + setup(ctx) { ctx.rpc.register(...) }
-│ └── app/ # Nuxt SPA — uses `@devframes/nuxt`
+│ └── app/ # Nuxt SPA, uses `@devframes/nuxt`
└── dist/
├── cli.mjs # bundled Node entry
└── public/ # Nuxt build output, pointed at by clientAssets
@@ -114,7 +114,7 @@ const rpc = await connectDevframe({ baseURL: config.public.devframe.baseURL })
return { provide: { rpc } }
```
-At runtime the SPA fetches `./__connection.json` and branches on `backend` — `websocket` in dev, `static` from a `createBuild` snapshot.
+At runtime the SPA fetches `./__connection.json` and branches on `backend`: `websocket` in dev, `static` from a `createBuild` snapshot.
## Mounting a hub
@@ -131,5 +131,5 @@ Nuxt DevTools (`@nuxt/devtools`) integrates the same protocol natively; this mod
## See also
- [Standalone CLI recipe](/guide/standalone-cli)
-- [Client](/guide/client) — `connectDevframe` reference
+- [Client](/guide/client): `connectDevframe` reference
- [Adapters](/adapters)
diff --git a/docs/content/3.frameworks/3.next.md b/docs/content/3.frameworks/3.next.md
index 23f11e436..2bbad6eb4 100644
--- a/docs/content/3.frameworks/3.next.md
+++ b/docs/content/3.frameworks/3.next.md
@@ -6,7 +6,7 @@ description: '@devframes/next hosts devframes from a Next.js App Router app via
---
> [!WARNING]
-> Experimental. `@devframes/next`'s API is still settling — expect changes before a stable release.
+> Experimental. `@devframes/next`'s API is still settling; expect changes before a stable release.
`@devframes/next` hosts devframes from a Next.js App Router app via a route handler: one `fetch` handler serves each SPA and its `__connection.json` via [`serveStaticHandler`](/adapters/dev).
@@ -46,7 +46,7 @@ export const GET = handler.fetch
| `base` | `def.basePath ?? '/__/'` | SPA mount path. |
| `host` | `def.cli?.host ?? 'localhost'` | Side-car bind host. |
| `port` | from `def.cli?.port` | Side-car port. |
-| `flags` | — | Passed to `def.setup(ctx, { flags })`. |
+| `flags` | none | Passed to `def.setup(ctx, { flags })`. |
| `auth` | `false` | `true` for the OTP gate, or a handler. |
| `key` | `@devframes/next::` | `globalThis` memoization key. |
@@ -97,9 +97,9 @@ import { useRpc, useRpcStatus } from '@devframes/next/single/client'
export function Panel() {
const rpc = useRpc()?.scope('my-tool:')
- const { status, error } = useRpcStatus()
+ const { error } = useRpcStatus()
if (!rpc)
- return
// rpc.rpc.call('get-payload'), rpc.sharedState, …
}
```
diff --git a/docs/content/3.frameworks/index.md b/docs/content/3.frameworks/index.md
index bd1de2fdd..bd0764a46 100644
--- a/docs/content/3.frameworks/index.md
+++ b/docs/content/3.frameworks/index.md
@@ -2,10 +2,10 @@
title: 'Frameworks'
navigation:
icon: i-lucide-layers
-description: 'The framework kits — @devframes/vite, @devframes/nuxt, @devframes/next — integrate devframe with a meta-framework''s dev server. Two subpaths:'
+description: 'The framework kits (@devframes/vite, @devframes/nuxt, @devframes/next) integrate devframe with a meta-framework''s dev server. Two subpaths:'
---
-The framework kits — [`@devframes/vite`](/frameworks/vite), [`@devframes/nuxt`](/frameworks/nuxt), [`@devframes/next`](/frameworks/next) — integrate devframe with a meta-framework's dev server. Two **subpaths**:
+The framework kits ([`@devframes/vite`](/frameworks/vite), [`@devframes/nuxt`](/frameworks/nuxt), [`@devframes/next`](/frameworks/next)) integrate devframe with a meta-framework's dev server. Two **subpaths**:
| Scope | Subpath | You are… |
|-------|---------|----------|
diff --git a/docs/content/5.add-ons/1.devframes/1.data-inspector.md b/docs/content/5.add-ons/1.devframes/1.data-inspector.md
index 745aee13f..d4953d625 100644
--- a/docs/content/5.add-ons/1.devframes/1.data-inspector.md
+++ b/docs/content/5.add-ons/1.devframes/1.data-inspector.md
@@ -19,17 +19,17 @@ _Query data with advanced Jora syntax_
## What it does
-- **Query workbench** — a CodeMirror jora editor with server-computed autocomplete; queries auto-run as you type, [state in the URL hash](#deep-linking).
-- **Auto rerun** — optional poller (`auto rerun every N seconds`).
-- **Result viewer** — normalizes to strict JSON (circulars → `$ref`; Maps, Sets, class instances, functions, Dates get type badges) plus per-query stats.
-- **Expansion, shape & filters** — deep nodes fetch lazily via `load deeper`; a shape panel shows a one-level skeleton; filters drop functions and `_`/`$` properties.
-- **Saved queries** — recipes (`query` + title/description + filters) in the **workspace scope** (committable) and the **project scope** (per-checkout).
+- **Query workbench**: a CodeMirror jora editor with server-computed autocomplete; queries auto-run as you type, [state in the URL hash](#deep-linking).
+- **Auto rerun**: optional poller (`auto rerun every N seconds`).
+- **Result viewer**: normalizes to strict JSON (circulars → `$ref`; Maps, Sets, class instances, functions, Dates get type badges) plus per-query stats.
+- **Expansion, shape & filters**: deep nodes fetch lazily via `load deeper`; a shape panel shows a one-level skeleton; filters drop functions and `_`/`$` properties.
+- **Saved queries**: recipes (`query` + title/description + filters) in the **workspace scope** (committable) and the **project scope** (per-checkout).
A built-in **example source** registers by default; opt out with `exampleSource: false` (`--no-example`; `DEVFRAME_DATA_INSPECTOR_EXAMPLE=0` when injected).
## Providing data sources
-The registry is **process-global** — register anywhere, before or after mount.
+The registry is **process-global**; register anywhere, before or after mount.
```ts
import { registerDataSource } from '@devframes/plugin-data-inspector/registry'
@@ -56,7 +56,7 @@ registerDataSource({
Workbench state lives in the URL hash (`#source=&query=`, filters); the handshake token rides the query string (`?devframe_auth_token=`), scrubbed on read.
-In a hub, another dock jumps to a source via [dock activation](/guide/deep-linking#focusing-a-dock-inside-a-hub) — `rpc.call('hub:docks:activate', { dockId: 'devframes:plugin:data-inspector', params: { sourceId } })` (waits for registration).
+In a hub, another dock jumps to a source via [dock activation](/guide/deep-linking#focusing-a-dock-inside-a-hub): `rpc.call('hub:docks:activate', { dockId: 'devframes:plugin:data-inspector', params: { sourceId } })` (waits for registration).
## Standalone
diff --git a/docs/content/5.add-ons/1.devframes/2.inspect.md b/docs/content/5.add-ons/1.devframes/2.inspect.md
index b8f5469d0..c6befcc7a 100644
--- a/docs/content/5.add-ons/1.devframes/2.inspect.md
+++ b/docs/content/5.add-ons/1.devframes/2.inspect.md
@@ -2,10 +2,10 @@
title: 'Devframe Inspector'
navigation:
icon: i-ph:stethoscope-duotone
-description: 'A self-inspector for any devframe connection, including the host framework''s — a Vue SPA.'
+description: 'A self-inspector for any devframe connection, including the host framework''s: a Vue SPA.'
---
-A self-inspector for any devframe connection, including the host framework's — a **Vue** SPA.
+A self-inspector for any devframe connection, including the host framework's: a **Vue** SPA.
Package: `@devframes/plugin-inspect` · framework: **Vue + Vite**
@@ -23,10 +23,10 @@ _History panels_
## What it does
-- **Functions** — type, flags, JSON Schema, agent exposure; read-only `query` / `static` invokable inline.
-- **State** — shared-state keys in a live JSON tree that flashes changes.
-- **Agent** — tools and resources for agents.
-- **History** — a timeline of RPC calls and shared-state updates.
+- **Functions**: type, flags, JSON Schema, agent exposure; read-only `query` / `static` invokable inline.
+- **State**: shared-state keys in a live JSON tree that flashes changes.
+- **Agent**: tools and resources for agents.
+- **History**: a timeline of RPC calls and shared-state updates.
## Standalone
@@ -86,7 +86,7 @@ All functions are namespaced `devframes:plugin:inspect:*`:
| `list-functions` | `query` (snapshot) | RPC functions with metadata. |
| `invoke` | `action` | Invokes a read-only `query` / `static`; refuses `action`/`event`. |
| `list-state-keys` | `query` (snapshot) | Shared-state keys. |
-| `describe-agent` | `query` (snapshot) | Agent manifest — tools and resources. |
+| `describe-agent` | `query` (snapshot) | Agent manifest: tools and resources. |
## Source
diff --git a/docs/content/5.add-ons/1.devframes/4.a11y.md b/docs/content/5.add-ons/1.devframes/4.a11y.md
index 0875e9255..30e425284 100644
--- a/docs/content/5.add-ons/1.devframes/4.a11y.md
+++ b/docs/content/5.add-ons/1.devframes/4.a11y.md
@@ -27,7 +27,7 @@ Three pieces, two browser-side:
| **Panel** | the devtools iframe | Solid SPA: lists violations, highlights on hover |
| **Node side** | the Node process | the `get-config` RPC (impact taxonomy), baked in static builds |
-The page script and the panel talk over the [in-page channel](/guide/in-page-channel), so the loop works live or static. The page script is the author-provided bridge (the panel has no reach into the user app's DOM) — one module script scans, reports, and highlights.
+The page script and the panel talk over the [in-page channel](/guide/in-page-channel), so the loop works live or static. The page script is the author-provided bridge (the panel has no reach into the user app's DOM): one module script scans, reports, and highlights.
## In a hub
@@ -37,9 +37,9 @@ The definition declares the page script as its dock [client script](/guide/clien
initHub({ devframes: ['@devframes/plugin-a11y'] })
```
-The hub serves the bundle same-origin and a client runtime imports it into the host page. Each scan also mirrors into the hub's messages feed — a summary plus one per rule.
+The hub serves the bundle same-origin and a client runtime imports it into the host page. Each scan also mirrors into the hub's messages feed: a summary plus one per rule.
-A host can also mount the module itself — e.g. a Vite host via `/@fs/`:
+A host can also mount the module itself, for example a Vite host via `/@fs/`:
```ts
import createA11yDevframe, { a11yPageScriptBundlePath } from '@devframes/plugin-a11y'
diff --git a/docs/content/5.add-ons/1.devframes/5.git.md b/docs/content/5.add-ons/1.devframes/5.git.md
index 865c0fc10..c3b806073 100644
--- a/docs/content/5.add-ons/1.devframes/5.git.md
+++ b/docs/content/5.add-ons/1.devframes/5.git.md
@@ -2,10 +2,10 @@
title: 'Git'
navigation:
icon: i-ph:git-branch-duotone
-description: 'A repository dashboard — a Next.js + shadcn/ui SPA that shells out to git. The same bundle runs live or static.'
+description: 'A repository dashboard: a Next.js + shadcn/ui SPA that shells out to git. The same bundle runs live or static.'
---
-A repository dashboard — a **Next.js + shadcn/ui** SPA that shells out to `git`. The same bundle runs live or static.
+A repository dashboard: a **Next.js + shadcn/ui** SPA that shells out to `git`. The same bundle runs live or static.
Package: `@devframes/plugin-git`
@@ -44,7 +44,7 @@ await createCac(createGitDevframe({ repoRoot: process.cwd() })).parse()
## RPC
-Namespaced `devframes:plugin:git:*`. Reads — `status`, `log` (+ parent hashes), `branches` (ahead / behind), `diff` (unified patch) — are `query` (`snapshot: true`): live in dev, baked static, `isRepo: false` outside a repo. Write `stage` / `unstage` / `commit` are write-mode `action`s.
+Namespaced `devframes:plugin:git:*`. Reads are `query` (`snapshot: true`): `status`, `log` (+ parent hashes), `branches` (ahead / behind), and `diff` (unified patch), live in dev, baked static, `isRepo: false` outside a repo. Write `stage` / `unstage` / `commit` are write-mode `action`s.
For a repo capability shared across devframes rather than this dashboard's own RPC, see the [`@devframes/service-git`](/add-ons/services/git) wire service.
diff --git a/docs/content/5.add-ons/1.devframes/6.terminals.md b/docs/content/5.add-ons/1.devframes/6.terminals.md
index 3abe8e5b9..0fbe36653 100644
--- a/docs/content/5.add-ons/1.devframes/6.terminals.md
+++ b/docs/content/5.add-ons/1.devframes/6.terminals.md
@@ -2,10 +2,10 @@
title: 'Terminals'
navigation:
icon: i-ph:terminal-window-duotone
-description: 'A terminal panel — a Svelte SPA on xterm.js.'
+description: 'A terminal panel: a Svelte SPA on xterm.js.'
---
-A terminal panel — a **Svelte** SPA on [xterm.js](https://xtermjs.org/).
+A terminal panel: a **Svelte** SPA on [xterm.js](https://xtermjs.org/).
Package: `@devframes/plugin-terminals`
@@ -15,9 +15,9 @@ _Interactive and read-only sessions in the browser_
## What it does
-- **Read-only output** — via devframe's [streaming channels](/guide/streaming).
-- **Interactive shells** — PTY-backed terminal sessions you can type into, including full-screen TUI programs.
-- **Presets** — named commands launchable in one click.
+- **Read-only output**: via devframe's [streaming channels](/guide/streaming).
+- **Interactive shells**: PTY-backed terminal sessions you can type into, including full-screen TUI programs.
+- **Presets**: named commands launchable in one click.
Interactive shells use [`zigpty`](https://github.com/pithings/zigpty)'s prebuilt native bindings (Linux/macOS/Windows, x64/arm64), falling back to pipe-based emulation where they can't load.
diff --git a/docs/content/5.add-ons/1.devframes/7.code-server.md b/docs/content/5.add-ons/1.devframes/7.code-server.md
index 61973bb2e..1b147cb54 100644
--- a/docs/content/5.add-ons/1.devframes/7.code-server.md
+++ b/docs/content/5.add-ons/1.devframes/7.code-server.md
@@ -20,9 +20,9 @@ _The embedded editor in the browser_
## What it does
-- **Detection** — probes with `--version`; if absent, shows install info.
-- **Launch** — a managed child process on a free port, readiness-probed.
-- **Auto-auth** — fresh auth per launch; the editor opens signed in.
+- **Detection**: probes with `--version`; if absent, shows install info.
+- **Launch**: a managed child process on a free port, readiness-probed.
+- **Auto-auth**: fresh auth per launch; the editor opens signed in.
## Backends
diff --git a/docs/content/5.add-ons/1.devframes/index.md b/docs/content/5.add-ons/1.devframes/index.md
index 41689f9bd..e15cd7c10 100644
--- a/docs/content/5.add-ons/1.devframes/index.md
+++ b/docs/content/5.add-ons/1.devframes/index.md
@@ -20,7 +20,7 @@ Ready-to-run built-in example devframes (`@devframes/plugin-*`). Compose your ow
## One RPC client, any framework
-Each devframe picks its own UI framework yet shares one node-side API — [RPC](/guide/rpc), [shared state](/guide/shared-state), and `connectDevframe`.
+Each devframe picks its own UI framework yet shares one node-side API: [RPC](/guide/rpc), [shared state](/guide/shared-state), and `connectDevframe`.
## Running a built-in devframe
diff --git a/docs/content/5.add-ons/2.services/1.open.md b/docs/content/5.add-ons/2.services/1.open.md
index 8815d8014..acb493780 100644
--- a/docs/content/5.add-ons/2.services/1.open.md
+++ b/docs/content/5.add-ons/2.services/1.open.md
@@ -24,7 +24,7 @@ A hub installs a shared instance with `initHub({ services: [createOpenService(op
## Options
-`OpenServiceOptions` — later installer wins on `editor`; `roots` union-merged.
+`OpenServiceOptions`: later installer wins on `editor`; `roots` union-merged.
| Option | Type | Description |
|--------|------|-------------|
diff --git a/docs/content/5.add-ons/2.services/2.git.md b/docs/content/5.add-ons/2.services/2.git.md
index e04d487c7..5a73b2f1a 100644
--- a/docs/content/5.add-ons/2.services/2.git.md
+++ b/docs/content/5.add-ons/2.services/2.git.md
@@ -24,7 +24,7 @@ A hub installs a shared instance with `initHub({ services: [createGitService(opt
## Options
-`GitServiceOptions` — `cwd` merges as a scalar (later installer wins).
+`GitServiceOptions`: `cwd` merges as a scalar (later installer wins).
| Option | Type | Description |
|--------|------|-------------|
@@ -32,17 +32,17 @@ A hub installs a shared instance with `initHub({ services: [createGitService(opt
## RPC functions
-Registered under `devframes:service:git:*`. Reads are `query`; writes are `action`. Write ops are **always exposed** — authorization is the host's connection-trust boundary. The service defines no `dump`/`snapshot`; a devframe bakes what it needs via `snapshotRpc`.
+Registered under `devframes:service:git:*`. Reads are `query`; writes are `action`. Write ops are **always exposed**; authorization is the host's connection-trust boundary. The service defines no `dump`/`snapshot`; a devframe bakes what it needs via `snapshotRpc`.
| Function | Type | Args | Returns |
|----------|------|------|---------|
-| `status` | `query` | — | Working-tree status: branch, ahead/behind, staged/unstaged/untracked files. |
+| `status` | `query` | none | Working-tree status: branch, ahead/behind, staged/unstaged/untracked files. |
| `log` | `query` | `{ limit?, skip?, ref?, paths? }` | Commit history, newest first (paginated). |
| `show` | `query` | `{ hash, patch? }` | Full detail of one commit: metadata, files, unified patch. |
| `readFile` | `query` | `{ path, ref? }` | Contents of a file at a commit-ish (default HEAD). |
| `diff` | `query` | `{ path?, staged? }` | Unified diff of uncommitted changes. |
-| `branches` | `query` | — | Local branches with tracking state and the current branch. |
-| `tags` | `query` | — | Tags (newest first) with target SHA, date, and subject. |
+| `branches` | `query` | none | Local branches with tracking state and the current branch. |
+| `tags` | `query` | none | Tags (newest first) with target SHA, date, and subject. |
| `stage` | `action` | `{ … }` | Stage paths; returns the new status. |
| `unstage` | `action` | `{ … }` | Unstage paths; returns the new status. |
| `commit` | `action` | `{ … }` | Create a commit; returns the result. |
@@ -51,7 +51,7 @@ The read `query` functions carry agent metadata, so they surface as tools to a [
## Node API
-`ctx.services.get('@devframes/service-git')` returns the in-process `GitServiceApi` — the same operations without an RPC hop.
+`ctx.services.get('@devframes/service-git')` returns the in-process `GitServiceApi`: the same operations without an RPC hop.
## On the RPC client
@@ -61,6 +61,7 @@ const rpc = await connectDevframe()
if (rpc.services.has('@devframes/service-git')) {
const git = rpc.services.get('@devframes/service-git')!
const status = await git.rpc.call('status')
+ console.log(status)
}
```
diff --git a/docs/content/5.add-ons/2.services/3.shiki.md b/docs/content/5.add-ons/2.services/3.shiki.md
index 73245a445..5bdd114a8 100644
--- a/docs/content/5.add-ons/2.services/3.shiki.md
+++ b/docs/content/5.add-ons/2.services/3.shiki.md
@@ -24,7 +24,7 @@ A hub installs a shared instance with `initHub({ services: [createShikiService(o
## Options
-`ShikiServiceOptions` — later installer wins on `themes` (deep-merged per key); `langs` union-merged.
+`ShikiServiceOptions`: later installer wins on `themes` (deep-merged per key); `langs` union-merged.
| Option | Type | Description |
|--------|------|-------------|
@@ -37,7 +37,7 @@ Registered under `devframes:service:shiki:*`, all `query` and `cacheable`. Each
| Function | Returns |
|----------|---------|
-| `highlight` | `{ html }` — dual-theme HTML (light values inline, dark via `--shiki-dark` vars). |
+| `highlight` | `{ html }`: dual-theme HTML (light values inline, dark via `--shiki-dark` vars). |
| `code-to-hast` | A HAST tree, for surfaces that render their own DOM. |
| `code-to-tokens` | Themed tokens, for line-oriented renderers (e.g. diff views). |
@@ -53,6 +53,7 @@ const rpc = await connectDevframe()
if (rpc.services.has('@devframes/service-shiki')) {
const shiki = rpc.services.get('@devframes/service-shiki')!
const { html } = await shiki.rpc.call('highlight', { code, lang: 'ts' })
+ element.innerHTML = html
}
```
diff --git a/docs/content/5.add-ons/2.services/index.md b/docs/content/5.add-ons/2.services/index.md
index 3c15cecfd..8f2d2a0e7 100644
--- a/docs/content/5.add-ons/2.services/index.md
+++ b/docs/content/5.add-ons/2.services/index.md
@@ -5,7 +5,7 @@ navigation:
description: 'Built-in wire services (@devframes/service-*): one node-side capability installed once per host and consumed by every devframe and RPC client, without re-implementing or re-bundling it.'
---
-Built-in [wire services](/guide/services#wire-services) (`@devframes/service-*`) — one node-side capability installed once per host and consumed by every devframe and RPC client, without re-implementing or re-bundling it. See [Cross-Devframe Services](/guide/services) for the mechanism and the [Node-Side API reference](/references/node-api#devframeserviceshost) for the host API.
+Built-in [wire services](/guide/services#wire-services) (`@devframes/service-*`) each package one node-side capability, installed once per host and consumed by every devframe and RPC client, without re-implementing or re-bundling it. See [Cross-Devframe Services](/guide/services) for the mechanism and the [Node-Side API reference](/references/node-api#devframeserviceshost) for the host API.
| Service | Scope | RPC functions | What it does |
|---------|-------|---------------|--------------|
@@ -15,7 +15,7 @@ Built-in [wire services](/guide/services#wire-services) (`@devframes/service-*`)
## Installing a service
-Services are **declarative** — a devframe lists what it consumes on its definition; a hub lists shared ones on `initHub`:
+Services are **declarative**: a devframe lists what it consumes on its definition; a hub lists shared ones on `initHub`:
```ts
defineDevframe({
diff --git a/docs/content/5.add-ons/index.md b/docs/content/5.add-ons/index.md
index 0be441f5f..e2f406ea4 100644
--- a/docs/content/5.add-ons/index.md
+++ b/docs/content/5.add-ons/index.md
@@ -7,12 +7,12 @@ description: 'Ready-to-run packages built on Devframe: built-in devframes you ca
Ready-to-run packages built on Devframe, in two families:
-- **[Devframes](/add-ons/devframes)** — complete built-in devtools (`@devframes/plugin-*`). Run one standalone, compose several into your own DevTools, or read one as a reference for building your own.
-- **[Services](/add-ons/services)** — wire services (`@devframes/service-*`): one node-side capability installed once per host and consumed by every devframe and RPC client, without re-bundling it.
+- **[Devframes](/add-ons/devframes)** are complete built-in devtools (`@devframes/plugin-*`). Run one standalone, compose several into your own DevTools, or read one as a reference for building your own.
+- **[Services](/add-ons/services)** are wire services (`@devframes/service-*`): one node-side capability installed once per host and consumed by every devframe and RPC client, without re-bundling it.
## Devframes
-Complete tools, each picking its own UI framework yet sharing one node-side API — [RPC](/guide/rpc), [shared state](/guide/shared-state), and `connectDevframe`.
+Complete tools, each picking its own UI framework yet sharing one node-side API: [RPC](/guide/rpc), [shared state](/guide/shared-state), and `connectDevframe`.
| Devframe | UI framework | What it does |
|--------|--------------|--------------|
@@ -27,7 +27,7 @@ Complete tools, each picking its own UI framework yet sharing one node-side API
## Services
-Shared node-side capabilities other devframes install and consume — see [Cross-Devframe Services](/guide/services) for the mechanism, and the [Node-Side API reference](/references/node-api#devframeserviceshost) for the host API.
+Shared node-side capabilities other devframes install and consume; see [Cross-Devframe Services](/guide/services) for the mechanism, and the [Node-Side API reference](/references/node-api#devframeserviceshost) for the host API.
| Service | Scope | What it does |
|---------|-------|--------------|
diff --git a/docs/content/6.errors/DF0006.md b/docs/content/6.errors/DF0006.md
index 055efc355..e3f21361d 100644
--- a/docs/content/6.errors/DF0006.md
+++ b/docs/content/6.errors/DF0006.md
@@ -17,4 +17,4 @@ Register the function with `ctx.rpc.register(defineRpcFunction({ name }))` befor
## Source
-- [`packages/devframe/src/node/host-functions.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/node/host-functions.ts) — `RpcFunctionsHost.invokeLocal()` throws `DF0006` when the requested method has not been registered on this host.
+- [`packages/devframe/src/node/host-functions.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/node/host-functions.ts): `RpcFunctionsHost.invokeLocal()` throws `DF0006` when the requested method has not been registered on this host.
diff --git a/docs/content/6.errors/DF0007.md b/docs/content/6.errors/DF0007.md
index 5259bffdb..b963c5bd0 100644
--- a/docs/content/6.errors/DF0007.md
+++ b/docs/content/6.errors/DF0007.md
@@ -17,4 +17,4 @@ Only call `getCurrentRpcSession()` from RPC handlers executed by the server. Rep
## Source
-- [`packages/devframe/src/node/host-functions.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/node/host-functions.ts) — `getCurrentRpcSession()` throws `DF0007` when called outside the RPC dispatch async context.
+- [`packages/devframe/src/node/host-functions.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/node/host-functions.ts): `getCurrentRpcSession()` throws `DF0007` when called outside the RPC dispatch async context.
diff --git a/docs/content/6.errors/DF0008.md b/docs/content/6.errors/DF0008.md
index b1bf73e96..26207660f 100644
--- a/docs/content/6.errors/DF0008.md
+++ b/docs/content/6.errors/DF0008.md
@@ -17,4 +17,4 @@ Verify the `distDir` path resolves correctly (run your SPA build first, and chec
## Source
-- [`packages/devframe/src/node/host-views.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/node/host-views.ts) — `DevframeViewHost.hostStatic()` throws `DF0008` when the resolved `distDir` does not exist on disk.
+- [`packages/devframe/src/node/host-views.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/node/host-views.ts): `DevframeViewHost.hostStatic()` throws `DF0008` when the resolved `distDir` does not exist on disk.
diff --git a/docs/content/6.errors/DF0012.md b/docs/content/6.errors/DF0012.md
index eb55dd48e..93ef22382 100644
--- a/docs/content/6.errors/DF0012.md
+++ b/docs/content/6.errors/DF0012.md
@@ -17,4 +17,4 @@ Delete the file to reset to defaults, or investigate how it became malformed.
## Source
-- [`packages/devframe/src/node/storage.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/node/storage.ts) — `createStorage()` catches `JSON.parse` errors and logs `DF0012` (with the cause attached) before falling back to `initialValue`.
+- [`packages/devframe/src/node/storage.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/node/storage.ts): `createStorage()` catches `JSON.parse` errors and logs `DF0012` (with the cause attached) before falling back to `initialValue`.
diff --git a/docs/content/6.errors/DF0013.md b/docs/content/6.errors/DF0013.md
index 86ddf4279..0204976f5 100644
--- a/docs/content/6.errors/DF0013.md
+++ b/docs/content/6.errors/DF0013.md
@@ -17,4 +17,4 @@ Pass `initialValue` on the first call: `ctx.rpc.sharedState.get(key, { initialVa
## Source
-- [`packages/devframe/src/node/rpc-shared-state.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/node/rpc-shared-state.ts) — `RpcSharedStateHost.get()` throws `DF0013` when neither an existing entry nor an `initialValue` is provided for a key.
+- [`packages/devframe/src/node/rpc-shared-state.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/node/rpc-shared-state.ts): `RpcSharedStateHost.get()` throws `DF0013` when neither an existing entry nor an `initialValue` is provided for a key.
diff --git a/docs/content/6.errors/DF0014.md b/docs/content/6.errors/DF0014.md
index fe1db4d9d..5ae29873d 100644
--- a/docs/content/6.errors/DF0014.md
+++ b/docs/content/6.errors/DF0014.md
@@ -1,11 +1,11 @@
---
title: 'DF0014: Invalid Agent Field'
-description: 'RPC function "{name}" has an invalid agent field — description must be a non-empty string.'
+description: 'RPC function "{name}" has an invalid agent field: description must be a non-empty string.'
---
## Message
-> RPC function "`{name}`" has an invalid `agent` field — `description` must be a non-empty string.
+> RPC function "`{name}`" has an invalid `agent` field: `description` must be a non-empty string.
## Cause
@@ -41,4 +41,4 @@ defineRpcFunction({
## Source
-- [`packages/devframe/src/node/host-agent.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/node/host-agent.ts) — agent registration throws `DF0014` when a tool's `agent.description` is missing or empty.
+- [`packages/devframe/src/node/host-agent.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/node/host-agent.ts): agent registration throws `DF0014` when a tool's `agent.description` is missing or empty.
diff --git a/docs/content/6.errors/DF0015.md b/docs/content/6.errors/DF0015.md
index aa1c88004..a67095222 100644
--- a/docs/content/6.errors/DF0015.md
+++ b/docs/content/6.errors/DF0015.md
@@ -29,4 +29,4 @@ ctx.agent.registerTool({ id: 'my-tool', /* new config */ })
## Source
-- [`packages/devframe/src/node/host-agent.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/node/host-agent.ts) — `ctx.agent.registerTool()` throws `DF0015` when the tool id collides with an existing agent tool or an RPC function's `agent` exposure.
+- [`packages/devframe/src/node/host-agent.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/node/host-agent.ts): `ctx.agent.registerTool()` throws `DF0015` when the tool id collides with an existing agent tool or an RPC function's `agent` exposure.
diff --git a/docs/content/6.errors/DF0016.md b/docs/content/6.errors/DF0016.md
index 132ab2e88..f7a16db91 100644
--- a/docs/content/6.errors/DF0016.md
+++ b/docs/content/6.errors/DF0016.md
@@ -17,4 +17,4 @@ Pick a distinct id or unregister the existing resource first via the handle retu
## Source
-- [`packages/devframe/src/node/host-agent.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/node/host-agent.ts) — `ctx.agent.registerResource()` throws `DF0016` when the resource id is already registered on the host.
+- [`packages/devframe/src/node/host-agent.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/node/host-agent.ts): `ctx.agent.registerResource()` throws `DF0016` when the resource id is already registered on the host.
diff --git a/docs/content/6.errors/DF0017.md b/docs/content/6.errors/DF0017.md
index 1ade75340..3737e5b0d 100644
--- a/docs/content/6.errors/DF0017.md
+++ b/docs/content/6.errors/DF0017.md
@@ -21,5 +21,5 @@ The MCP server failed while initializing. Common reasons:
## Source
-- [`packages/devframe/src/adapters/mcp/build-server.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/adapters/mcp/build-server.ts) — `createMcpServer()` throws `DF0017` when the stdio transport fails to `connect()`.
-- [`packages/devframe/src/adapters/dev.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/adapters/dev.ts) — `createDevServer()` throws `DF0017` (transport `http`) when the route-based MCP server can't load its transport module.
+- [`packages/devframe/src/adapters/mcp/build-server.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/adapters/mcp/build-server.ts): `createMcpServer()` throws `DF0017` when the stdio transport fails to `connect()`.
+- [`packages/devframe/src/adapters/dev.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/adapters/dev.ts): `createDevServer()` throws `DF0017` (transport `http`) when the route-based MCP server can't load its transport module.
diff --git a/docs/content/6.errors/DF0019.md b/docs/content/6.errors/DF0019.md
index 2acd951c5..027e864ad 100644
--- a/docs/content/6.errors/DF0019.md
+++ b/docs/content/6.errors/DF0019.md
@@ -1,11 +1,11 @@
---
title: 'DF0019: Agent Requires JSON-Serializable RPC'
-description: 'RPC function "{name}" has agent set but jsonSerializable is not true — MCP requires JSON-serializable data.'
+description: 'RPC function "{name}" has agent set but jsonSerializable is not true; MCP requires JSON-serializable data.'
---
## Message
-> RPC function "`{name}`" has `agent` set but `jsonSerializable` is not `true` — MCP requires JSON-serializable data.
+> RPC function "`{name}`" has `agent` set but `jsonSerializable` is not `true`; MCP requires JSON-serializable data.
## Cause
@@ -17,7 +17,7 @@ The `agent` field exposes an RPC function as an MCP tool, and MCP only consumes
defineRpcFunction({
name: 'my-plugin:summary',
agent: { description: 'Returns a summary' },
- handler: () => ({ items: [1, 2, 3] }), // ✗ throws DF0019 — missing jsonSerializable: true
+ handler: () => ({ items: [1, 2, 3] }), // ✗ throws DF0019: missing jsonSerializable: true
})
```
@@ -36,4 +36,4 @@ defineRpcFunction({
## Source
-- [`packages/devframe/src/rpc/collector.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/rpc/collector.ts) — `RpcFunctionsCollectorBase.register()` throws `DF0019` when a definition has `agent` set but is not declared `jsonSerializable: true`.
+- [`packages/devframe/src/rpc/collector.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/rpc/collector.ts): `RpcFunctionsCollectorBase.register()` throws `DF0019` when a definition has `agent` set but is not declared `jsonSerializable: true`.
diff --git a/docs/content/6.errors/DF0020.md b/docs/content/6.errors/DF0020.md
index f5b722742..fee3bd260 100644
--- a/docs/content/6.errors/DF0020.md
+++ b/docs/content/6.errors/DF0020.md
@@ -25,7 +25,7 @@ defineRpcFunction({
name: 'my-plugin:graph',
jsonSerializable: true,
handler: () => ({
- nodes: new Map([['a', 1]]), // ✗ throws DF0020 — type=Map, path="nodes"
+ nodes: new Map([['a', 1]]), // ✗ throws DF0020: type=Map, path="nodes"
}),
})
```
@@ -36,4 +36,4 @@ Drop `jsonSerializable: true` to fall back to `structured-clone-es` (round-trips
## Source
-- [`packages/devframe/src/rpc/serialization.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/rpc/serialization.ts) — the strict JSON serializer throws `DF0020` (with the offending path and runtime type) when a `jsonSerializable: true` payload contains a non-JSON value.
+- [`packages/devframe/src/rpc/serialization.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/rpc/serialization.ts): the strict JSON serializer throws `DF0020` (with the offending path and runtime type) when a `jsonSerializable: true` payload contains a non-JSON value.
diff --git a/docs/content/6.errors/DF0021.md b/docs/content/6.errors/DF0021.md
index 0ecacd8ae..7876e43ed 100644
--- a/docs/content/6.errors/DF0021.md
+++ b/docs/content/6.errors/DF0021.md
@@ -21,4 +21,4 @@ ctx.rpc.register(defineRpcFunction({ name: 'my-plugin:fn', handler: () => 1 }),
## Source
-- [`packages/devframe/src/rpc/collector.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/rpc/collector.ts) — `RpcFunctionsCollectorBase.register()` throws `DF0021` when an RPC name is already registered and `force` is not set.
+- [`packages/devframe/src/rpc/collector.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/rpc/collector.ts): `RpcFunctionsCollectorBase.register()` throws `DF0021` when an RPC name is already registered and `force` is not set.
diff --git a/docs/content/6.errors/DF0022.md b/docs/content/6.errors/DF0022.md
index 3c628b09f..6a7a7a897 100644
--- a/docs/content/6.errors/DF0022.md
+++ b/docs/content/6.errors/DF0022.md
@@ -17,4 +17,4 @@ Call `ctx.rpc.register()` first, or pass `force: true` to `update()` to register
## Source
-- [`packages/devframe/src/rpc/collector.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/rpc/collector.ts) — `RpcFunctionsCollectorBase.update()` throws `DF0022` when the named function was never registered.
+- [`packages/devframe/src/rpc/collector.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/rpc/collector.ts): `RpcFunctionsCollectorBase.update()` throws `DF0022` when the named function was never registered.
diff --git a/docs/content/6.errors/DF0023.md b/docs/content/6.errors/DF0023.md
index 0e1604b1e..83630ffd1 100644
--- a/docs/content/6.errors/DF0023.md
+++ b/docs/content/6.errors/DF0023.md
@@ -13,8 +13,8 @@ A consumer asked for the schema or handler of a function that has never been reg
## Fix
-Confirm the function name matches a registration. RPC names are namespaced — typos in the prefix are a common cause.
+Confirm the function name matches a registration. RPC names are namespaced, so typos in the prefix are a common cause.
## Source
-- [`packages/devframe/src/rpc/collector.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/rpc/collector.ts) — collector `get()`/lookup paths throw `DF0023` when consumers ask for a function that has not been registered.
+- [`packages/devframe/src/rpc/collector.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/rpc/collector.ts): collector `get()`/lookup paths throw `DF0023` when consumers ask for a function that has not been registered.
diff --git a/docs/content/6.errors/DF0024.md b/docs/content/6.errors/DF0024.md
index dfd74a76e..e15664774 100644
--- a/docs/content/6.errors/DF0024.md
+++ b/docs/content/6.errors/DF0024.md
@@ -17,5 +17,5 @@ Add either `handler: ...` directly on the definition, or `setup: ctx => ({ handl
## Source
-- [`packages/devframe/src/rpc/handler.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/rpc/handler.ts) — invocation throws `DF0024` when neither `handler` nor a `setup` returning `{ handler }` is provided.
-- [`packages/devframe/src/rpc/dump/index.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/rpc/dump/index.ts) — dump generation also requires a handler and throws `DF0024` if the definition is incomplete.
+- [`packages/devframe/src/rpc/handler.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/rpc/handler.ts): invocation throws `DF0024` when neither `handler` nor a `setup` returning `{ handler }` is provided.
+- [`packages/devframe/src/rpc/dump/index.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/rpc/dump/index.ts): dump generation also requires a handler and throws `DF0024` if the definition is incomplete.
diff --git a/docs/content/6.errors/DF0025.md b/docs/content/6.errors/DF0025.md
index b9fd3ebf8..c573f9464 100644
--- a/docs/content/6.errors/DF0025.md
+++ b/docs/content/6.errors/DF0025.md
@@ -17,4 +17,4 @@ Re-run `createBuild` to regenerate the dump, or check that the call site uses th
## Source
-- [`packages/devframe/src/rpc/dump/index.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/rpc/dump/index.ts) — the static-mode dump resolver throws `DF0025` when a client calls a function name that is not present in the baked dump store.
+- [`packages/devframe/src/rpc/dump/index.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/rpc/dump/index.ts): the static-mode dump resolver throws `DF0025` when a client calls a function name that is not present in the baked dump store.
diff --git a/docs/content/6.errors/DF0026.md b/docs/content/6.errors/DF0026.md
index e422eb62c..fb10be9bb 100644
--- a/docs/content/6.errors/DF0026.md
+++ b/docs/content/6.errors/DF0026.md
@@ -27,4 +27,4 @@ defineRpcFunction({
## Source
-- [`packages/devframe/src/rpc/dump/index.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/rpc/dump/index.ts) — the static-mode dump resolver throws `DF0026` when none of the pre-computed inputs matches the call's args and no `fallback` was configured.
+- [`packages/devframe/src/rpc/dump/index.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/rpc/dump/index.ts): the static-mode dump resolver throws `DF0026` when none of the pre-computed inputs matches the call's args and no `fallback` was configured.
diff --git a/docs/content/6.errors/DF0027.md b/docs/content/6.errors/DF0027.md
index cae4a0cb2..edea544f9 100644
--- a/docs/content/6.errors/DF0027.md
+++ b/docs/content/6.errors/DF0027.md
@@ -9,7 +9,7 @@ description: 'Function "{name}" with type "{type}" cannot have dump configuratio
## Cause
-A `dump` field was attached to an `'action'` or `'event'` function. These types perform side effects rather than returning queryable data — there is nothing meaningful to pre-compute.
+A `dump` field was attached to an `'action'` or `'event'` function. These types perform side effects rather than returning queryable data, so there is nothing meaningful to pre-compute.
## Fix
@@ -17,4 +17,4 @@ Drop the `dump` field, or change the function `type` to `'static'` / `'query'` i
## Source
-- [`packages/devframe/src/rpc/validation.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/rpc/validation.ts) — definition validation throws `DF0027` when a `dump` field is attached to an `'action'` or `'event'` function.
+- [`packages/devframe/src/rpc/validation.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/rpc/validation.ts): definition validation throws `DF0027` when a `dump` field is attached to an `'action'` or `'event'` function.
diff --git a/docs/content/6.errors/DF0028.md b/docs/content/6.errors/DF0028.md
index 3f57b392f..573dc33b9 100644
--- a/docs/content/6.errors/DF0028.md
+++ b/docs/content/6.errors/DF0028.md
@@ -9,7 +9,7 @@ description: 'Function "{name}" with type "{type}" cannot use snapshot: true. On
## Cause
-`snapshot: true` is sugar for "query in dev, single baked snapshot in build". It is only meaningful on `'query'` functions — `'static'` already has equivalent default behavior, and `'action'` / `'event'` have nothing to snapshot.
+`snapshot: true` is sugar for "query in dev, single baked snapshot in build". It is only meaningful on `'query'` functions: `'static'` already has equivalent default behavior, and `'action'` / `'event'` have nothing to snapshot.
## Fix
@@ -17,4 +17,4 @@ Remove `snapshot: true`, or change the function `type` to `'query'`.
## Source
-- [`packages/devframe/src/rpc/validation.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/rpc/validation.ts) — definition validation throws `DF0028` when `snapshot: true` is set on a function whose type is not `'query'`.
+- [`packages/devframe/src/rpc/validation.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/rpc/validation.ts): definition validation throws `DF0028` when `snapshot: true` is set on a function whose type is not `'query'`.
diff --git a/docs/content/6.errors/DF0029.md b/docs/content/6.errors/DF0029.md
index 3a391501b..024509981 100644
--- a/docs/content/6.errors/DF0029.md
+++ b/docs/content/6.errors/DF0029.md
@@ -14,9 +14,9 @@ The consumer is slower than the producer, so the subscriber's queue grew past it
## Fix
- Raise `highWaterMark` on `rpc.streaming.subscribe(channel, id, { highWaterMark })` if the consumer can occasionally catch up.
-- Slow the producer — throttle, debounce, or batch chunks server-side.
+- Slow the producer by throttling, debouncing, or batching chunks server-side.
- Use `sharedState` if you only need the latest value rather than every chunk.
## Source
-- [`packages/devframe/src/client/rpc-streaming.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/client/rpc-streaming.ts) — the client subscription queue logs `DF0029` (with the dropped chunk count) when buffered chunks exceed `highWaterMark`.
+- [`packages/devframe/src/client/rpc-streaming.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/client/rpc-streaming.ts): the client subscription queue logs `DF0029` (with the dropped chunk count) when buffered chunks exceed `highWaterMark`.
diff --git a/docs/content/6.errors/DF0030.md b/docs/content/6.errors/DF0030.md
index d932ef805..3dc8b6bfd 100644
--- a/docs/content/6.errors/DF0030.md
+++ b/docs/content/6.errors/DF0030.md
@@ -1,11 +1,11 @@
---
title: 'DF0030: Unknown Stream ID'
-description: 'Stream "{channel}#{id}" is unknown — no producer has called channel.start({ id: "{id}" }).'
+description: 'Stream "{channel}#{id}" is unknown; no producer has called channel.start({ id: "{id}" }).'
---
## Message
-> Stream "`{channel}#{id}`" is unknown — no producer has called `channel.start({ id: "{id}" })`.
+> Stream "`{channel}#{id}`" is unknown; no producer has called `channel.start({ id: "{id}" })`.
## Cause
@@ -13,10 +13,10 @@ A client subscribed to a stream id no server-side producer has started. Either t
## Fix
-- Run the producer before clients subscribe — typically await `rpc.call('your-action')` and use the returned id.
+- Run the producer before clients subscribe; typically await `rpc.call('your-action')` and use the returned id.
- Bump `replayWindow` on `ctx.rpc.streaming.create(name, { replayWindow })` to let clients resume after the producer finishes.
- Verify the id propagates correctly (action return → component prop → subscribe call).
## Source
-- [`packages/devframe/src/node/rpc-streaming.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/node/rpc-streaming.ts) — the streaming subscribe/unsubscribe paths log `DF0030` when a client references an `id` that no producer has started (and no replay buffer covers).
+- [`packages/devframe/src/node/rpc-streaming.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/node/rpc-streaming.ts): the streaming subscribe/unsubscribe paths log `DF0030` when a client references an `id` that no producer has started (and no replay buffer covers).
diff --git a/docs/content/6.errors/DF0031.md b/docs/content/6.errors/DF0031.md
index afd40a3a7..b30ad3830 100644
--- a/docs/content/6.errors/DF0031.md
+++ b/docs/content/6.errors/DF0031.md
@@ -32,4 +32,4 @@ catch (err) {
## Source
-- [`packages/devframe/src/utils/streaming-channel.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/utils/streaming-channel.ts) — `stream.write()` throws `DF0031` when called after the stream has been closed, errored, or aborted by the consumer.
+- [`packages/devframe/src/utils/streaming-channel.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/utils/streaming-channel.ts): `stream.write()` throws `DF0031` when called after the stream has been closed, errored, or aborted by the consumer.
diff --git a/docs/content/6.errors/DF0032.md b/docs/content/6.errors/DF0032.md
index 3fecee8cc..5fd620d65 100644
--- a/docs/content/6.errors/DF0032.md
+++ b/docs/content/6.errors/DF0032.md
@@ -18,4 +18,4 @@ Two calls to `ctx.rpc.streaming.create(name, ...)` used the same channel name. E
## Source
-- [`packages/devframe/src/node/rpc-streaming.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/node/rpc-streaming.ts) — `ctx.rpc.streaming.create()` throws `DF0032` when the requested channel name is already registered on the context.
+- [`packages/devframe/src/node/rpc-streaming.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/node/rpc-streaming.ts): `ctx.rpc.streaming.create()` throws `DF0032` when the requested channel name is already registered on the context.
diff --git a/docs/content/6.errors/DF0033.md b/docs/content/6.errors/DF0033.md
index acd5a1c20..39075afd9 100644
--- a/docs/content/6.errors/DF0033.md
+++ b/docs/content/6.errors/DF0033.md
@@ -9,7 +9,7 @@ description: 'Failed to start dev RPC bridge for "{id}": {reason}'
## Cause
-`devframeViteBridge()` (from `@devframes/vite`) could not bring up the bridge dev server that pairs a host-served SPA with devframe's RPC backend — usually because the preferred port is taken with no fallback range, or `def.setup(ctx)` threw. The surrounding Vite dev server keeps running, but the SPA's `__connection.json` lookup fails until the bridge starts.
+`devframeViteBridge()` (from `@devframes/vite`) could not bring up the bridge dev server that pairs a host-served SPA with devframe's RPC backend, usually because the preferred port is taken with no fallback range, or `def.setup(ctx)` threw. The surrounding Vite dev server keeps running, but the SPA's `__connection.json` lookup fails until the bridge starts.
## Fix
@@ -18,4 +18,4 @@ description: 'Failed to start dev RPC bridge for "{id}": {reason}'
## Source
-- [`packages/vite/src/index.ts`](https://github.com/devframes/devframe/blob/main/packages/vite/src/index.ts) — `devframeViteBridge()` logs `DF0033` when port resolution or `createDevServer` throws during `configureServer`.
+- [`packages/vite/src/index.ts`](https://github.com/devframes/devframe/blob/main/packages/vite/src/index.ts): `devframeViteBridge()` logs `DF0033` when port resolution or `createDevServer` throws during `configureServer`.
diff --git a/docs/content/6.errors/DF0034.md b/docs/content/6.errors/DF0034.md
index 686411a53..112ca5d96 100644
--- a/docs/content/6.errors/DF0034.md
+++ b/docs/content/6.errors/DF0034.md
@@ -16,10 +16,10 @@ A [scoped context](/guide/scoped-context) auto-namespaces the ids you pass it. `
```ts
const my = ctx.scope('my-plugin')
-// ✗ Bad — already namespaced
+// ✗ Bad: already namespaced
my.rpc.register(defineRpcFunction({ name: 'my-plugin:get-cwd', type: 'query', handler }))
-// ✓ Good — bare name, stored as `my-plugin:get-cwd`
+// ✓ Good: bare name, stored as `my-plugin:get-cwd`
my.rpc.register(defineRpcFunction({ name: 'get-cwd', type: 'query', handler }))
```
@@ -30,4 +30,4 @@ my.rpc.register(defineRpcFunction({ name: 'get-cwd', type: 'query', handler }))
## Source
-- [`packages/devframe/src/node/scope.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/node/scope.ts) — `register()` / `update()` throw this when the supplied definition name is already namespaced.
+- [`packages/devframe/src/node/scope.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/node/scope.ts): `register()` / `update()` throw this when the supplied definition name is already namespaced.
diff --git a/docs/content/6.errors/DF0035.md b/docs/content/6.errors/DF0035.md
index 2b9ad3bb4..642a45d04 100644
--- a/docs/content/6.errors/DF0035.md
+++ b/docs/content/6.errors/DF0035.md
@@ -9,7 +9,7 @@ description: 'Failed to persist storage file: {filepath}'
## Cause
-A shared-state store's debounced write to disk failed — the directory could not be created, or the temp-file write / atomic rename threw. Usually the storage directory is not writable or the disk is full.
+A shared-state store's debounced write to disk failed: the directory could not be created, or the temp-file write / atomic rename threw. Usually the storage directory is not writable or the disk is full.
## Fix
@@ -17,4 +17,4 @@ Check that the storage directory is writable and has free space.
## Source
-- [`packages/devframe/src/node/storage.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/node/storage.ts) — the debounced `updated` handler reports this when writing the temp file or renaming it into place fails.
+- [`packages/devframe/src/node/storage.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/node/storage.ts): the debounced `updated` handler reports this when writing the temp file or renaming it into place fails.
diff --git a/docs/content/6.errors/DF0036.md b/docs/content/6.errors/DF0036.md
index 12535aeae..0b7d03fc4 100644
--- a/docs/content/6.errors/DF0036.md
+++ b/docs/content/6.errors/DF0036.md
@@ -1,5 +1,5 @@
---
-title: 'DF0036: RPC Call Rejected — Not Authorized'
+title: 'DF0036: RPC Call Rejected, Not Authorized'
description: 'RPC call to "{name}" was rejected: the caller is not authorized.'
---
@@ -25,8 +25,8 @@ await client.call('some-plugin:do-something') // ✗ throws DF0036
- Complete the auth handshake before calling a trusted method.
- Connect with a static/pre-shared token (`createInteractiveAuth`'s `clientAuthTokens`) for CI or shared machines.
-- With a custom `authorize`, confirm it allows the method — it receives the method name and the session's `meta`.
+- With a custom `authorize`, confirm it allows the method; it receives the method name and the session's `meta`.
## Source
-- [`packages/devframe/src/node/rpc-core.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/node/rpc-core.ts) — `createContextRpcServer`'s resolver throws this when `authorize`/`auth.authorize` rejects a call.
+- [`packages/devframe/src/node/rpc-core.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/node/rpc-core.ts): `createContextRpcServer`'s resolver throws this when `authorize`/`auth.authorize` rejects a call.
diff --git a/docs/content/6.errors/DF0037.md b/docs/content/6.errors/DF0037.md
index 96e0cf263..6b952b6ec 100644
--- a/docs/content/6.errors/DF0037.md
+++ b/docs/content/6.errors/DF0037.md
@@ -14,11 +14,11 @@ description: 'A service is already provided under "{id}".'
## Example
```ts
-// ✗ Bad — provided twice
+// ✗ Bad: provided twice
ctx.services.provide('my-plugin:sources', hostA)
ctx.services.provide('my-plugin:sources', hostB)
-// ✓ Good — revoke the previous provider first
+// ✓ Good: revoke the previous provider first
const revoke = ctx.services.provide('my-plugin:sources', hostA)
revoke()
ctx.services.provide('my-plugin:sources', hostB)
@@ -26,10 +26,10 @@ ctx.services.provide('my-plugin:sources', hostB)
## Fix
-- Revoke the existing provider first — `provide()` returns a revoke function.
+- Revoke the existing provider first; `provide()` returns a revoke function.
- If the collision is between two unrelated devframes, namespace the id with your devframe id (`:`), the same rule RPC function names follow.
- Guard idempotent setup paths with `ctx.services.has(id)`.
## Source
-- [`packages/devframe/src/node/host-services.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/node/host-services.ts) — `provide()` throws this when the id is already taken.
+- [`packages/devframe/src/node/host-services.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/node/host-services.ts): `provide()` throws this when the id is already taken.
diff --git a/docs/content/6.errors/DF0038.md b/docs/content/6.errors/DF0038.md
index b0245b3dd..d7462bb0f 100644
--- a/docs/content/6.errors/DF0038.md
+++ b/docs/content/6.errors/DF0038.md
@@ -16,7 +16,7 @@ description: 'JSON-render view "{id}" received invalid props on element "{key}":
```ts
createJsonRenderView(ctx, {
id: 'toolbar',
- // ✗ throws DF0038 — `variant` is not a Button variant
+ /** ✗ throws DF0038: `variant` is not a Button variant */
spec: { root: 'a', elements: { a: { type: 'Button', props: { variant: 'nope' }, children: [] } } },
})
```
@@ -27,4 +27,4 @@ Match the element props to the base catalog's prop schema for that component. Dy
## Source
-- [`packages/json-render/src/node/create-view.ts`](https://github.com/devframes/devframe/blob/main/packages/json-render/src/node/create-view.ts) — `validateElementProps()` throws this at ingress and on `update`.
+- [`packages/json-render/src/node/create-view.ts`](https://github.com/devframes/devframe/blob/main/packages/json-render/src/node/create-view.ts): `validateElementProps()` throws this at ingress and on `update`.
diff --git a/docs/content/6.errors/DF0039.md b/docs/content/6.errors/DF0039.md
index 0c27b2b2b..ed7c2b4bf 100644
--- a/docs/content/6.errors/DF0039.md
+++ b/docs/content/6.errors/DF0039.md
@@ -24,4 +24,4 @@ Give each view a stable id unique within its scope, or dispose the previous view
## Source
-- [`packages/json-render/src/node/create-view.ts`](https://github.com/devframes/devframe/blob/main/packages/json-render/src/node/create-view.ts) — `createJsonRenderView()` throws this when the scoped id is already live.
+- [`packages/json-render/src/node/create-view.ts`](https://github.com/devframes/devframe/blob/main/packages/json-render/src/node/create-view.ts): `createJsonRenderView()` throws this when the scoped id is already live.
diff --git a/docs/content/6.errors/DF0040.md b/docs/content/6.errors/DF0040.md
index 1ba577474..5fdffc7e5 100644
--- a/docs/content/6.errors/DF0040.md
+++ b/docs/content/6.errors/DF0040.md
@@ -9,7 +9,7 @@ description: 'JSON-render view "{id}" was used after it was disposed.'
## Cause
-`view.dispose()` unregisters the view's shared state and its broadcast listeners. Calling `update` or `patchState` on a disposed handle is a lifecycle bug — the shared state it targeted no longer exists.
+`view.dispose()` unregisters the view's shared state and its broadcast listeners. Calling `update` or `patchState` on a disposed handle is a lifecycle bug: the shared state it targeted no longer exists.
## Example
@@ -25,4 +25,4 @@ Create a fresh view with `createJsonRenderView` instead of reusing a disposed ha
## Source
-- [`packages/json-render/src/node/create-view.ts`](https://github.com/devframes/devframe/blob/main/packages/json-render/src/node/create-view.ts) — `update` / `patchState` throw this after `dispose()`.
+- [`packages/json-render/src/node/create-view.ts`](https://github.com/devframes/devframe/blob/main/packages/json-render/src/node/create-view.ts): `update` / `patchState` throw this after `dispose()`.
diff --git a/docs/content/6.errors/DF0041.md b/docs/content/6.errors/DF0041.md
index 727dd9cad..daf164430 100644
--- a/docs/content/6.errors/DF0041.md
+++ b/docs/content/6.errors/DF0041.md
@@ -21,8 +21,8 @@ createJsonRenderView(ctx, { id: 'x', spec }) // ✗ throws DF0041
## Fix
-Keep specs and state strict JSON — remove functions, symbols, class instances, `Map`/`Set`, or circular references.
+Keep specs and state strict JSON: remove functions, symbols, class instances, `Map`/`Set`, or circular references.
## Source
-- [`packages/json-render/src/node/create-view.ts`](https://github.com/devframes/devframe/blob/main/packages/json-render/src/node/create-view.ts) — `assertJsonSerializable()` throws this at ingress and on `update`.
+- [`packages/json-render/src/node/create-view.ts`](https://github.com/devframes/devframe/blob/main/packages/json-render/src/node/create-view.ts): `assertJsonSerializable()` throws this at ingress and on `update`.
diff --git a/docs/content/6.errors/DF0042.md b/docs/content/6.errors/DF0042.md
index 1ecf296f5..e7ca87a3b 100644
--- a/docs/content/6.errors/DF0042.md
+++ b/docs/content/6.errors/DF0042.md
@@ -1,23 +1,23 @@
---
title: 'DF0042: Static Build Disabled By The Definition'
-description: '"{id}" declares capabilities.build: false — its static export is not meaningful (writes are excluded and any live-served data won''t be there).'
+description: '"{id}" declares capabilities.build: false; its static export is not meaningful (writes are excluded and any live-served data won''t be there).'
---
## Message
-> "`{id}`" declares `capabilities.build: false` — its static export is not meaningful (writes are excluded and any live-served data won't be there).
+> "`{id}`" declares `capabilities.build: false`; its static export is not meaningful (writes are excluded and any live-served data won't be there).
## Cause
-The definition opted out of static export via `capabilities.build: false` — typically because it is inherently live (manages real files, spawns a process) and a build export would only produce a write-less shell. `createCac` already hides the `build` subcommand for such a definition; this covers a caller invoking `createBuild()` directly.
+The definition opted out of static export via `capabilities.build: false`, typically because it is inherently live (manages real files, spawns a process) and a build export would only produce a write-less shell. `createCac` already hides the `build` subcommand for such a definition; this covers a caller invoking `createBuild()` directly.
## Example
```ts
-// ✗ Bad — builds a devframe that opted out of static export
+// ✗ Bad: builds a devframe that opted out of static export
await createBuild(assetsDevframe) // throws DF0042
-// ✓ Good — the degraded export is still useful to you
+// ✓ Good: the degraded export is still useful to you
await createBuild(assetsDevframe, { force: true })
```
@@ -28,4 +28,4 @@ await createBuild(assetsDevframe, { force: true })
## Source
-- [`packages/devframe/src/adapters/build.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/adapters/build.ts) — `createBuild()` throws this when `capabilities.build` is `false` and `force` isn't set.
+- [`packages/devframe/src/adapters/build.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/adapters/build.ts): `createBuild()` throws this when `capabilities.build` is `false` and `force` isn't set.
diff --git a/docs/content/6.errors/DF0043.md b/docs/content/6.errors/DF0043.md
index 538961b70..41890c2ab 100644
--- a/docs/content/6.errors/DF0043.md
+++ b/docs/content/6.errors/DF0043.md
@@ -9,7 +9,7 @@ description: 'RPC function "{name}" received an invalid argument at position {in
## Cause
-Each declared `args` schema validates its argument before the handler runs — on every path: local, over-the-wire, and the agent/MCP bridge. The argument at `{index}` failed its schema. Validation guards without rewriting, so unmentioned object fields still reach the handler.
+Each declared `args` schema validates its argument before the handler runs, on every path: local, over-the-wire, and the agent/MCP bridge. The argument at `{index}` failed its schema. Validation guards without rewriting, so unmentioned object fields still reach the handler.
## Example
@@ -24,7 +24,7 @@ const greet = defineRpcFunction({
// ✓ Good
await ctx.rpc.functions.greet('ada')
-// ✗ Bad — a number where a string is required → DF0043 at position 0
+// ✗ Bad: a number where a string is required → DF0043 at position 0
await ctx.rpc.functions.greet(42 as never)
```
@@ -34,4 +34,4 @@ Pass a value that satisfies the `args` schema declared for the function, or wide
## Source
-- [`packages/devframe/src/rpc/validate-io.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/rpc/validate-io.ts) — `validateRpcArgs()` throws `DF0043` on the first argument that fails its declared schema.
+- [`packages/devframe/src/rpc/validate-io.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/rpc/validate-io.ts): `validateRpcArgs()` throws `DF0043` on the first argument that fails its declared schema.
diff --git a/docs/content/6.errors/DF0044.md b/docs/content/6.errors/DF0044.md
index bc79d7e6e..572549bd8 100644
--- a/docs/content/6.errors/DF0044.md
+++ b/docs/content/6.errors/DF0044.md
@@ -9,7 +9,7 @@ description: 'RPC function "{name}" returned a value that failed its returns sch
## Cause
-A declared `returns` schema validates the handler's resolved value before it goes back to the caller. The value failed the schema — a bug in the handler, or a schema narrower than the real result. Validation guards without rewriting, so a value carrying extra object fields is accepted.
+A declared `returns` schema validates the handler's resolved value before it goes back to the caller. The value failed the schema, whether from a bug in the handler or a schema narrower than the real result. Validation guards without rewriting, so a value carrying extra object fields is accepted.
## Example
@@ -18,7 +18,7 @@ const count = defineRpcFunction({
name: 'count',
args: [],
returns: v.number(),
- // ✗ Bad — returns a string where a number is declared → DF0044
+ /** ✗ Bad: returns a string where a number is declared → DF0044 */
handler: () => 'twelve' as never,
})
```
@@ -29,4 +29,4 @@ Make the handler return a value that satisfies the `returns` schema, or relax th
## Source
-- [`packages/devframe/src/rpc/validate-io.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/rpc/validate-io.ts) — `validateRpcReturn()` throws `DF0044` when the handler's resolved value fails its declared schema.
+- [`packages/devframe/src/rpc/validate-io.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/rpc/validate-io.ts): `validateRpcReturn()` throws `DF0044` when the handler's resolved value fails its declared schema.
diff --git a/docs/content/6.errors/DF0045.md b/docs/content/6.errors/DF0045.md
index 8ce580f41..54ee0d48d 100644
--- a/docs/content/6.errors/DF0045.md
+++ b/docs/content/6.errors/DF0045.md
@@ -9,7 +9,7 @@ description: 'Failed to update the devframe instance registry at "{file}": {reas
## Cause
-A dev server (or a host calling `registerDevframeInstance`) could not write or remove its record in the instance registry directory (`~/.devframe/instances/` by default, or `$DEVFRAME_INSTANCES_DIR`) — usually a read-only home, missing permissions, or a full disk. The server keeps running; only discovery is affected, so `devframe connect` won't see this instance.
+A dev server (or a host calling `registerDevframeInstance`) could not write or remove its record in the instance registry directory (`~/.devframe/instances/` by default, or `$DEVFRAME_INSTANCES_DIR`), usually a read-only home, missing permissions, or a full disk. The server keeps running; only discovery is affected, so `devframe connect` won't see this instance.
## Fix
@@ -19,4 +19,4 @@ A dev server (or a host calling `registerDevframeInstance`) could not write or r
## Source
-- [`packages/devframe/src/node/instance-registry.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/node/instance-registry.ts) — `registerDevframeInstance()` reports this on a failed write and its `unregister()` on a failed removal.
+- [`packages/devframe/src/node/instance-registry.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/node/instance-registry.ts): `registerDevframeInstance()` reports this on a failed write and its `unregister()` on a failed removal.
diff --git a/docs/content/6.errors/DF0046.md b/docs/content/6.errors/DF0046.md
index cb5d96513..d6b624137 100644
--- a/docs/content/6.errors/DF0046.md
+++ b/docs/content/6.errors/DF0046.md
@@ -9,7 +9,7 @@ description: 'devframe connect requires the optional peer dependency @modelconte
## Cause
-`devframe connect` was started but `@modelcontextprotocol/server` could not be imported. The SDK is an optional peer dependency of `devframe` — the MCP surface stays opt-in, so it only needs to be installed where MCP features are used.
+`devframe connect` was started but `@modelcontextprotocol/server` could not be imported. The SDK is an optional peer dependency of `devframe`, keeping the MCP surface opt-in, so it only needs to be installed where MCP features are used.
## Fix
@@ -22,4 +22,4 @@ devframe connect
## Source
-- [`packages/devframe/src/cli/connect.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/cli/connect.ts) — `startConnectServer()` throws this when the dynamic SDK import fails.
+- [`packages/devframe/src/cli/connect.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/cli/connect.ts): `startConnectServer()` throws this when the dynamic SDK import fails.
diff --git a/docs/content/6.errors/DF0047.md b/docs/content/6.errors/DF0047.md
index be8d65e20..03353f5c4 100644
--- a/docs/content/6.errors/DF0047.md
+++ b/docs/content/6.errors/DF0047.md
@@ -9,7 +9,7 @@ description: 'Agent tool "{id}" is hidden from the MCP surface: its wire name "{
## Cause
-MCP clients constrain tool names to `^[a-zA-Z0-9_-]{1,128}$`, so the MCP adapter derives each tool's wire name from its id (runs of characters outside `[a-zA-Z0-9_-]` become a single `_`). Two registered ids sanitized to the same wire name — e.g. `demo:greet` and `demo_greet`. The first registration keeps the name; the later tool is hidden from `tools/list`.
+MCP clients constrain tool names to `^[a-zA-Z0-9_-]{1,128}$`, so the MCP adapter derives each tool's wire name from its id (runs of characters outside `[a-zA-Z0-9_-]` become a single `_`). Two registered ids sanitized to the same wire name, for example `demo:greet` and `demo_greet`. The first registration keeps the name; the later tool is hidden from `tools/list`.
## Example
@@ -24,4 +24,4 @@ Rename one of the two ids so they sanitize to distinct wire names. Namespaced id
## Source
-- [`packages/devframe/src/adapters/mcp/build-server.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/adapters/mcp/build-server.ts) — the `tools/list` handler reports this once per hidden tool when deduplicating wire names.
+- [`packages/devframe/src/adapters/mcp/build-server.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/adapters/mcp/build-server.ts): the `tools/list` handler reports this once per hidden tool when deduplicating wire names.
diff --git a/docs/content/6.errors/DF0048.md b/docs/content/6.errors/DF0048.md
index 6cc3ae6f8..2016d9139 100644
--- a/docs/content/6.errors/DF0048.md
+++ b/docs/content/6.errors/DF0048.md
@@ -24,4 +24,4 @@ Call the `devframe_state_read` tool without arguments to list the available keys
## Source
-- [`packages/devframe/src/adapters/mcp/build-server.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/adapters/mcp/build-server.ts) — `readStateResult()` throws this when the requested key is absent from the filtered key list.
+- [`packages/devframe/src/adapters/mcp/build-server.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/adapters/mcp/build-server.ts): `readStateResult()` throws this when the requested key is absent from the filtered key list.
diff --git a/docs/content/6.errors/DF0049.md b/docs/content/6.errors/DF0049.md
index 65033b607..483c23344 100644
--- a/docs/content/6.errors/DF0049.md
+++ b/docs/content/6.errors/DF0049.md
@@ -9,7 +9,7 @@ description: 'The devframe_connect_call-tool tool requires { port: number, tool:
## Cause
-The `devframe connect` gateway tool `devframe_connect_call-tool` was invoked without a numeric `port` or a string `tool` name — the two fields that identify which instance to dial and which of its tools to call.
+The `devframe connect` gateway tool `devframe_connect_call-tool` was invoked without a numeric `port` or a string `tool` name, the two fields that identify which instance to dial and which of its tools to call.
## Example
@@ -19,8 +19,8 @@ The `devframe connect` gateway tool `devframe_connect_call-tool` was invoked wit
## Fix
-Call `devframe_connect_list-instances` first — its result carries each instance's `port` and tool names — then retry with both fields.
+Call `devframe_connect_list-instances` first (its result carries each instance's `port` and tool names), then retry with both fields.
## Source
-- [`packages/devframe/src/cli/connect.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/cli/connect.ts) — `call()` throws this when the gateway arguments fail validation.
+- [`packages/devframe/src/cli/connect.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/cli/connect.ts): `call()` throws this when the gateway arguments fail validation.
diff --git a/docs/content/6.errors/DF0050.md b/docs/content/6.errors/DF0050.md
index ea2a723f0..fb9010fe1 100644
--- a/docs/content/6.errors/DF0050.md
+++ b/docs/content/6.errors/DF0050.md
@@ -9,7 +9,7 @@ description: 'No running devframe instance on port {port}.'
## Cause
-The `devframe connect` gateway tool `devframe_connect_call-tool` targeted a port with no live devframe instance behind it — neither the registry nor a direct probe found one serving `__connection.json`. The instance may have stopped, restarted on a different port, or never existed.
+The `devframe connect` gateway tool `devframe_connect_call-tool` targeted a port with no live devframe instance behind it: neither the registry nor a direct probe found one serving `__connection.json`. The instance may have stopped, restarted on a different port, or never existed.
## Example
@@ -24,4 +24,4 @@ Call `devframe_connect_list-instances` for the current instance list and retry w
## Source
-- [`packages/devframe/src/cli/connect.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/cli/connect.ts) — `call()` throws this when neither the registry nor the port probe finds an instance.
+- [`packages/devframe/src/cli/connect.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/cli/connect.ts): `call()` throws this when neither the registry nor the port probe finds an instance.
diff --git a/docs/content/6.errors/DF0051.md b/docs/content/6.errors/DF0051.md
index 723164ce8..deea443aa 100644
--- a/docs/content/6.errors/DF0051.md
+++ b/docs/content/6.errors/DF0051.md
@@ -9,7 +9,7 @@ description: 'The devframe instance on port {port} has no MCP endpoint.'
## Cause
-The `devframe connect` gateway tool `devframe_connect_call-tool` targeted a live instance running without an MCP route — its `__connection.json` advertises no `mcp` entry, so there is no endpoint to proxy the tool call to.
+The `devframe connect` gateway tool `devframe_connect_call-tool` targeted a live instance running without an MCP route: its `__connection.json` advertises no `mcp` entry, so there is no endpoint to proxy the tool call to.
## Example
@@ -24,4 +24,4 @@ Restart the instance with the `--mcp` flag (or set `cli.mcp: true` on its defini
## Source
-- [`packages/devframe/src/cli/connect.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/cli/connect.ts) — `call()` throws this when the targeted instance's record carries `mcp: null`.
+- [`packages/devframe/src/cli/connect.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/cli/connect.ts): `call()` throws this when the targeted instance's record carries `mcp: null`.
diff --git a/docs/content/6.errors/DF0052.md b/docs/content/6.errors/DF0052.md
index 2ea74ef9a..b8824ceee 100644
--- a/docs/content/6.errors/DF0052.md
+++ b/docs/content/6.errors/DF0052.md
@@ -9,7 +9,7 @@ description: 'Failed to listen on {host}:{port}: {reason}'
## Cause
-The instance shell's HTTP server failed to bind `host:port` — most commonly `EADDRINUSE` (another process, often a previously running devframe, holds the port) or `EACCES` (insufficient permissions on a privileged port). The WS RPC transport is torn down before this surfaces, so nothing leaks.
+The instance shell's HTTP server failed to bind `host:port`, most commonly `EADDRINUSE` (another process, often a previously running devframe, holds the port) or `EACCES` (insufficient permissions on a privileged port). The WS RPC transport is torn down before this surfaces, so nothing leaks.
## Example
@@ -21,8 +21,8 @@ The instance shell's HTTP server failed to bind `host:port` — most commonly `E
## Fix
- Free the port, or pick another via `--port`, `cli.port` / `cli.portRange` on the definition, or `port` on `devframeViteBridge` (`@devframes/vite`).
-- The original node error is available as `error.cause` — check `error.cause.code` (e.g. `'EADDRINUSE'`) to branch on the failure kind programmatically.
+- The original node error is available as `error.cause`; check `error.cause.code` (e.g. `'EADDRINUSE'`) to branch on the failure kind programmatically.
## Source
-- [`packages/devframe/src/node/instance-shell.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/node/instance-shell.ts) — the instance shell's HTTP+WS binding throws this when its owned HTTP server's `listen()` fails.
+- [`packages/devframe/src/node/instance-shell.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/node/instance-shell.ts): the instance shell's HTTP+WS binding throws this when its owned HTTP server's `listen()` fails.
diff --git a/docs/content/6.errors/DF0054.md b/docs/content/6.errors/DF0054.md
index 86659e881..05ef04a0c 100644
--- a/docs/content/6.errors/DF0054.md
+++ b/docs/content/6.errors/DF0054.md
@@ -9,7 +9,7 @@ description: 'connectionMeta() was called before initDevframe("{id}") finished i
## Cause
-`initDevframe` is a synchronous factory that kicks off asynchronous initialization eagerly — running `def.setup`, binding the WebSocket tier, and mounting the routes. `connectionMeta()` describes the WebSocket binding, which only exists once that initialization completes; calling it earlier has nothing correct to return.
+`initDevframe` is a synchronous factory that kicks off asynchronous initialization eagerly, running `def.setup`, binding the WebSocket tier, and mounting the routes. `connectionMeta()` describes the WebSocket binding, which only exists once that initialization completes; calling it earlier has nothing correct to return.
## Example
@@ -17,7 +17,7 @@ description: 'connectionMeta() was called before initDevframe("{id}") finished i
import { initDevframe } from 'devframe/initiate'
const devtools = initDevframe(def, { base: '/__my-tool/' })
-devtools.connectionMeta() // ✗ throws DF0054 — init is still in flight
+devtools.connectionMeta() // ✗ throws DF0054: init is still in flight
await devtools.ready
devtools.connectionMeta() // ✓ { backend: 'websocket', websocket: { … } }
@@ -25,8 +25,8 @@ devtools.connectionMeta() // ✓ { backend: 'websocket', websocket: { … } }
## Fix
-Await `instance.ready` (or any request through `instance.handler` — it awaits readiness internally) before reading `connectionMeta()`.
+Await `instance.ready` (or any request through `instance.handler`, which awaits readiness internally) before reading `connectionMeta()`.
## Source
-- [`packages/devframe/src/adapters/initiate.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/adapters/initiate.ts) — `initDevframe`'s `connectionMeta()` throws this while initialization is still pending.
+- [`packages/devframe/src/adapters/initiate.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/adapters/initiate.ts): `initDevframe`'s `connectionMeta()` throws this while initialization is still pending.
diff --git a/docs/content/6.errors/DF0055.md b/docs/content/6.errors/DF0055.md
index fe89de267..99ab2d252 100644
--- a/docs/content/6.errors/DF0055.md
+++ b/docs/content/6.errors/DF0055.md
@@ -9,7 +9,7 @@ description: 'This instance already owns its WebSocket transport ({tier}), so it
## Cause
-`attach(server)` / `handleUpgrade(req, socket, head)` exist for the tier where the instance binds nothing and waits for the host to hand upgrade events over. When the options already name a local binding — `ws.port` or `ws.sidecar` (`tier: 'sidecar'`) or `server` (`tier: 'server'`) — that transport already serves the socket, so routing a second server's upgrades into it would give the same RPC group two conflicting bindings.
+`attach(server)` / `handleUpgrade(req, socket, head)` exist for the tier where the instance binds nothing and waits for the host to hand upgrade events over. When the options already name a local binding (`ws.port` or `ws.sidecar` (`tier: 'sidecar'`) or `server` (`tier: 'server'`)), that transport already serves the socket, so routing a second server's upgrades into it would give the same RPC group two conflicting bindings.
## Example
@@ -17,7 +17,7 @@ description: 'This instance already owns its WebSocket transport ({tier}), so it
import { initHub } from '@devframes/hub/initiate'
const hub = initHub({ base: '/__devframes/', ws: { sidecar: true } })
-hub.attach(myServer) // ✗ throws DF0055 — the side-car already serves `__ws`
+hub.attach(myServer) // ✗ throws DF0055: the side-car already serves `__ws`
```
## Fix
@@ -26,4 +26,4 @@ Drop the `attach` / `handleUpgrade` call and let the configured transport serve
## Source
-- [`packages/devframe/src/node/instance-shell.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/node/instance-shell.ts) — the shared instance shell throws this from `attach` / `handleUpgrade` when the resolved tier is `sidecar` or `server`, for both `initDevframe` and `initHub`.
+- [`packages/devframe/src/node/instance-shell.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/node/instance-shell.ts): the shared instance shell throws this from `attach` / `handleUpgrade` when the resolved tier is `sidecar` or `server`, for both `initDevframe` and `initHub`.
diff --git a/docs/content/6.errors/DF0056.md b/docs/content/6.errors/DF0056.md
index 0dae7cd9b..9d052855f 100644
--- a/docs/content/6.errors/DF0056.md
+++ b/docs/content/6.errors/DF0056.md
@@ -20,7 +20,7 @@ const relayed = initDevframe(def, {
base: '/__my-tool/',
ws: { url: 'wss://devtools.example.com/relay/__ws' },
})
-relayed.attach(myServer) // ✗ throws DF0056 — an external server owns the socket
+relayed.attach(myServer) // ✗ throws DF0056: an external server owns the socket
// ✓ Serve the socket here, advertised through the relay (the tunnel pattern).
const tunnelled = initDevframe(def, {
@@ -31,8 +31,8 @@ const tunnelled = initDevframe(def, {
## Fix
-Drop `ws.url` to have the instance serve the socket, or pair it with `server` / `ws.port` / `ws.sidecar` for the tunnel pattern — a local binding that the advertised relay forwards to.
+Drop `ws.url` to have the instance serve the socket, or pair it with `server` / `ws.port` / `ws.sidecar` for the tunnel pattern: a local binding that the advertised relay forwards to.
## Source
-- [`packages/devframe/src/node/instance-shell.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/node/instance-shell.ts) — the shared instance shell throws this from `attach` / `handleUpgrade` when the resolved tier is `external`, for both `initDevframe` and `initHub`.
+- [`packages/devframe/src/node/instance-shell.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/node/instance-shell.ts): the shared instance shell throws this from `attach` / `handleUpgrade` when the resolved tier is `external`, for both `initDevframe` and `initHub`.
diff --git a/docs/content/6.errors/DF0057.md b/docs/content/6.errors/DF0057.md
index 82ee81c05..024a93062 100644
--- a/docs/content/6.errors/DF0057.md
+++ b/docs/content/6.errors/DF0057.md
@@ -9,7 +9,7 @@ description: 'This instance disables its WebSocket transport (ws: false), so the
## Cause
-`ws: false` runs the instance without a WebSocket — clients connect over the SSE endpoint instead (`backend: 'sse'`). There is no socket for `attach(server)` / `handleUpgrade(req, socket, head)` to feed.
+`ws: false` runs the instance without a WebSocket, so clients connect over the SSE endpoint instead (`backend: 'sse'`). There is no socket for `attach(server)` / `handleUpgrade(req, socket, head)` to feed.
## Example
@@ -20,7 +20,7 @@ const sseOnly = initDevframe(def, {
base: '/__my-tool/',
ws: false,
})
-sseOnly.attach(myServer) // ✗ throws DF0057 — there is no socket
+sseOnly.attach(myServer) // ✗ throws DF0057: there is no socket
// ✓ SSE needs no upgrade wiring; serve the HTTP surface and you're done.
myServer.on('request', (req, res) => sseOnly.nodeMiddleware(req, res))
@@ -28,8 +28,8 @@ myServer.on('request', (req, res) => sseOnly.nodeMiddleware(req, res))
## Fix
-Drop the `attach` / `handleUpgrade` wiring — the SSE endpoint rides the instance's ordinary HTTP surface (`handler` / `nodeMiddleware`), so serving requests is all a host needs. Remove `ws: false` if the instance should serve a WebSocket after all.
+Drop the `attach` / `handleUpgrade` wiring; the SSE endpoint rides the instance's ordinary HTTP surface (`handler` / `nodeMiddleware`), so serving requests is all a host needs. Remove `ws: false` if the instance should serve a WebSocket after all.
## Source
-- [`packages/devframe/src/node/instance-shell.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/node/instance-shell.ts) — the shared instance shell throws this from `attach` / `handleUpgrade` when the WebSocket tier is `disabled`, for both `initDevframe` and `initHub`.
+- [`packages/devframe/src/node/instance-shell.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/node/instance-shell.ts): the shared instance shell throws this from `attach` / `handleUpgrade` when the WebSocket tier is `disabled`, for both `initDevframe` and `initHub`.
diff --git a/docs/content/6.errors/DF0058.md b/docs/content/6.errors/DF0058.md
index 1511bf008..4f1e0ff94 100644
--- a/docs/content/6.errors/DF0058.md
+++ b/docs/content/6.errors/DF0058.md
@@ -1,11 +1,11 @@
---
title: 'DF0058: Dev Server Disabled By The Definition'
-description: '"{id}" declares capabilities.dev: false — it does not support a live dev server (its value is a static export only).'
+description: '"{id}" declares capabilities.dev: false; it does not support a live dev server (its value is a static export only).'
---
## Message
-> "`{id}`" declares `capabilities.dev: false` — it does not support a live dev server (its value is a static export only).
+> "`{id}`" declares `capabilities.dev: false`; it does not support a live dev server (its value is a static export only).
## Cause
@@ -27,4 +27,4 @@ await createDevServer(reportDevframe, { force: true })
## Source
-- [`packages/devframe/src/adapters/dev.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/adapters/dev.ts) — `createDevServer()` throws this when `capabilities.dev` is `false` and `force` isn't set.
+- [`packages/devframe/src/adapters/dev.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/adapters/dev.ts): `createDevServer()` throws this when `capabilities.dev` is `false` and `force` isn't set.
diff --git a/docs/content/6.errors/DF0059.md b/docs/content/6.errors/DF0059.md
index fd1ce15ff..60b771715 100644
--- a/docs/content/6.errors/DF0059.md
+++ b/docs/content/6.errors/DF0059.md
@@ -9,15 +9,15 @@ description: 'Failed to fetch the file listing for "{package}@{version}" from {p
## Cause
-A remote-assets source resolves request paths against the CDN provider's file-listing API (`data.jsdelivr.com` for jsDelivr, `?meta` for unpkg, or a custom provider's `listFiles`). That listing request failed — usually the provider is unreachable or returned an error status.
+A remote-assets source resolves request paths against the CDN provider's file-listing API (`data.jsdelivr.com` for jsDelivr, `?meta` for unpkg, or a custom provider's `listFiles`). That listing request failed, usually because the provider is unreachable or returned an error status.
## Fix
Requests fall back to probing each candidate path against the provider directly. To resolve it:
- Check network access to the configured provider, or switch providers (`provider: 'unpkg'` or a custom mirror).
-- Install the assets package locally (`npm install `) — a local copy is served with zero network and needs no listing.
+- Install the assets package locally (`npm install `); a local copy is served with zero network and needs no listing.
## Source
-- [`packages/devframe/src/utils/remote-assets.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/utils/remote-assets.ts) — `createRemoteAssetsStore()` reports this (once per store) when the provider's file listing cannot be fetched or parsed.
+- [`packages/devframe/src/utils/remote-assets.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/utils/remote-assets.ts): `createRemoteAssetsStore()` reports this (once per store) when the provider's file listing cannot be fetched or parsed.
diff --git a/docs/content/6.errors/DF0060.md b/docs/content/6.errors/DF0060.md
index b551ae9de..fbaa87ecb 100644
--- a/docs/content/6.errors/DF0060.md
+++ b/docs/content/6.errors/DF0060.md
@@ -9,13 +9,13 @@ description: 'Failed to fetch a remote asset of "{package}" ({url}): {reason}'
## Cause
-A requested file is in neither the locally installed assets package nor the on-disk cache, and streaming it through the CDN provider failed — the request errored, the provider returned a non-OK status, or the source is `offline: true` with the file missing from the cache.
+A requested file is in neither the locally installed assets package nor the on-disk cache, and streaming it through the CDN provider failed: the request errored, the provider returned a non-OK status, or the source is `offline: true` with the file missing from the cache.
## Fix
-- Install the assets package locally (`npm install `) to serve it with zero network — best for offline and air-gapped machines.
+- Install the assets package locally (`npm install `) to serve it with zero network, best for offline and air-gapped machines.
- Otherwise check network access to the configured provider, or point `provider` at a reachable mirror.
## Source
-- [`packages/devframe/src/utils/remote-assets.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/utils/remote-assets.ts) — `createRemoteAssetsStore()`'s `serve()` throws this when a provider fetch fails, returns a non-OK status, or an `offline` store misses its cache.
+- [`packages/devframe/src/utils/remote-assets.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/utils/remote-assets.ts): `createRemoteAssetsStore()`'s `serve()` throws this when a provider fetch fails, returns a non-OK status, or an `offline` store misses its cache.
diff --git a/docs/content/6.errors/DF0061.md b/docs/content/6.errors/DF0061.md
index a53a13909..bf015f16f 100644
--- a/docs/content/6.errors/DF0061.md
+++ b/docs/content/6.errors/DF0061.md
@@ -9,7 +9,7 @@ description: 'The locally installed "{package}@{installed}" is a different major
## Cause
-A locally installed copy of the assets package (resolved from the declaration's `resolveFrom` module) differs from the declared version by a **major**. Assets and node code are published in lockstep, so across a major boundary the served UI can be incompatible with its node backend — devframe refuses to serve it.
+A locally installed copy of the assets package (resolved from the declaration's `resolveFrom` module) differs from the declared version by a **major**. Assets and node code are published in lockstep, so across a major boundary the served UI can be incompatible with its node backend, and devframe refuses to serve it.
## Fix
@@ -23,4 +23,4 @@ Or uninstall the stale local copy so the assets stream from the CDN back-proxy a
## Source
-- [`packages/devframe/src/utils/remote-assets.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/utils/remote-assets.ts) — `resolveInstalledRemoteAssets()` throws this when the installed package's major version differs from the declared one.
+- [`packages/devframe/src/utils/remote-assets.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/utils/remote-assets.ts): `resolveInstalledRemoteAssets()` throws this when the installed package's major version differs from the declared one.
diff --git a/docs/content/6.errors/DF0062.md b/docs/content/6.errors/DF0062.md
index b4536fe29..b9b85d93a 100644
--- a/docs/content/6.errors/DF0062.md
+++ b/docs/content/6.errors/DF0062.md
@@ -1,15 +1,15 @@
---
title: 'DF0062: Installed Assets Package Version Skew'
-description: 'The locally installed "{package}@{installed}" differs from the required "{required}" — serving the installed one.'
+description: 'The locally installed "{package}@{installed}" differs from the required "{required}"; serving the installed one.'
---
## Message
-> The locally installed "`{package}`@`{installed}`" differs from the required "`{required}`" — serving the installed one.
+> The locally installed "`{package}`@`{installed}`" differs from the required "`{required}`"; serving the installed one.
## Cause
-A locally installed copy of the assets package differs from the declared version within the same major. The local install wins — keeping offline and air-gapped setups working — but the served assets are not byte-identical to the declared release, so the skew is surfaced.
+A locally installed copy of the assets package differs from the declared version within the same major. The local install wins (keeping offline and air-gapped setups working), but the served assets are not byte-identical to the declared release, so the skew is surfaced.
## Fix
@@ -19,8 +19,8 @@ Install the exact declared version to serve byte-identical assets:
npm install @devframes/plugin-git-client@1.2.3
```
-A major-version mismatch is rejected instead — see [DF0061](/errors/DF0061).
+A major-version mismatch is rejected instead; see [DF0061](/errors/DF0061).
## Source
-- [`packages/devframe/src/utils/remote-assets.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/utils/remote-assets.ts) — `resolveInstalledRemoteAssets()` reports this when the installed version differs from the declared one within the same major.
+- [`packages/devframe/src/utils/remote-assets.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/utils/remote-assets.ts): `resolveInstalledRemoteAssets()` reports this when the installed version differs from the declared one within the same major.
diff --git a/docs/content/6.errors/DF0063.md b/docs/content/6.errors/DF0063.md
index e4d450958..df164b38a 100644
--- a/docs/content/6.errors/DF0063.md
+++ b/docs/content/6.errors/DF0063.md
@@ -9,7 +9,7 @@ description: 'Failed to persist a remote asset into the cache at "{filepath}": {
## Cause
-A remote asset streamed through the CDN back-proxy to the browser, but writing the teed copy into the local cache directory (`/.remote-assets/@/…`) failed — usually a permissions problem, a full disk, or a removed `node_modules`. The response was still served; only caching failed, so the file streams through the provider again next request.
+A remote asset streamed through the CDN back-proxy to the browser, but writing the teed copy into the local cache directory (`/.remote-assets/@/…`) failed, usually from a permissions problem, a full disk, or a removed `node_modules`. The response was still served; only caching failed, so the file streams through the provider again next request.
## Fix
@@ -17,4 +17,4 @@ Check that the project storage directory (conventionally `node_modules/./de
## Source
-- [`packages/devframe/src/utils/remote-assets.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/utils/remote-assets.ts) — `createRemoteAssetsStore()`'s background cache write reports this when persisting a fetched file fails.
+- [`packages/devframe/src/utils/remote-assets.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/utils/remote-assets.ts): `createRemoteAssetsStore()`'s background cache write reports this when persisting a fetched file fails.
diff --git a/docs/content/6.errors/DF0064.md b/docs/content/6.errors/DF0064.md
index a7a54a22b..fc474de77 100644
--- a/docs/content/6.errors/DF0064.md
+++ b/docs/content/6.errors/DF0064.md
@@ -9,13 +9,13 @@ description: 'Failed to materialize the remote assets of "{package}@{version}":
## Cause
-A static build (`createBuild`) with remote-assets `clientAssets` needs every asset file up front so the output is self-contained. Materialization walks the provider's file listing and downloads each file; one of those steps failed — the provider has no `listFiles`, the listing request failed, or a file download errored.
+A static build (`createBuild`) with remote-assets `clientAssets` needs every asset file up front so the output is self-contained. Materialization walks the provider's file listing and downloads each file; one of those steps failed: the provider has no `listFiles`, the listing request failed, or a file download errored.
## Fix
-- Install the assets package locally (`npm install @`) — builds copy from the local install and touch no network.
+- Install the assets package locally (`npm install @`); builds copy from the local install and touch no network.
- Otherwise ensure the provider and its file-listing API are reachable during the build, or configure a custom provider that implements `listFiles`.
## Source
-- [`packages/devframe/src/utils/remote-assets.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/utils/remote-assets.ts) — `createRemoteAssetsStore()`'s `materialize()` throws this when the file listing is unavailable or a download fails.
+- [`packages/devframe/src/utils/remote-assets.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/utils/remote-assets.ts): `createRemoteAssetsStore()`'s `materialize()` throws this when the file listing is unavailable or a download fails.
diff --git a/docs/content/6.errors/DF0065.md b/docs/content/6.errors/DF0065.md
index e1c9de10e..8270d8ae1 100644
--- a/docs/content/6.errors/DF0065.md
+++ b/docs/content/6.errors/DF0065.md
@@ -9,7 +9,7 @@ description: 'Invalid remote-assets {field} "{value}".'
## Cause
-A remote-assets source's `package` and `version` are interpolated into CDN URLs (`https://cdn.jsdelivr.net/npm/@/…`) and the on-disk cache path (`.remote-assets/@/`). So `package` must be a valid npm package name and `version` an exact semver version — a value carrying path separators, `@`, whitespace, or traversal segments (`..`) is rejected.
+A remote-assets source's `package` and `version` are interpolated into CDN URLs (`https://cdn.jsdelivr.net/npm/@/…`) and the on-disk cache path (`.remote-assets/@/`). So `package` must be a valid npm package name and `version` an exact semver version; a value carrying path separators, `@`, whitespace, or traversal segments (`..`) is rejected.
## Example
@@ -37,4 +37,4 @@ defineDevframe({
## Source
-- [`packages/devframe/src/utils/remote-assets.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/utils/remote-assets.ts) — `resolveStaticAssetsSource()` validates a remote source before resolving it.
+- [`packages/devframe/src/utils/remote-assets.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/utils/remote-assets.ts): `resolveStaticAssetsSource()` validates a remote source before resolving it.
diff --git a/docs/content/6.errors/DF0066.md b/docs/content/6.errors/DF0066.md
index 307f7de6d..d5bb166db 100644
--- a/docs/content/6.errors/DF0066.md
+++ b/docs/content/6.errors/DF0066.md
@@ -1,11 +1,11 @@
---
title: 'DF0066: Service Already Installed'
-description: 'Service "{package}" is already installed — keeping the first installation and ignoring this one''s options.'
+description: 'Service "{package}" is already installed; keeping the first installation and ignoring this one''s options.'
---
## Message
-> Service "`{package}`" is already installed — keeping the first installation and ignoring this one's options.
+> Service "`{package}`" is already installed; keeping the first installation and ignoring this one's options.
## Cause
@@ -21,7 +21,7 @@ ctx.services.install(createShikiService({ themes }))
## Fix
-Declare the service so its options join the pre-setup merge — on the devframe's `DevframeDefinition.services`, or hub-wide via `initHub({ services })`:
+Declare the service so its options join the pre-setup merge: on the devframe's `DevframeDefinition.services`, or hub-wide via `initHub({ services })`:
```ts
initHub({
@@ -32,4 +32,4 @@ initHub({
## Source
-- [`packages/devframe/src/node/host-services.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/node/host-services.ts) — `installPackage` warns when an already-installed package is installed again.
+- [`packages/devframe/src/node/host-services.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/node/host-services.ts): `installPackage` warns when an already-installed package is installed again.
diff --git a/docs/content/6.errors/DF0067.md b/docs/content/6.errors/DF0067.md
index 98f8d8375..f50a9099c 100644
--- a/docs/content/6.errors/DF0067.md
+++ b/docs/content/6.errors/DF0067.md
@@ -9,7 +9,7 @@ description: 'Failed to import the required service package "{package}": {reason
## Cause
-A service descriptor marked `required: true` names a package that could not be resolved and imported when services are constructed before setup. Descriptors resolve against the declaring devframe's own dependencies first (then the workspace root), so the package is usually missing from the declarer's `dependencies` or isn't installed. Descriptors without `required` degrade instead — the missing service is skipped and consumers observe `services.has(pkg) === false`.
+A service descriptor marked `required: true` names a package that could not be resolved and imported when services are constructed before setup. Descriptors resolve against the declaring devframe's own dependencies first (then the workspace root), so the package is usually missing from the declarer's `dependencies` or isn't installed. Descriptors without `required` degrade instead: the missing service is skipped and consumers observe `services.has(pkg) === false`.
## Example
@@ -24,8 +24,8 @@ defineDevframe({
## Fix
-Install the service package next to whoever declares it — a devframe declaring it in `services` lists it in its own `dependencies` (or `peerDependencies`) — or drop `required: true` and let the consuming UI fall back when the service is absent.
+Install the service package next to whoever declares it (a devframe declaring it in `services` lists it in its own `dependencies` or `peerDependencies`), or drop `required: true` and let the consuming UI fall back when the service is absent.
## Source
-- [`packages/devframe/src/node/host-services.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/node/host-services.ts) — the pre-setup construction throws when a `required` descriptor's package fails to import.
+- [`packages/devframe/src/node/host-services.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/node/host-services.ts): the pre-setup construction throws when a `required` descriptor's package fails to import.
diff --git a/docs/content/6.errors/DF0068.md b/docs/content/6.errors/DF0068.md
index 172394a81..4079f3442 100644
--- a/docs/content/6.errors/DF0068.md
+++ b/docs/content/6.errors/DF0068.md
@@ -24,8 +24,8 @@ defineDevframe({
## Fix
-Align the installed service package with the declared range (update whichever side is stale), or drop `required: true` to downgrade the mismatch to a warning — the advertised meta carries the real version, so clients can gate on it.
+Align the installed service package with the declared range (update whichever side is stale), or drop `required: true` to downgrade the mismatch to a warning; the advertised meta carries the real version, so clients can gate on it.
## Source
-- [`packages/devframe/src/node/host-services.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/node/host-services.ts) — the pre-setup construction checks each descriptor's `version` range against the resolved definition.
+- [`packages/devframe/src/node/host-services.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/node/host-services.ts): the pre-setup construction checks each descriptor's `version` range against the resolved definition.
diff --git a/docs/content/6.errors/DF0069.md b/docs/content/6.errors/DF0069.md
index d214d6435..5d7451a6c 100644
--- a/docs/content/6.errors/DF0069.md
+++ b/docs/content/6.errors/DF0069.md
@@ -1,15 +1,15 @@
---
title: 'DF0069: Service Version Range Not Satisfied'
-description: 'The installed service "{package}@{installed}" does not satisfy the declared range "{required}" — installing it anyway.'
+description: 'The installed service "{package}@{installed}" does not satisfy the declared range "{required}"; installing it anyway.'
---
## Message
-> The installed service "`{package}`@`{installed}`" does not satisfy the declared range "`{required}`" — installing it anyway.
+> The installed service "`{package}`@`{installed}`" does not satisfy the declared range "`{required}`"; installing it anyway.
## Cause
-A service descriptor declares a `version` range, and the resolved service's own `version` falls outside it. The descriptor isn't marked `required`, so the service still installs — the range is a compatibility hint and this warning surfaces the drift. The advertised meta carries the real version, so client UIs can gate features on it. The `required: true` variant throws [`DF0068`](/errors/DF0068) instead.
+A service descriptor declares a `version` range, and the resolved service's own `version` falls outside it. The descriptor isn't marked `required`, so the service still installs: the range is a compatibility hint and this warning surfaces the drift. The advertised meta carries the real version, so client UIs can gate features on it. The `required: true` variant throws [`DF0068`](/errors/DF0068) instead.
## Example
@@ -28,4 +28,4 @@ Align the installed service package with the declared range to silence the warni
## Source
-- [`packages/devframe/src/node/host-services.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/node/host-services.ts) — the pre-setup construction checks each descriptor's `version` range against the resolved definition.
+- [`packages/devframe/src/node/host-services.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/node/host-services.ts): the pre-setup construction checks each descriptor's `version` range against the resolved definition.
diff --git a/docs/content/6.errors/DF0070.md b/docs/content/6.errors/DF0070.md
index ddecf4e7f..b03d0a6fd 100644
--- a/docs/content/6.errors/DF0070.md
+++ b/docs/content/6.errors/DF0070.md
@@ -19,17 +19,17 @@ A wire service failed structural validation at install time. The `reason` names
## Example
```ts
-// ✗ A pre-built instance as the default export — not a factory.
+/** ✗ A pre-built instance as the default export, not a factory. */
export default createShikiService()
-// ✓ The factory itself.
+/** ✓ The factory itself. */
export default createShikiService
```
## Fix
-A service package's default export must be its `createService` factory, returning a `DevframeServiceDefinition` — an object with `package`, `version`, `scope`, and a `setup` function. See [Cross-Devframe Services](/guide/services#wire-services) for the full shape.
+A service package's default export must be its `createService` factory, returning a `DevframeServiceDefinition`: an object with `package`, `version`, `scope`, and a `setup` function. See [Cross-Devframe Services](/guide/services#wire-services) for the full shape.
## Source
-- [`packages/devframe/src/node/host-services.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/node/host-services.ts) — `install()` validates its input; the pre-setup construction validates imported factories and the definitions they return.
+- [`packages/devframe/src/node/host-services.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/node/host-services.ts): `install()` validates its input; the pre-setup construction validates imported factories and the definitions they return.
diff --git a/docs/content/6.errors/DF0072.md b/docs/content/6.errors/DF0072.md
index 4f1234353..c08d596a6 100644
--- a/docs/content/6.errors/DF0072.md
+++ b/docs/content/6.errors/DF0072.md
@@ -1,11 +1,11 @@
---
title: 'DF0072: Snapshot Names Unknown RPC Method'
-description: 'rpc.snapshot names "{method}", but no RPC function is registered under that id — nothing to bake into the static build.'
+description: 'rpc.snapshot names "{method}", but no RPC function is registered under that id, so there is nothing to bake into the static build.'
---
## Message
-> `rpc.snapshot` names "`{method}`", but no RPC function is registered under that id — nothing to bake into the static build.
+> `rpc.snapshot` names "`{method}`", but no RPC function is registered under that id, so there is nothing to bake into the static build.
## Cause
@@ -17,4 +17,4 @@ Check the method id, and ensure the service/devframe that registers it is instal
## Source
-- [`packages/devframe/src/adapters/build.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/adapters/build.ts) — `applySnapshotRpc()` reports this when a `snapshot` entry's method id is missing from `ctx.rpc.definitions`.
+- [`packages/devframe/src/adapters/build.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/adapters/build.ts): `applySnapshotRpc()` reports this when a `snapshot` entry's method id is missing from `ctx.rpc.definitions`.
diff --git a/docs/content/6.errors/DF0073.md b/docs/content/6.errors/DF0073.md
index 64aff333d..989820023 100644
--- a/docs/content/6.errors/DF0073.md
+++ b/docs/content/6.errors/DF0073.md
@@ -17,4 +17,4 @@ Match the authored spec to the configured schema before creating or updating the
## Source
-- [`packages/json-render/src/node/create-view.ts`](https://github.com/devframes/devframe/blob/main/packages/json-render/src/node/create-view.ts) — `validateSpec()` throws this before shared state changes.
+- [`packages/json-render/src/node/create-view.ts`](https://github.com/devframes/devframe/blob/main/packages/json-render/src/node/create-view.ts): `validateSpec()` throws this before shared state changes.
diff --git a/docs/content/6.errors/DF0074.md b/docs/content/6.errors/DF0074.md
index 233fb5a17..06a80991f 100644
--- a/docs/content/6.errors/DF0074.md
+++ b/docs/content/6.errors/DF0074.md
@@ -17,4 +17,4 @@ Use a synchronous Standard Schema for JSON-render specs.
## Source
-- [`packages/json-render/src/node/create-view.ts`](https://github.com/devframes/devframe/blob/main/packages/json-render/src/node/create-view.ts) — `validateSpec()` rejects promise-returning validators.
+- [`packages/json-render/src/node/create-view.ts`](https://github.com/devframes/devframe/blob/main/packages/json-render/src/node/create-view.ts): `validateSpec()` rejects promise-returning validators.
diff --git a/docs/content/6.errors/DF0075.md b/docs/content/6.errors/DF0075.md
index d629d0385..506c07fa3 100644
--- a/docs/content/6.errors/DF0075.md
+++ b/docs/content/6.errors/DF0075.md
@@ -5,11 +5,11 @@ description: 'On Bun/Deno a shared server needs crossws Node adapter and SSE is
## Message
-> On {runtime} the shared server's WebSocket upgrade needs crossws's Node adapter, which refuses to run off Node — and SSE is disabled, so this instance advertises no RPC transport at all.
+> On {runtime} the shared server's WebSocket upgrade needs crossws's Node adapter, which refuses to run off Node, and SSE is disabled, so this instance advertises no RPC transport at all.
## Cause
-Sharing a host's `node:http` server (the `server` tier) drives the WebSocket upgrade through crossws's Node adapter, which runs only on Node. On Bun and Deno the socket falls back to the SSE endpoint — but here `sse: false` turned that endpoint off too, so the instance has no way for a client to reach its RPC surface.
+Sharing a host's `node:http` server (the `server` tier) drives the WebSocket upgrade through crossws's Node adapter, which runs only on Node. On Bun and Deno the socket falls back to the SSE endpoint, but here `sse: false` turned that endpoint off too, so the instance has no way for a client to reach its RPC surface.
## Example
@@ -25,8 +25,8 @@ const hub = initHub({
## Fix
-Keep the SSE endpoint enabled (drop `sse: false`) so clients connect over it on Bun/Deno, or move the socket to a side-car — `ws: { sidecar: true }` binds the native WebSocket adapter (`Bun.serve` / `Deno.serve`) on its own port, where a real WebSocket works.
+Keep the SSE endpoint enabled (drop `sse: false`) so clients connect over it on Bun/Deno, or move the socket to a side-car: `ws: { sidecar: true }` binds the native WebSocket adapter (`Bun.serve` / `Deno.serve`) on its own port, where a real WebSocket works.
## Source
-- [`packages/devframe/src/node/instance-shell.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/node/instance-shell.ts) — the shared instance shell warns this when a shared-server WebSocket binding falls back on Bun/Deno and the SSE endpoint is disabled, for both `initDevframe` and `initHub`.
+- [`packages/devframe/src/node/instance-shell.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/node/instance-shell.ts): the shared instance shell warns this when a shared-server WebSocket binding falls back on Bun/Deno and the SSE endpoint is disabled, for both `initDevframe` and `initHub`.
diff --git a/docs/content/6.errors/DF0076.md b/docs/content/6.errors/DF0076.md
index 413a684bb..d5796c119 100644
--- a/docs/content/6.errors/DF0076.md
+++ b/docs/content/6.errors/DF0076.md
@@ -9,7 +9,7 @@ description: 'attach / handleUpgrade drive a raw node:http upgrade into crossws
## Cause
-`attach(server)` and `handleUpgrade(req, socket, head)` hand a raw `node:http` upgrade socket to crossws's Node adapter. That adapter runs only on Node — Bun and Deno expose WebSockets as `fetch` upgrades through `Bun.serve` / `Deno.serve` instead, so there is no `node:http` upgrade socket for the adapter to take over.
+`attach(server)` and `handleUpgrade(req, socket, head)` hand a raw `node:http` upgrade socket to crossws's Node adapter. That adapter runs only on Node: Bun and Deno expose WebSockets as `fetch` upgrades through `Bun.serve` / `Deno.serve` instead, so there is no `node:http` upgrade socket for the adapter to take over.
## Example
@@ -23,8 +23,8 @@ hub.attach(myNodeHttpServer) // ✗ throws DF0076 on Bun/Deno
## Fix
-On Bun/Deno, serve the advertised `__ws` route from `Bun.serve` / `Deno.serve` and complete the upgrade with `attachBunWsTransport` / `attachDenoWsTransport` (see the `hub-deno-minimal` example), or connect over the SSE endpoint instead — it rides the instance's ordinary HTTP surface and needs no upgrade wiring. A side-car (`ws: { sidecar: true }`) also binds the native WebSocket adapter for you on its own port.
+On Bun/Deno, serve the advertised `__ws` route from `Bun.serve` / `Deno.serve` and complete the upgrade with `attachBunWsTransport` / `attachDenoWsTransport` (see the `hub-deno-minimal` example), or connect over the SSE endpoint instead; it rides the instance's ordinary HTTP surface and needs no upgrade wiring. A side-car (`ws: { sidecar: true }`) also binds the native WebSocket adapter for you on its own port.
## Source
-- [`packages/devframe/src/node/instance-shell.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/node/instance-shell.ts) — the shared instance shell throws this from `attach` / `handleUpgrade` on Bun/Deno, for both `initDevframe` and `initHub`.
+- [`packages/devframe/src/node/instance-shell.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/node/instance-shell.ts): the shared instance shell throws this from `attach` / `handleUpgrade` on Bun/Deno, for both `initDevframe` and `initHub`.
diff --git a/docs/content/6.errors/DF8000.md b/docs/content/6.errors/DF8000.md
index 9a8e2d492..43a8c354a 100644
--- a/docs/content/6.errors/DF8000.md
+++ b/docs/content/6.errors/DF8000.md
@@ -1,15 +1,15 @@
---
title: 'DF8000: Devframe Id Collides With a Reserved Hub Path'
-description: 'Devframe id "{id}" collides with a reserved hub path — it cannot be mounted directly under the hub base.'
+description: 'Devframe id "{id}" collides with a reserved hub path; it cannot be mounted directly under the hub base.'
---
## Message
-> Devframe id "`{id}`" collides with a reserved hub path — it cannot be mounted directly under the hub base.
+> Devframe id "`{id}`" collides with a reserved hub path; it cannot be mounted directly under the hub base.
## Cause
-`initHub` mounts every devframe at `/`, directly under the hub base. The filenames that live at that same level — `__connection.json`, `__ws`, `__index.json`, `__client-imports.js`, `__mcp`, and `embedded.js` — are the hub protocol's own endpoints, so a devframe id equal to one of them would shadow the endpoint.
+`initHub` mounts every devframe at `/`, directly under the hub base. The filenames that live at that same level (`__connection.json`, `__ws`, `__index.json`, `__client-imports.js`, `__mcp`, and `embedded.js`) are the hub protocol's own endpoints, so a devframe id equal to one of them would shadow the endpoint.
## Example
@@ -28,4 +28,4 @@ Rename the devframe id, or mount it at a non-colliding path via `basePath` on th
## Source
-- [`packages/hub/src/node/initiate.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/initiate.ts) — `initHub` throws this while mounting the `devframes` list.
+- [`packages/hub/src/node/initiate.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/initiate.ts): `initHub` throws this while mounting the `devframes` list.
diff --git a/docs/content/6.errors/DF8002.md b/docs/content/6.errors/DF8002.md
index 49a2fb2ec..905afaa54 100644
--- a/docs/content/6.errors/DF8002.md
+++ b/docs/content/6.errors/DF8002.md
@@ -1,15 +1,15 @@
---
title: 'DF8002: Both devframes and context Passed to initHub'
-description: 'initHub received both devframes and context — the two assembly modes are mutually exclusive.'
+description: 'initHub received both devframes and context; the two assembly modes are mutually exclusive.'
---
## Message
-> initHub received both `devframes` and `context` — the two assembly modes are mutually exclusive.
+> initHub received both `devframes` and `context`; the two assembly modes are mutually exclusive.
## Cause
-`initHub` assembles a hub two ways: **declaratively** (`devframes: [...]` — the instance creates the hub context and mounts each devframe under `/`), or **from a pre-built context** (`context: ctx` — your host framework already mounted the devframes; the instance serves only the hub-level endpoints and transport). A `devframes` list cannot be mounted into a context the instance doesn't own, so passing both contradicts.
+`initHub` assembles a hub two ways: **declaratively** (`devframes: [...]`, where the instance creates the hub context and mounts each devframe under `/`), or **from a pre-built context** (`context: ctx`, where your host framework already mounted the devframes and the instance serves only the hub-level endpoints and transport). A `devframes` list cannot be mounted into a context the instance doesn't own, so passing both contradicts.
## Example
@@ -17,10 +17,10 @@ description: 'initHub received both devframes and context — the two assembly m
// ✗ Bad
initHub({ base: '/__devframes/', devframes: [git], context: myCtx })
-// ✓ Good — declarative:
+// ✓ Good, declarative:
initHub({ base: '/__devframes/', devframes: [git] })
-// ✓ Good — bring your own context:
+// ✓ Good, bring your own context:
const ctx = await createHubContext({ host: myHost, cwd })
await ctx.install(git)
initHub({ base: '/__devframes/', context: ctx })
@@ -32,4 +32,4 @@ Pick one mode. Use `configure(ctx)` on the declarative mode when you need post-m
## Source
-- [`packages/hub/src/node/initiate.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/initiate.ts) — `initHub` throws this during initialization when both options are present.
+- [`packages/hub/src/node/initiate.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/initiate.ts): `initHub` throws this during initialization when both options are present.
diff --git a/docs/content/6.errors/DF8003.md b/docs/content/6.errors/DF8003.md
index dbccd443d..8e9269abc 100644
--- a/docs/content/6.errors/DF8003.md
+++ b/docs/content/6.errors/DF8003.md
@@ -9,7 +9,7 @@ description: 'connectionMeta() was called before initHub finished initializing.'
## Cause
-`initHub` is a synchronous factory that kicks off asynchronous initialization eagerly — creating the hub context, mounting every frame, and binding the WebSocket tier. `connectionMeta()` describes the WebSocket binding, which only exists once that initialization completes; calling it earlier has nothing correct to return.
+`initHub` is a synchronous factory that kicks off asynchronous initialization eagerly, creating the hub context, mounting every frame, and binding the WebSocket tier. `connectionMeta()` describes the WebSocket binding, which only exists once that initialization completes; calling it earlier has nothing correct to return.
## Example
@@ -17,7 +17,7 @@ description: 'connectionMeta() was called before initHub finished initializing.'
import { initHub } from '@devframes/hub/initiate'
const hub = initHub({ base: '/__devframes/', devframes: [git] })
-hub.connectionMeta() // ✗ throws DF8003 — init is still in flight
+hub.connectionMeta() // ✗ throws DF8003: init is still in flight
await hub.ready
hub.connectionMeta() // ✓ { backend: 'websocket', websocket: { … } }
@@ -25,8 +25,8 @@ hub.connectionMeta() // ✓ { backend: 'websocket', websocket: { … } }
## Fix
-Await `instance.ready` (or any request through `instance.handler` — it awaits readiness internally) before reading `connectionMeta()`.
+Await `instance.ready` (or any request through `instance.handler`, which awaits readiness internally) before reading `connectionMeta()`.
## Source
-- [`packages/hub/src/node/initiate.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/initiate.ts) — `initHub`'s `connectionMeta()` throws this while initialization is still pending.
+- [`packages/hub/src/node/initiate.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/initiate.ts): `initHub`'s `connectionMeta()` throws this while initialization is still pending.
diff --git a/docs/content/6.errors/DF8004.md b/docs/content/6.errors/DF8004.md
index 134d04473..c8e1f4aed 100644
--- a/docs/content/6.errors/DF8004.md
+++ b/docs/content/6.errors/DF8004.md
@@ -1,15 +1,15 @@
---
title: 'DF8004: Devframe Id Is Not a Mountable URL Segment'
-description: 'Devframe id "{id}" is not a mountable URL segment — the hub mounts each frame at /.'
+description: 'Devframe id "{id}" is not a mountable URL segment; the hub mounts each frame at /.'
---
## Message
-> Devframe id "`{id}`" is not a mountable URL segment — the hub mounts each frame at `/`.
+> Devframe id "`{id}`" is not a mountable URL segment; the hub mounts each frame at `/`.
## Cause
-`initHub` derives each frame's mount base from its id (`/__devframes//`), and that segment is routed by h3 — where `:` and `*` are route-pattern markers and `/` ends the segment. An id carrying those characters either crashes route registration or matches the wrong paths.
+`initHub` derives each frame's mount base from its id (`/__devframes//`), and that segment is routed by h3, where `:` and `*` are route-pattern markers and `/` ends the segment. An id carrying those characters either crashes route registration or matches the wrong paths.
## Example
@@ -21,14 +21,14 @@ initHub({
devframes: [defineDevframe({ id: 'devframes:plugin:my-tool', /* … */ })], // ✗ throws DF8004
})
-// ✓ Good — route-safe id (letters, digits, `_`, `-`, `.`):
+// ✓ Good, route-safe id (letters, digits, `_`, `-`, `.`):
defineDevframe({ id: 'devframes_plugin_my-tool', /* … */ })
```
## Fix
-Set a route-safe `id` on the definition — letters, digits, `_`, `-`, and `.` only (e.g. `my_plugin` instead of `my:plugin`). This constraint applies to the devframe id alone; RPC function ids (the colon-namespaced `devframes:plugin::` convention) are unaffected.
+Set a route-safe `id` on the definition: letters, digits, `_`, `-`, and `.` only (e.g. `my_plugin` instead of `my:plugin`). This constraint applies to the devframe id alone; RPC function ids (the colon-namespaced `devframes:plugin::` convention) are unaffected.
## Source
-- [`packages/hub/src/node/initiate.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/initiate.ts) — `initHub` throws this while mounting the `devframes` list.
+- [`packages/hub/src/node/initiate.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/initiate.ts): `initHub` throws this while mounting the `devframes` list.
diff --git a/docs/content/6.errors/DF8100.md b/docs/content/6.errors/DF8100.md
index 9211b2762..c09d11db5 100644
--- a/docs/content/6.errors/DF8100.md
+++ b/docs/content/6.errors/DF8100.md
@@ -18,4 +18,4 @@ description: 'Dock with id "{id}" is already registered'
## Source
-- [`packages/hub/src/node/host-docks.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/host-docks.ts) — `DevframeDocksHost.register()` throws when `views.has(view.id) && !force`.
+- [`packages/hub/src/node/host-docks.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/host-docks.ts): `DevframeDocksHost.register()` throws when `views.has(view.id) && !force`.
diff --git a/docs/content/6.errors/DF8101.md b/docs/content/6.errors/DF8101.md
index 6c7435291..8f8751ef5 100644
--- a/docs/content/6.errors/DF8101.md
+++ b/docs/content/6.errors/DF8101.md
@@ -9,7 +9,7 @@ description: 'Cannot change the id of dock "{id}" to "{attempted}". Dock ids are
## Cause
-The `update` handle returned by `ctx.docks.register(view)` received a patch whose `id` differs from the original. Dock ids are immutable post-registration — they key the dock list and any shared-state references.
+The `update` handle returned by `ctx.docks.register(view)` received a patch whose `id` differs from the original. Dock ids are immutable post-registration: they key the dock list and any shared-state references.
## Fix
@@ -18,4 +18,4 @@ The `update` handle returned by `ctx.docks.register(view)` received a patch whos
## Source
-- [`packages/hub/src/node/host-docks.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/host-docks.ts) — `DevframeDocksHost.register()` returns an `update` callable that throws this when the patch carries a different `id`.
+- [`packages/hub/src/node/host-docks.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/host-docks.ts): `DevframeDocksHost.register()` returns an `update` callable that throws this when the patch carries a different `id`.
diff --git a/docs/content/6.errors/DF8102.md b/docs/content/6.errors/DF8102.md
index f9ca7c1f5..9ccc86598 100644
--- a/docs/content/6.errors/DF8102.md
+++ b/docs/content/6.errors/DF8102.md
@@ -14,8 +14,8 @@ description: 'Dock with id "{id}" is not registered and cannot be updated'
## Fix
- Use `ctx.docks.register(view)` for new entries.
-- Verify the id matches a previously registered dock — typos / case mismatches are the usual cause.
+- Verify the id matches a previously registered dock; typos / case mismatches are the usual cause.
## Source
-- [`packages/hub/src/node/host-docks.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/host-docks.ts) — `DevframeDocksHost.update()` throws when `views.has(view.id) === false`.
+- [`packages/hub/src/node/host-docks.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/host-docks.ts): `DevframeDocksHost.update()` throws when `views.has(view.id) === false`.
diff --git a/docs/content/6.errors/DF8103.md b/docs/content/6.errors/DF8103.md
index 58b2b025f..35e9b93f4 100644
--- a/docs/content/6.errors/DF8103.md
+++ b/docs/content/6.errors/DF8103.md
@@ -18,4 +18,4 @@ A dock entry registered with `groupId` pointing at its own `id`. `groupId` is a
## Source
-- [`packages/hub/src/node/host-docks.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/host-docks.ts) — `DevframeDocksHost.register()` and `update()` throw this when `view.groupId === view.id`.
+- [`packages/hub/src/node/host-docks.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/host-docks.ts): `DevframeDocksHost.register()` and `update()` throw this when `view.groupId === view.id`.
diff --git a/docs/content/6.errors/DF8104.md b/docs/content/6.errors/DF8104.md
index 3d5230cad..549d1c364 100644
--- a/docs/content/6.errors/DF8104.md
+++ b/docs/content/6.errors/DF8104.md
@@ -18,4 +18,4 @@ A `type: 'group'` entry was registered with `groupId` set. Dock grouping is one
## Source
-- [`packages/hub/src/node/host-docks.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/host-docks.ts) — `DevframeDocksHost.register()` and `update()` throw this when `view.type === 'group'` and `view.groupId` is set.
+- [`packages/hub/src/node/host-docks.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/host-docks.ts): `DevframeDocksHost.register()` and `update()` throw this when `view.type === 'group'` and `view.groupId` is set.
diff --git a/docs/content/6.errors/DF8105.md b/docs/content/6.errors/DF8105.md
index 8116cddc0..e75ab7f72 100644
--- a/docs/content/6.errors/DF8105.md
+++ b/docs/content/6.errors/DF8105.md
@@ -15,12 +15,12 @@ description: 'Devframe "{name}" (id "{id}") is already mounted on this hub'
Set `duplicationStrategy` on the definition to choose how duplicates are handled:
-- `'duplicate'` — let every instance coexist under a disambiguated dock id (`my-tool`, `my-tool-2`, …).
-- `'silent'` — drop duplicates quietly.
-- `'throw'` — surface duplicates as errors.
+- `'duplicate'`: let every instance coexist under a disambiguated dock id (`my-tool`, `my-tool-2`, …).
+- `'silent'`: drop duplicates quietly.
+- `'throw'`: surface duplicates as errors.
Otherwise, remove the redundant `ctx.install` call (or duplicate `devframes` entry) so each devframe mounts once.
## Source
-- [`packages/hub/src/node/install-devframe.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/install-devframe.ts) — `ctx.install()` emits this when a devframe sharing an already-mounted `id` is installed and the strategy is not `'duplicate'`.
+- [`packages/hub/src/node/install-devframe.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/install-devframe.ts): `ctx.install()` emits this when a devframe sharing an already-mounted `id` is installed and the strategy is not `'duplicate'`.
diff --git a/docs/content/6.errors/DF8106.md b/docs/content/6.errors/DF8106.md
index c9d2e42e2..cc8bcbd98 100644
--- a/docs/content/6.errors/DF8106.md
+++ b/docs/content/6.errors/DF8106.md
@@ -1,11 +1,11 @@
---
title: 'DF8106: Connection Meta Not Served'
-description: 'The host cannot serve the RPC connection meta for devframe "{name}" (id "{id}") at "{base}" — its DevframeHost does not implement mountConnectionMeta.'
+description: 'The host cannot serve the RPC connection meta for devframe "{name}" (id "{id}") at "{base}"; its DevframeHost does not implement mountConnectionMeta.'
---
## Message
-> The host cannot serve the RPC connection meta for devframe "`{name}`" (id "`{id}`") at "`{base}`" — its `DevframeHost` does not implement `mountConnectionMeta`.
+> The host cannot serve the RPC connection meta for devframe "`{name}`" (id "`{id}`") at "`{base}`"; its `DevframeHost` does not implement `mountConnectionMeta`.
## Cause
@@ -30,4 +30,4 @@ A static-snapshot host that bakes `__connection.json` into its served files can
## Source
-- [`packages/hub/src/node/install-devframe.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/install-devframe.ts) — `ctx.install()` emits this when a devframe with servable `clientAssets` is installed on a host lacking `mountConnectionMeta`.
+- [`packages/hub/src/node/install-devframe.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/install-devframe.ts): `ctx.install()` emits this when a devframe with servable `clientAssets` is installed on a host lacking `mountConnectionMeta`.
diff --git a/docs/content/6.errors/DF8107.md b/docs/content/6.errors/DF8107.md
index 014cf4d83..4a4596e86 100644
--- a/docs/content/6.errors/DF8107.md
+++ b/docs/content/6.errors/DF8107.md
@@ -9,7 +9,7 @@ description: 'Dock activation requested for unknown dock id "{id}"'
## Cause
-`ctx.docks.activate(dockId)` — reached via the `hub:docks:activate` RPC — was called with a `dockId` that no registered dock entry owns. The activation is still broadcast, but no hub UI provider will switch to it.
+`ctx.docks.activate(dockId)`, reached via the `hub:docks:activate` RPC, was called with a `dockId` that no registered dock entry owns. The activation is still broadcast, but no hub UI provider will switch to it.
## Fix
@@ -24,4 +24,4 @@ await rpc.call('hub:docks:activate', {
## Source
-- [`packages/hub/src/node/host-docks.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/host-docks.ts) — `DevframeDocksHost.activate()` reports this when the requested dock id isn't in `views`.
+- [`packages/hub/src/node/host-docks.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/host-docks.ts): `DevframeDocksHost.activate()` reports this when the requested dock id isn't in `views`.
diff --git a/docs/content/6.errors/DF8108.md b/docs/content/6.errors/DF8108.md
index e7329e473..2738e278a 100644
--- a/docs/content/6.errors/DF8108.md
+++ b/docs/content/6.errors/DF8108.md
@@ -9,7 +9,7 @@ description: 'A renderer module is already registered for dock type "{type}"'
## Cause
-`initHub({ renderers })` received two registrations carrying the same `type`. Each dock type resolves to exactly one renderer module in the hub's renderer manifest — the module served at `__renderers/.mjs` — so a second registration for the same type would be unreachable.
+`initHub({ renderers })` received two registrations carrying the same `type`. Each dock type resolves to exactly one renderer module in the hub's renderer manifest (the module served at `__renderers/.mjs`), so a second registration for the same type would be unreachable.
## Example
@@ -24,9 +24,9 @@ initHub({
## Fix
-- Keep one registration per dock type — pick the implementation you want the manifest to serve.
+- Keep one registration per dock type: pick the implementation you want the manifest to serve.
- To override a manifest module for one specific client, register a renderer locally instead (`createDevframeClientRuntime({ renderers })`); local registrations take precedence.
## Source
-- [`packages/hub/src/node/initiate.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/initiate.ts) — `resolveRendererRegistrations()` throws when a `type` repeats.
+- [`packages/hub/src/node/initiate.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/initiate.ts): `resolveRendererRegistrations()` throws when a `type` repeats.
diff --git a/docs/content/6.errors/DF8109.md b/docs/content/6.errors/DF8109.md
index 845c0668b..7dbab0ede 100644
--- a/docs/content/6.errors/DF8109.md
+++ b/docs/content/6.errors/DF8109.md
@@ -9,7 +9,7 @@ description: 'The renderer module registered for dock type "{type}" does not exi
## Cause
-An `initHub({ renderers })` registration points at a file that isn't on disk. Renderer modules are prebuilt, self-contained browser ES modules the hub serves verbatim at `__renderers/.mjs` — a missing bundle would make every client's lazy import 404 at mount time, so the hub fails fast at startup instead.
+An `initHub({ renderers })` registration points at a file that isn't on disk. Renderer modules are prebuilt, self-contained browser ES modules the hub serves verbatim at `__renderers/.mjs`; a missing bundle would make every client's lazy import 404 at mount time, so the hub fails fast at startup instead.
## Example
@@ -23,9 +23,9 @@ initHub({
## Fix
-- Build the renderer package first — the bundle is a build artifact (e.g. `@devframes/json-render-ui`'s `dist/renderer/json-render.mjs`).
-- Prefer the package's registration helper over a hand-written path — `jsonRenderUiRenderer()` from `@devframes/json-render-ui/hub` resolves the shipped bundle for you.
+- Build the renderer package first; the bundle is a build artifact (e.g. `@devframes/json-render-ui`'s `dist/renderer/json-render.mjs`).
+- Prefer the package's registration helper over a hand-written path; `jsonRenderUiRenderer()` from `@devframes/json-render-ui/hub` resolves the shipped bundle for you.
## Source
-- [`packages/hub/src/node/initiate.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/initiate.ts) — `resolveRendererRegistrations()` throws when the resolved `file` fails the existence probe.
+- [`packages/hub/src/node/initiate.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/initiate.ts): `resolveRendererRegistrations()` throws when the resolved `file` fails the existence probe.
diff --git a/docs/content/6.errors/DF8110.md b/docs/content/6.errors/DF8110.md
index 418e36899..be83676c8 100644
--- a/docs/content/6.errors/DF8110.md
+++ b/docs/content/6.errors/DF8110.md
@@ -1,15 +1,15 @@
---
title: 'DF8110: Renderer Type Is Not URL-Safe'
-description: 'Dock type "{type}" is not a servable renderer-module name — the hub serves each module at __renderers/.mjs'
+description: 'Dock type "{type}" is not a servable renderer-module name; the hub serves each module at __renderers/.mjs'
---
## Message
-> Dock type "`{type}`" is not a servable renderer-module name — the hub serves each module at `__renderers/.mjs`
+> Dock type "`{type}`" is not a servable renderer-module name; the hub serves each module at `__renderers/.mjs`
## Cause
-An `initHub({ renderers })` registration carries a `type` that can't become a URL segment. The hub derives each module's serving path — and the manifest's `importFrom` — from the type, so `:` and `*` (route-pattern markers to the underlying router) or separators like `/` would break the route.
+An `initHub({ renderers })` registration carries a `type` that can't become a URL segment. The hub derives each module's serving path (and the manifest's `importFrom`) from the type, so `:` and `*` (route-pattern markers to the underlying router) or separators like `/` would break the route.
## Example
@@ -27,4 +27,4 @@ Use a route-safe dock type: letters, digits, `_`, `-`, and `.` only (e.g. `json-
## Source
-- [`packages/hub/src/node/initiate.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/initiate.ts) — `resolveRendererRegistrations()` rejects a `type` failing the `[\w.-]+` segment check.
+- [`packages/hub/src/node/initiate.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/initiate.ts): `resolveRendererRegistrations()` rejects a `type` failing the `[\w.-]+` segment check.
diff --git a/docs/content/6.errors/DF8111.md b/docs/content/6.errors/DF8111.md
index 43e0a0666..54e3ae4ff 100644
--- a/docs/content/6.errors/DF8111.md
+++ b/docs/content/6.errors/DF8111.md
@@ -1,15 +1,15 @@
---
title: 'DF8111: Bare-Specifier Client Script Without Host Resolution'
-description: 'Dock "{id}" declares the bare-specifier client script "{specifier}", but this host advertises no client-module resolution — the browser cannot resolve a bare npm specifier natively, so the script will fail to load.'
+description: 'Dock "{id}" declares the bare-specifier client script "{specifier}", but this host advertises no client-module resolution; the browser cannot resolve a bare npm specifier natively, so the script will fail to load.'
---
## Message
-> Dock "`{id}`" declares the bare-specifier client script "`{specifier}`", but this host advertises no client-module resolution — the browser cannot resolve a bare npm specifier natively, so the script will fail to load.
+> Dock "`{id}`" declares the bare-specifier client script "`{specifier}`", but this host advertises no client-module resolution; the browser cannot resolve a bare npm specifier natively, so the script will fail to load.
## Cause
-A dock entry's client script (`clientScript`, `action`, `renderer`) names a bare npm specifier as its `importFrom`. Client scripts load with a native browser `import()`, which resolves only URL specifiers — a bare specifier needs the host runtime to resolve it, advertised as `clientModuleResolution`. This host advertises none, so the script fails to load.
+A dock entry's client script (`clientScript`, `action`, `renderer`) names a bare npm specifier as its `importFrom`. Client scripts load with a native browser `import()`, which resolves only URL specifiers; a bare specifier needs the host runtime to resolve it, advertised as `clientModuleResolution`. This host advertises none, so the script fails to load.
## Example
@@ -22,7 +22,7 @@ initHub({
id: 'vue-tracer',
title: 'Vue Tracer',
icon: 'ph:crosshair-simple-duotone',
- // ✗ Bare specifier on a host with no `clientModuleResolution`
+ /** ✗ Bare specifier on a host with no `clientModuleResolution` */
action: { importFrom: 'vite-plugin-vue-tracer/client/vite-devtools' },
})
},
@@ -33,10 +33,10 @@ initHub({
Pick whichever side you control:
-- **Run under a host framework that resolves bare specifiers** — declare `initHub({ clientModuleResolution })` (e.g. Vite's `'/@id/{specifier}'`). `@devframes/vite/hub` sets this by default.
+- **Run under a host framework that resolves bare specifiers**: declare `initHub({ clientModuleResolution })` (e.g. Vite's `'/@id/{specifier}'`). `@devframes/vite/hub` sets this by default.
- **Ship the script as a self-contained bundle** served by URL, and pass that URL as `importFrom` (after `ctx.host.mountStatic(...)`).
-- **Resolve it in the hub UI provider** via `createDevframeClientRuntime({ resolveClientModule })` — then disregard this warning.
+- **Resolve it in the hub UI provider** via `createDevframeClientRuntime({ resolveClientModule })`; then disregard this warning.
## Source
-- [`packages/hub/src/node/host-docks.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/host-docks.ts) — `DevframeDocksHost.register()` warns when a bare-specifier client script registers on a host whose `staticConfig.dock` declares no `clientModuleResolution`.
+- [`packages/hub/src/node/host-docks.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/host-docks.ts): `DevframeDocksHost.register()` warns when a bare-specifier client script registers on a host whose `staticConfig.dock` declares no `clientModuleResolution`.
diff --git a/docs/content/6.errors/DF8200.md b/docs/content/6.errors/DF8200.md
index 3e877ca82..e1ab3957c 100644
--- a/docs/content/6.errors/DF8200.md
+++ b/docs/content/6.errors/DF8200.md
@@ -18,4 +18,4 @@ description: 'Terminal session with id "{id}" already registered'
## Source
-- [`packages/hub/src/node/host-terminals.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/host-terminals.ts) — `DevframeTerminalsHost.register()` and `startChildProcess()` throw when the id is already taken.
+- [`packages/hub/src/node/host-terminals.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/host-terminals.ts): `DevframeTerminalsHost.register()` and `startChildProcess()` throw when the id is already taken.
diff --git a/docs/content/6.errors/DF8201.md b/docs/content/6.errors/DF8201.md
index fa5a82bdd..856c66694 100644
--- a/docs/content/6.errors/DF8201.md
+++ b/docs/content/6.errors/DF8201.md
@@ -14,8 +14,8 @@ description: 'Terminal session with id "{id}" not registered'
## Fix
- Use `ctx.terminals.register(session)` to add new sessions.
-- Verify the id matches an existing session — common cause is updating after `remove()`.
+- Verify the id matches an existing session; a common cause is updating after `remove()`.
## Source
-- [`packages/hub/src/node/host-terminals.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/host-terminals.ts) — `DevframeTerminalsHost.update()` throws when `sessions.has(patch.id) === false`.
+- [`packages/hub/src/node/host-terminals.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/host-terminals.ts): `DevframeTerminalsHost.update()` throws when `sessions.has(patch.id) === false`.
diff --git a/docs/content/6.errors/DF8202.md b/docs/content/6.errors/DF8202.md
index be9f311a7..ee87a6d08 100644
--- a/docs/content/6.errors/DF8202.md
+++ b/docs/content/6.errors/DF8202.md
@@ -17,4 +17,4 @@ Spawn it via `ctx.terminals.startPtySession()` to get an interactive, writable s
## Source
-- [`packages/hub/src/node/rpc-builtins.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/rpc-builtins.ts) — the `hub:terminals:write` / `hub:terminals:resize` handlers throw this when the resolved session has no `write` handle.
+- [`packages/hub/src/node/rpc-builtins.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/rpc-builtins.ts): the `hub:terminals:write` / `hub:terminals:resize` handlers throw this when the resolved session has no `write` handle.
diff --git a/docs/content/6.errors/DF8203.md b/docs/content/6.errors/DF8203.md
index 19eda723c..bc0dcb600 100644
--- a/docs/content/6.errors/DF8203.md
+++ b/docs/content/6.errors/DF8203.md
@@ -10,7 +10,7 @@ description: 'Failed to spawn PTY session for "{command}": {reason}'
## Cause
`ctx.terminals.startPtySession()` could not launch the requested command in a
-pseudo-terminal — for example the executable was not found, the working
+pseudo-terminal: for example the executable was not found, the working
directory does not exist, or spawning was denied by the OS.
## Fix
@@ -21,4 +21,4 @@ directory does not exist, or spawning was denied by the OS.
## Source
-- [`packages/hub/src/node/host-terminals.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/host-terminals.ts) — `DevframeTerminalsHost.startPtySession()` throws this when an initial or restart `zigpty` spawn fails.
+- [`packages/hub/src/node/host-terminals.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/host-terminals.ts): `DevframeTerminalsHost.startPtySession()` throws this when an initial or restart `zigpty` spawn fails.
diff --git a/docs/content/6.errors/DF8204.md b/docs/content/6.errors/DF8204.md
index c0a27f5fc..0b0ed2492 100644
--- a/docs/content/6.errors/DF8204.md
+++ b/docs/content/6.errors/DF8204.md
@@ -13,8 +13,8 @@ description: 'Terminal session "{id}" cannot be controlled (no lifecycle handle)
## Fix
-Spawn it via `ctx.terminals.startChildProcess()` or `startPtySession()` — sessions added with a bare `register()` expose no terminate/restart handle. A bare session's lifecycle is driven by whatever owns its process; `hub:terminals:remove` still drops it from the registry.
+Spawn it via `ctx.terminals.startChildProcess()` or `startPtySession()`; sessions added with a bare `register()` expose no terminate/restart handle. A bare session's lifecycle is driven by whatever owns its process; `hub:terminals:remove` still drops it from the registry.
## Source
-- [`packages/hub/src/node/rpc-builtins.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/rpc-builtins.ts) — the `hub:terminals:terminate` / `hub:terminals:restart` handlers throw this when the resolved session has no `terminate` handle.
+- [`packages/hub/src/node/rpc-builtins.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/rpc-builtins.ts): the `hub:terminals:terminate` / `hub:terminals:restart` handlers throw this when the resolved session has no `terminate` handle.
diff --git a/docs/content/6.errors/DF8205.md b/docs/content/6.errors/DF8205.md
index cde97edef..73b05d9a0 100644
--- a/docs/content/6.errors/DF8205.md
+++ b/docs/content/6.errors/DF8205.md
@@ -9,7 +9,7 @@ description: 'Terminal session "{id}" is not restartable'
## Cause
-`hub:terminals:restart` was called for a session registered with `restartable: false` — a flag for sessions whose lifecycle is owned elsewhere (a one-shot build, or a server like code-server restarted through its own controls).
+`hub:terminals:restart` was called for a session registered with `restartable: false`, a flag for sessions whose lifecycle is owned elsewhere (a one-shot build, or a server like code-server restarted through its own controls).
## Fix
@@ -17,4 +17,4 @@ It was registered with `restartable: false`; restart it through its owner's cont
## Source
-- [`packages/hub/src/node/rpc-builtins.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/rpc-builtins.ts) — the `hub:terminals:restart` handler throws this when the resolved session has `restartable: false`.
+- [`packages/hub/src/node/rpc-builtins.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/rpc-builtins.ts): the `hub:terminals:restart` handler throws this when the resolved session has `restartable: false`.
diff --git a/docs/content/6.errors/DF8206.md b/docs/content/6.errors/DF8206.md
index c88ecd10a..4dab15761 100644
--- a/docs/content/6.errors/DF8206.md
+++ b/docs/content/6.errors/DF8206.md
@@ -1,15 +1,15 @@
---
title: 'DF8206: Terminal Session Restart on Closed Stream'
-description: 'Terminal session "{id}" cannot be restarted — its output stream is already closed'
+description: 'Terminal session "{id}" cannot be restarted; its output stream is already closed'
---
## Message
-> Terminal session "`{id}`" cannot be restarted — its output stream is already closed
+> Terminal session "`{id}`" cannot be restarted; its output stream is already closed
## Cause
-`restart()` was called on a `startChildProcess()` or `startPtySession()` session whose output stream is already closed. The stream closes irreversibly on a natural process exit or after `terminate()` — it backs a single-use `ReadableStream` controller that cannot be reopened, so restarting in place is not possible once it has closed.
+`restart()` was called on a `startChildProcess()` or `startPtySession()` session whose output stream is already closed. The stream closes irreversibly on a natural process exit or after `terminate()`: it backs a single-use `ReadableStream` controller that cannot be reopened, so restarting in place is not possible once it has closed.
## Fix
@@ -17,4 +17,4 @@ Drop the spent session with `ctx.terminals.remove(session)`, then spawn a replac
## Source
-- [`packages/hub/src/node/host-terminals.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/host-terminals.ts) — the `restart()` handle returned by `startChildProcess()` and `startPtySession()` throws this once the session's stream has closed.
+- [`packages/hub/src/node/host-terminals.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/host-terminals.ts): the `restart()` handle returned by `startChildProcess()` and `startPtySession()` throws this once the session's stream has closed.
diff --git a/docs/content/6.errors/DF8400.md b/docs/content/6.errors/DF8400.md
index 1925fac98..bb127e207 100644
--- a/docs/content/6.errors/DF8400.md
+++ b/docs/content/6.errors/DF8400.md
@@ -18,4 +18,4 @@ description: 'Command "{id}" is already registered'
## Source
-- [`packages/hub/src/node/host-commands.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/host-commands.ts) — `DevframeCommandsHost.register()` throws when `commands.has(command.id)`.
+- [`packages/hub/src/node/host-commands.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/host-commands.ts): `DevframeCommandsHost.register()` throws when `commands.has(command.id)`.
diff --git a/docs/content/6.errors/DF8401.md b/docs/content/6.errors/DF8401.md
index 2bb6fcc20..0dc4a3ed3 100644
--- a/docs/content/6.errors/DF8401.md
+++ b/docs/content/6.errors/DF8401.md
@@ -18,4 +18,4 @@ The `update` handle returned by `ctx.commands.register(cmd)` received a patch wi
## Source
-- [`packages/hub/src/node/host-commands.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/host-commands.ts) — `DevframeCommandsHost.register()` returns a `update` callable that throws when `'id' in patch`.
+- [`packages/hub/src/node/host-commands.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/host-commands.ts): `DevframeCommandsHost.register()` returns a `update` callable that throws when `'id' in patch`.
diff --git a/docs/content/6.errors/DF8402.md b/docs/content/6.errors/DF8402.md
index 5dbc56f29..a086f68cc 100644
--- a/docs/content/6.errors/DF8402.md
+++ b/docs/content/6.errors/DF8402.md
@@ -14,9 +14,9 @@ description: 'Command "{id}" is not registered'
## Fix
- Register the command first via `ctx.commands.register({ id, title, handler })`.
-- Verify the id — typos and stale references are the usual cause.
+- Verify the id; typos and stale references are the usual cause.
- If invoking client-side, register the command on the client via `ctx.commands.register` in the dock client script.
## Source
-- [`packages/hub/src/node/host-commands.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/host-commands.ts) — `DevframeCommandsHost.execute()` and the `update` handle throw when the id is missing.
+- [`packages/hub/src/node/host-commands.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/host-commands.ts): `DevframeCommandsHost.execute()` and the `update` handle throw when the id is missing.
diff --git a/docs/content/6.errors/DF8403.md b/docs/content/6.errors/DF8403.md
index fe31fa049..e650c8cfc 100644
--- a/docs/content/6.errors/DF8403.md
+++ b/docs/content/6.errors/DF8403.md
@@ -19,4 +19,4 @@ description: 'Command id "{id}" is already used by another command or child comm
## Source
-- [`packages/hub/src/node/host-commands.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/host-commands.ts) — `DevframeCommandsHost.register()` and command handle `update()` throw when a command id is duplicated.
+- [`packages/hub/src/node/host-commands.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/host-commands.ts): `DevframeCommandsHost.register()` and command handle `update()` throw when a command id is duplicated.
diff --git a/docs/content/6.errors/DF8404.md b/docs/content/6.errors/DF8404.md
index 04dc5864c..98bb19c1a 100644
--- a/docs/content/6.errors/DF8404.md
+++ b/docs/content/6.errors/DF8404.md
@@ -9,7 +9,7 @@ description: 'Command "{id}" declares agent exposure but has no handler'
## Cause
-`ctx.commands.register(command)` or a command handle `update()` received a command carrying an `agent` field but no `handler`. Agent-exposed commands are projected into `ctx.agent` as callable tools (reaching MCP clients through the devframe MCP adapter), so they must be executable server-side — a handler-less command is a palette group and cannot run.
+`ctx.commands.register(command)` or a command handle `update()` received a command carrying an `agent` field but no `handler`. Agent-exposed commands are projected into `ctx.agent` as callable tools (reaching MCP clients through the devframe MCP adapter), so they must be executable server-side; a handler-less command is a palette group and cannot run.
## Example
@@ -44,4 +44,4 @@ ctx.commands.register({
## Source
-- [`packages/hub/src/node/host-commands.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/host-commands.ts) — `DevframeCommandsHost.register()` and command handle `update()` validate agent exposure across the command tree.
+- [`packages/hub/src/node/host-commands.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/host-commands.ts): `DevframeCommandsHost.register()` and command handle `update()` validate agent exposure across the command tree.
diff --git a/docs/content/6.errors/index.md b/docs/content/6.errors/index.md
index 12d871834..c14717ae5 100644
--- a/docs/content/6.errors/index.md
+++ b/docs/content/6.errors/index.md
@@ -1,20 +1,20 @@
---
title: 'Error Reference'
-description: 'Devframe surfaces warnings and errors as structured diagnostics — each with a unique code, a human-readable message, and a link to this documentation.'
+description: 'Devframe surfaces warnings and errors as structured diagnostics: each with a unique code, a human-readable message, and a link to this documentation.'
---
-Devframe surfaces warnings and errors as structured diagnostics — each with a unique code, a human-readable message, and a link to this documentation.
+Devframe surfaces warnings and errors as structured diagnostics: each with a unique code, a human-readable message, and a link to this documentation.
## How error codes work
- Codes follow the pattern **`DF` + a 4-digit number**. Core `devframe` uses `DF00xx`–`DF07xx`; the hub reserves `DF8xxx`.
- Every page carries the message, cause, recommended fix, and the source file that emits it.
- **Level** is the diagnostic's severity: **error** or **warn**.
-- Diagnostics are powered by [`nostics`](https://www.npmjs.com/package/nostics) — structured codes with docs URLs, ANSI console output, and pluggable reporters.
+- Diagnostics are powered by [`nostics`](https://www.npmjs.com/package/nostics): structured codes with docs URLs, ANSI console output, and pluggable reporters.
## Devframe (DF)
-Emitted by `devframe` — the framework-neutral host, RPC, streaming, assets, services, and JSON-render surfaces.
+Emitted by `devframe`: the framework-neutral host, RPC, streaming, assets, services, and JSON-render surfaces.
| Code | Level | Title |
|------|-------|-------|
@@ -44,7 +44,7 @@ Emitted by `devframe` — the framework-neutral host, RPC, streaming, assets, se
| [DF0033](/errors/DF0033) | warn | Dev RPC Bridge Failed to Start |
| [DF0034](/errors/DF0034) | error | Already-Namespaced Scoped Registration |
| [DF0035](/errors/DF0035) | error | Storage File Persist Failed |
-| [DF0036](/errors/DF0036) | error | RPC Call Rejected — Not Authorized |
+| [DF0036](/errors/DF0036) | error | RPC Call Rejected, Not Authorized |
| [DF0037](/errors/DF0037) | error | Duplicate Service Provider |
| [DF0038](/errors/DF0038) | error | Invalid JSON-Render Element Props |
| [DF0039](/errors/DF0039) | error | Duplicate JSON-Render View |
@@ -82,7 +82,7 @@ Emitted by `devframe` — the framework-neutral host, RPC, streaming, assets, se
| [DF0073](/errors/DF0073) | error | JSON-Render Spec Does Not Match Its Schema |
| [DF0074](/errors/DF0074) | error | JSON-Render Schema Is Asynchronous |
-## Hub — context & lifecycle (DF80xx)
+## Hub: context & lifecycle (DF80xx)
Emitted by `@devframes/hub` while assembling and mounting the unified surface.
@@ -93,7 +93,7 @@ Emitted by `@devframes/hub` while assembling and mounting the unified surface.
| [DF8003](/errors/DF8003) | error | connectionMeta() Before Hub Instance Ready |
| [DF8004](/errors/DF8004) | error | Devframe Id Is Not a Mountable URL Segment |
-## Hub — docks & mounting (DF81xx)
+## Hub: docks & mounting (DF81xx)
| Code | Level | Title |
|------|-------|-------|
@@ -110,7 +110,7 @@ Emitted by `@devframes/hub` while assembling and mounting the unified surface.
| [DF8110](/errors/DF8110) | error | Renderer Type Is Not URL-Safe |
| [DF8111](/errors/DF8111) | warn | Bare-Specifier Client Script Without Host Resolution |
-## Hub — terminals (DF82xx)
+## Hub: terminals (DF82xx)
| Code | Level | Title |
|------|-------|-------|
@@ -122,7 +122,7 @@ Emitted by `@devframes/hub` while assembling and mounting the unified surface.
| [DF8205](/errors/DF8205) | error | Terminal Session Is Not Restartable |
| [DF8206](/errors/DF8206) | error | Terminal Session Restart on Closed Stream |
-## Hub — commands (DF84xx)
+## Hub: commands (DF84xx)
| Code | Level | Title |
|------|-------|-------|
diff --git a/docs/content/7.migrations/1.migration-0.9.md b/docs/content/7.migrations/1.migration-0.9.md
index a0fe256c3..ad5d2f0dd 100644
--- a/docs/content/7.migrations/1.migration-0.9.md
+++ b/docs/content/7.migrations/1.migration-0.9.md
@@ -3,7 +3,7 @@ title: 'Migrating to 0.9'
description: '0.9 removes the compatibility shims deprecated across the 0.7 series, trims the public API of devframe and @devframes/hub, and moves the MCP surface to the stateless MCP 2026-07-28 protocol.'
---
-0.9 removes the compatibility shims deprecated across the 0.7 series and trims the public API of `devframe` and `@devframes/hub`. Each change has a drop-in replacement. It also moves the [MCP](/adapters/mcp) surface to the stateless [MCP 2026-07-28 protocol](https://modelcontextprotocol.io/specification/2026-07-28) — the devframe API is unchanged; see [The MCP endpoints are stateless](#the-mcp-endpoints-are-stateless).
+0.9 removes the compatibility shims deprecated across the 0.7 series and trims the public API of `devframe` and `@devframes/hub`. Each change has a drop-in replacement. It also moves the [MCP](/adapters/mcp) surface to the stateless [MCP 2026-07-28 protocol](https://modelcontextprotocol.io/specification/2026-07-28). The devframe API is unchanged; see [The MCP endpoints are stateless](#the-mcp-endpoints-are-stateless).
## `devframe/adapters/cli` is removed
@@ -120,7 +120,7 @@ Two unused utility subpaths are removed:
## `devframe/node` is slimmed to the context API
-`devframe/node` keeps only the context API — `createHostContext`, `createStorage` (with their options types), and `RpcFunctionsHost`. Serve via the adapters or [`devframe/initiate`](/adapters/initiate).
+`devframe/node` keeps only the context API: `createHostContext`, `createStorage` (with their options types), and `RpcFunctionsHost`. Serve via the adapters or [`devframe/initiate`](/adapters/initiate).
Internal host implementations and factories are no longer exported:
@@ -231,7 +231,7 @@ export default defineConfig({
})
```
-`@devframes/vite` (and `@devframes/nuxt` / `@devframes/next`) take `@devframes/hub` and `@devframes/hub-ui` as **optional** peers — only the `/hub` scope needs them.
+`@devframes/vite` (and `@devframes/nuxt` / `@devframes/next`) take `@devframes/hub` and `@devframes/hub-ui` as **optional** peers; only the `/hub` scope needs them.
## Built-in devframes' `/vite` subpath is removed
@@ -291,17 +291,17 @@ await ctx.install(createA11yDevframe())
Both serve their single-devframe API from `.../single`; the bare root throws.
-Nuxt — register the module by its subpath:
+Nuxt: register the module by its subpath:
```ts
-// 0.8.x [nuxt.config.ts]
+/** 0.8.x [nuxt.config.ts] */
export default defineNuxtConfig({ modules: ['@devframes/nuxt'] })
-// 0.9 [nuxt.config.ts]
+/** 0.9 [nuxt.config.ts] */
export default defineNuxtConfig({ modules: ['@devframes/nuxt/single'] })
```
-Next — helpers and the React RPC client move down a level:
+Next: helpers and the React RPC client move down a level:
| 0.8.x | 0.9 |
|---|---|
@@ -321,7 +321,7 @@ export default defineConfig({ plugins: [viteDevframeHub({ devframes: [] })] })
```
```ts
-// Next — app/__devframes/[[...path]]/route.ts
+// Next: app/__devframes/[[...path]]/route.ts
import { nextDevframeHub } from '@devframes/next/hub'
export const runtime = 'nodejs'
@@ -335,7 +335,7 @@ export const DELETE = (req: Request) => hub.handler(req)
## The MCP endpoints are stateless
-The [MCP](/adapters/mcp) surface serves the stateless [2026-07-28 protocol](https://modelcontextprotocol.io/specification/2026-07-28). The devframe API you author against — `createMcpServer`, `createMcpFetchHandler`, `mountMcpHttp`, `cli.mcp`, and the agent host — is unchanged; the change is in how the endpoints serve requests on the wire.
+The [MCP](/adapters/mcp) surface serves the stateless [2026-07-28 protocol](https://modelcontextprotocol.io/specification/2026-07-28). The devframe API you author against (`createMcpServer`, `createMcpFetchHandler`, `mountMcpHttp`, `cli.mcp`, and the agent host) is unchanged; the change is in how the endpoints serve requests on the wire.
- **HTTP** serves each request through the SDK's `createMcpHandler`, building a fresh server per request. There is no `Mcp-Session-Id` and no `initialize` handshake to open a session, so a request reaches any server instance without affinity. A `GET` or `DELETE` (the 2025 session operations) is answered `405`. 2025-era clients keep listing and calling tools and resources through the SDK's stateless legacy path; the live server-push channel for `list_changed` notifications is available to modern clients over the `subscriptions/listen` stream they open.
- **stdio** serves the connection through the SDK's `serveStdio`, pinning one server instance per connection and negotiating the 2026-07-28 era (falling back to the 2025 handshake for a 2025-era opening).
diff --git a/docs/content/7.migrations/2.migration-0.8.md b/docs/content/7.migrations/2.migration-0.8.md
index 8e10194df..560207b53 100644
--- a/docs/content/7.migrations/2.migration-0.8.md
+++ b/docs/content/7.migrations/2.migration-0.8.md
@@ -45,7 +45,7 @@ export const rename = defineRpcFunction({
})
```
-**Declared schemas are now enforced.** Each argument is validated before the handler runs, and the resolved return value on the way out; a mismatch is rejected with a coded diagnostic. Audit schemas that were more type hint than contract — inputs that slipped through now throw.
+**Declared schemas are now enforced.** Each argument is validated before the handler runs, and the resolved return value on the way out; a mismatch is rejected with a coded diagnostic. Audit schemas that were more type hint than contract: inputs that slipped through now throw.
## MCP adapter upgraded to `@modelcontextprotocol/sdk` v2
@@ -66,8 +66,8 @@ SDK types imported directly moved from deep `@modelcontextprotocol/sdk/...` subp
## Agent-native MCP API
-0.8 adds the agent-facing API on `ctx.agent` — `registerTool`, `registerToolProvider`, `registerResource` — plus an instance registry and the `devframe connect` MCP connector. Existing `agent`-flagged RPCs keep working.
+0.8 adds the agent-facing API on `ctx.agent` (`registerTool`, `registerToolProvider`, `registerResource`), plus an instance registry and the `devframe connect` MCP connector. Existing `agent`-flagged RPCs keep working.
-One type sharpens: a `handler` (and its `dump`) now returns `Thenable` — `returns` describes the *resolved* value and the runtime always awaits, so an `async` handler whose `returns` is the unwrapped value type-checks correctly.
+One type sharpens: a `handler` (and its `dump`) now returns `Thenable`, where `returns` describes the *resolved* value and the runtime always awaits, so an `async` handler whose `returns` is the unwrapped value type-checks correctly.
See [Agent-Native](/guide/agent-native) and [MCP → `devframe connect`](/adapters/mcp#discovery-devframe-connect).
diff --git a/docs/content/7.migrations/3.migration-0.7.md b/docs/content/7.migrations/3.migration-0.7.md
index 03d3031d3..36ad52da3 100644
--- a/docs/content/7.migrations/3.migration-0.7.md
+++ b/docs/content/7.migrations/3.migration-0.7.md
@@ -7,13 +7,13 @@ description: '0.7 makes cac an optional peer and moves json-render out of @devfr
## `cac` is now an optional peer dependency
-`devframe` no longer bundles [`cac`](https://github.com/cacjs/cac) — it's an optional `peerDependency`. Projects using `createCac` (formerly `createCli`) install `cac`:
+`devframe` no longer bundles [`cac`](https://github.com/cacjs/cac); it's an optional `peerDependency`. Projects using `createCac` (formerly `createCli`) install `cac`:
```sh
npm install devframe cac
```
-Tools not using the CLI adapter — Vite plugins, embedded devframes, the [lower-level factories](/guide/standalone-cli#use-your-own-cli-framework) — never need `cac`.
+Tools not using the CLI adapter (Vite plugins, embedded devframes, the [lower-level factories](/guide/standalone-cli#use-your-own-cli-framework)) never need `cac`.
## `devframe/adapters/cli` → `devframe/adapters/cac`
@@ -67,4 +67,4 @@ const view = createJsonRenderView(ctx, {
})
```
-`@devframes/hub` still exports `defineJsonRenderSpec` (deprecated) and runs `ctx.createJsonRenderer`, so 0.7 call sites keep working — but nothing registers with the dock union or gains `registerRenderer()`; removed in 0.8.
+`@devframes/hub` still exports `defineJsonRenderSpec` (deprecated) and runs `ctx.createJsonRenderer`, so 0.7 call sites keep working, but nothing registers with the dock union or gains `registerRenderer()`; removed in 0.8.
diff --git a/docs/content/8.references/1.terms.md b/docs/content/8.references/1.terms.md
index d75e6fceb..d53d5703f 100644
--- a/docs/content/8.references/1.terms.md
+++ b/docs/content/8.references/1.terms.md
@@ -5,16 +5,16 @@ navigation:
description: 'The canonical vocabulary of these docs: one name per concept, the API or package that anchors it, and how the pieces talk to each other.'
---
-Every concept in these docs has exactly one name. This page fixes that vocabulary — when a term below appears anywhere in the documentation, it carries the meaning defined here.
+Every concept in these docs has exactly one name. This page fixes that vocabulary: when a term below appears anywhere in the documentation, it carries the meaning defined here.
## Core
| Term | Meaning | Anchor |
|------|---------|--------|
-| **Devframe** | The product: a framework-neutral foundation for building a devtool once and running it everywhere. | — |
+| **Devframe** | The product: a framework-neutral foundation for building a devtool once and running it everywhere. | none |
| `devframe` | The npm package the foundation ships as. | `devframe` |
| **a devframe** | One tool: a definition plus its SPA, mountable anywhere. | `defineDevframe()`, `DevframeDefinition` |
-| **built-in devframe** | A ready-to-run devframe shipped from this repo (data inspector, inspect, OG, a11y, git, terminals, code-server, assets). The `plugin-` npm prefix only sets these packages apart from core packages — Devframe has no plugin concept. | `@devframes/plugin-*` |
+| **built-in devframe** | A ready-to-run devframe shipped from this repo (data inspector, inspect, OG, a11y, git, terminals, code-server, assets). The `plugin-` npm prefix only sets these packages apart from core packages; Devframe has no plugin concept. | `@devframes/plugin-*` |
| **adapter** | A deployment entry point under `devframe/adapters/*`: cli (cac), dev, build, vite, embedded, mcp. | `devframe/adapters/*` |
| **framework kit** | Framework conventions over the standard handler, each split into a `/single` and a `/hub` scope. | `@devframes/vite`, `@devframes/nuxt`, `@devframes/next` |
| **opt-in package** | A capability shipped as its own package and added when needed. | `@devframes/json-render` |
@@ -28,9 +28,9 @@ A devframe has two halves: the **node side** registers RPC functions and owns st
| Term | Meaning | Anchor |
|------|---------|--------|
| **node side** | The half of a devframe running in the Node process. | `setup(ctx)` |
-| **host framework** | The environment a devframe or hub mounts into: a Vite dev server, a Next.js app, a Hono server. Named forms — *the Vite host*, *a Next.js host* — refer to a specific one. | `DevframeHost` |
+| **host framework** | The environment a devframe or hub mounts into: a Vite dev server, a Next.js app, a Hono server. Named forms (*the Vite host*, *a Next.js host*) refer to a specific one. | `DevframeHost` |
| **dev server** | The standalone HTTP server the dev adapter starts. | `createDevServer()` |
-| **side-car server** | The separate RPC/WebSocket process used when a host framework's handlers never see upgrade requests. | — |
+| **side-car server** | The separate RPC/WebSocket process used when a host framework's handlers never see upgrade requests. | none |
| **hosted / standalone adapters** | The two mount contexts: hosted adapters (vite, embedded) default the base path to `/__/`; standalone adapters (cli, build) default to `/`. | `resolveBasePath()` |
| **workspace scope** | Committable per-repository storage. | `DevframeStorageScope` |
| **project scope** | Per-checkout storage, gitignored. | `DevframeStorageScope` |
@@ -41,18 +41,18 @@ A devframe has two halves: the **node side** registers RPC functions and owns st
| Term | Meaning | Anchor |
|------|---------|--------|
| **browser side** | The half of a devframe running in a page. | `devframe/client` |
-| **user app** | The application being developed and inspected. | — |
-| **host page** | The browser document where the client runtime boots — in dev, usually the user app's own page. | — |
+| **user app** | The application being developed and inspected. | none |
+| **host page** | The browser document where the client runtime boots; in dev, usually the user app's own page. | none |
| **client runtime** | The headless runtime booted once per host page: it connects RPC, assembles the client context, and imports client scripts. | `createDevframeClientRuntime()` |
| **client context** | The shared object client scripts receive: panel, docks, commands, when-clauses. | `DevframeClientContext` |
| **client script** | A dock entry's script, imported into the host page by the client runtime. | `clientScript` |
-| **page script** | A devframe's script running in the user app's page — loaded as a client script or standalone. The a11y page script runs axe-core. | — |
+| **page script** | A devframe's script running in the user app's page, loaded as a client script or standalone. The a11y page script runs axe-core. | none |
| **RPC client** | The typed connection a browser surface gets. | `connectDevframe()` |
| **SPA** | A devframe's built web interface; `clientAssets` says where it lives. | `clientAssets` |
-| **panel** | A devframe's SPA as a rendered surface — in a dock panel or standalone. | — |
-| **surface** | Any rendered browser view: a panel, a dock iframe, a standalone SPA. | — |
+| **panel** | A devframe's SPA as a rendered surface, in a dock panel or standalone. | none |
+| **surface** | Any rendered browser view: a panel, a dock iframe, a standalone SPA. | none |
| **external viewer** | A cross-origin surface (a browser extension, a separate devtools page) connecting from its own origin. | `registerDevframeViewerOrigin()` |
-| **coding agent** | An agent consuming a devframe over MCP — the only agent in these docs. | `createMcpServer()` |
+| **coding agent** | An agent consuming a devframe over MCP, the only agent in these docs. | `createMcpServer()` |
## Hub
@@ -60,8 +60,8 @@ A devframe has two halves: the **node side** registers RPC functions and owns st
|------|---------|--------|
| **mounted devframe** | A devframe served inside a hub under `/`. | `initHub({ devframes })` |
| **dock entry** | A registry item: iframe, launcher, custom-render, group, or json-render. | `ctx.docks` |
-| **dock rail** | The bar listing every mounted tool. | — |
-| **dock panel** | The open drawer rendering the active dock entry. | — |
+| **dock rail** | The bar listing every mounted tool. | none |
+| **dock panel** | The open drawer rendering the active dock entry. | none |
## Communication paths
@@ -71,4 +71,4 @@ Three distinct paths connect the pieces; each has its own name.
|------|---------|-----------|
| **RPC** | browser side ↔ node side | WebSocket or static snapshot, via `connectDevframe()` |
| **client context** | client scripts ↔ client runtime | a shared object inside the host page |
-| **in-page channel** | page script ↔ panel | same-origin, entirely in-browser — a handshaken `MessageChannel` port per panel, via [`devframe/in-page-channel`](/guide/in-page-channel) |
+| **in-page channel** | page script ↔ panel | same-origin, entirely in-browser: a handshaken `MessageChannel` port per panel, via [`devframe/in-page-channel`](/guide/in-page-channel) |
diff --git a/docs/content/8.references/10.interactive-auth.md b/docs/content/8.references/10.interactive-auth.md
index c4d1f80e7..b20353f02 100644
--- a/docs/content/8.references/10.interactive-auth.md
+++ b/docs/content/8.references/10.interactive-auth.md
@@ -23,7 +23,7 @@ attachWsRpcTransport(rpcGroup, { server, onConnected, onDisconnected })
auth.printBanner()
```
-As `auth` it wires `rpcFunctions`, `authorize`, and `onConnect` — see [Security](/guide/security).
+As `auth` it wires `rpcFunctions`, `authorize`, and `onConnect`; see [Security](/guide/security).
## `createInteractiveAuth(context, options?)`
diff --git a/docs/content/8.references/2.when-clauses.md b/docs/content/8.references/2.when-clauses.md
index 9e8b40467..358a51af7 100644
--- a/docs/content/8.references/2.when-clauses.md
+++ b/docs/content/8.references/2.when-clauses.md
@@ -74,8 +74,8 @@ ctx.docks.register({
### `==` vs `===`
-- **`==` / `!=`** — VS Code idiom; RHS a single token, compared as a string.
-- **`===` / `!==`** — JS strict equality; full expressions both sides, no coercion.
+- **`==` / `!=`**: VS Code idiom; RHS a single token, compared as a string.
+- **`===` / `!==`**: JS strict equality; full expressions both sides, no coercion.
```ts
evaluateWhen('clientType == embedded', ctx) // string-style
@@ -141,7 +141,7 @@ defineCommand({
id: 'my-devtool:broken',
title: 'Broken',
when: 'dockOpen &&& !paletteOpen',
- // ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Type error: syntax error
+ /** ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Type error: syntax error */
handler: async () => {},
})
```
diff --git a/docs/content/8.references/3.events.md b/docs/content/8.references/3.events.md
index e776cb9d0..17da5c9e3 100644
--- a/docs/content/8.references/3.events.md
+++ b/docs/content/8.references/3.events.md
@@ -7,7 +7,7 @@ description: 'Devframe carries change notifications through client contexts, nod
Devframe carries change notifications through client contexts, node event buses, RPC, broadcasts, and shared state.
-Two prefixes mark the wire protocol: `hub:` for hub-layer server RPC (client → server), `devframe:` for the client-facing protocol (server → client). The internal event bus mirrors the subsystem vocabulary (`docks`, `terminals`, `messages`, `commands`) — `docks:activate` fans out to `devframe:docks:activate`.
+Two prefixes mark the wire protocol: `hub:` for hub-layer server RPC (client → server), `devframe:` for the client-facing protocol (server → client). The internal event bus mirrors the subsystem vocabulary (`docks`, `terminals`, `messages`, `commands`): `docks:activate` fans out to `devframe:docks:activate`.
Each name lives in code: [`HUB_EVENTS`](https://github.com/devframes/devframe/blob/main/packages/hub/src/events.ts) (`@devframes/hub/constants`) backs the hub tables, [`DEVFRAME_EVENTS`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/events.ts) (`devframe/constants`) the core ones.
@@ -32,14 +32,14 @@ Each subsystem emits on `ctx..events`, consumed **inside the same nod
| `docks:entry:updated` | `DocksHost.register` / `update` | context → `devframe:docks` shared state | `DevframeDockUserEntry` |
| `docks:activate` | `DocksHost.activate()` | context → broadcast + `devframe:docks:active` | `DevframeDockActivation` |
| `terminals:session:updated` | `TerminalsHost` register / update / remove / status change | context → `devframe:terminals:updated`; the terminals devframe | `DevframeTerminalSession` |
-| `messages:added` / `messages:updated` / `messages:removed` / `messages:cleared` | `MessagesHost` mutations | context → `devframe:messages:updated`; the messages devframe | entry / entry / id / — |
+| `messages:added` / `messages:updated` / `messages:removed` / `messages:cleared` | `MessagesHost` mutations | context → `devframe:messages:updated`; the messages devframe | entry / entry / id / none |
| `commands:registered` / `commands:unregistered` | `CommandsHost` register / update / unregister | context → `devframe:commands` shared state | entry / id |
-### Server RPC methods — client → server
+### Server RPC methods (client → server)
| Method | Signature | Purpose |
|---|---|---|
-| `hub:docks:activate` | `({ dockId, params? }) => void` | Ask the hub UI provider to switch its active dock — see [Deep Linking](/guide/deep-linking). |
+| `hub:docks:activate` | `({ dockId, params? }) => void` | Ask the hub UI provider to switch its active dock; see [Deep Linking](/guide/deep-linking). |
| `hub:commands:execute` | `(id, ...args) => unknown` | Invoke a registered server command by id. |
| `hub:messages:add` | `(input) => DevframeMessageEntry` | Add a message to the feed (marked `from: 'browser'`). |
| `hub:messages:update` | `(id, patch) => DevframeMessageEntry \| undefined` | Patch a message by id. |
@@ -51,13 +51,13 @@ Each subsystem emits on `ctx..events`, consumed **inside the same nod
| `hub:terminals:restart` | `(id) => void` | Re-run a session's command in place. |
| `hub:terminals:remove` | `(id) => void` | Kill a session's process and drop it from the registry. |
-### Broadcasts & shared state — server → client
+### Broadcasts & shared state (server → client)
A hub-aware RPC client reads or subscribes via `rpc.client.register(...)`; the [client runtime](/guide/client-context) registers the `devframe:docks:activate` handler for you.
| Name | Kind | Carries |
|---|---|---|
-| `devframe:docks:activate` | broadcast | Live "switch active dock" request — the client runtime calls its local `switchEntry`. |
+| `devframe:docks:activate` | broadcast | Live "switch active dock" request; the client runtime calls its local `switchEntry`. |
| `devframe:terminals:updated` | broadcast | Terminal sessions changed; re-read terminal state. |
| `devframe:messages:updated` | broadcast | Message list changed; re-read message state. |
| `devframe:docks` | shared state | Projected dock entry list (`DevframeDockEntry[]`). |
@@ -76,7 +76,7 @@ Emitted on `ctx.agent.events`; adapters (e.g. the MCP server) re-publish their m
| Event | Emitted by | Payload |
|---|---|---|
-| `agent:manifest:changed` | any tool/resource/provider change | — |
+| `agent:manifest:changed` | any tool/resource/provider change | none |
| `agent:tool:registered` / `agent:tool:unregistered` | `registerTool` / `unregisterTool` | `AgentTool` / id |
| `agent:resource:registered` / `agent:resource:unregistered` | `registerResource` / `unregisterResource` | `AgentResource` / id |
@@ -91,7 +91,7 @@ Emitted on the RPC client's `rpc.events` (`RpcClientEvents`) to track connection
| `connection:status` | Connection status changed (`status`, `previous`). |
| `connection:error` | A connection-level error (WebSocket errored, or trust refused). |
-### Broadcasts — server → client
+### Broadcasts (server → client)
Pushed to subscribed RPC clients, wired by the core node side.
@@ -104,7 +104,7 @@ Pushed to subscribed RPC clients, wired by the core node side.
| `devframe:streaming:end` | A streaming terminator (optionally an error). |
| `devframe:streaming:upload-cancel` | Server-side cancel of an in-flight upload. |
-### In-page channel notifications — page script → panel
+### In-page channel notifications (page script → panel)
Pushed over each panel's [in-page channel](/guide/in-page-channel) port; the paired request methods (`devframe:in-page:page-state:subscribe`/`set`/`patch`) are call endpoints defined at their handlers, not events.
diff --git a/docs/content/8.references/4.node-api.md b/docs/content/8.references/4.node-api.md
index 87ca32b3f..ab61b81f0 100644
--- a/docs/content/8.references/4.node-api.md
+++ b/docs/content/8.references/4.node-api.md
@@ -9,7 +9,7 @@ Lookup tables for a devframe's node side. Each section links the guide page that
## Definition fields
-The fields of a `DevframeDefinition` — [Devframe Definition](/guide/devframe-definition).
+The fields of a `DevframeDefinition`: [Devframe Definition](/guide/devframe-definition).
| Field | Type | Description |
|-------|------|-------------|
@@ -17,22 +17,22 @@ The fields of a `DevframeDefinition` — [Devframe Definition](/guide/devframe-d
| `name` | `string` | **Required.** Display name (dock, agent manifests). |
| `version` | `string` | **Required.** Semver; shown in hub UIs, diagnostics. |
| `packageName` | `string` | **Required.** npm package (`@scope/my-tool`). |
-| `importMetaUrl` | `string` | **Recommended.** Pass `import.meta.url` — the deps resolution base: default `resolveFrom` for [remote assets](/guide/client-assets) and declared [services](/guide/services#wire-services). |
+| `importMetaUrl` | `string` | **Recommended.** Pass `import.meta.url`, the deps resolution base: default `resolveFrom` for [remote assets](/guide/client-assets) and declared [services](/guide/services#wire-services). |
| `homepage` | `string` | **Required.** Homepage/docs URL. |
| `description` | `string` | **Required.** One-line summary. |
| `icon` | `string \| { light, dark }` | Optional Iconify name or URL; light/dark pairs. |
| `basePath` | `string` | Optional mount-path override. Default `/` standalone (`cli`/`build`), `/__/` hosted (`vite`/`embedded`). |
| `duplicationStrategy` | `'warn' \| 'silent' \| 'throw' \| 'duplicate'` | Hub reaction when another devframe shares this `id`. Default `'warn'`. See [Duplication strategies](/references/hub-api#duplication-strategies); standalone adapters ignore it. |
| `capabilities` | `{ dev?, build? }` | Per-runtime feature flags. `boolean` = whole runtime; object = individual features. |
-| `services` | `DevframeServiceInput[]` | Wire services consumed — descriptors (`{ package, version?, required?, options? }`) imported against the devframe's own deps, or ready definitions. See [Cross-Devframe Services](/guide/services#wire-services). |
-| `clientAssets` | `string \| RemoteAssets` | Built SPA served as the UI — local dist dir or [remote assets](/guide/client-assets). Read by every UI-serving adapter (`dev`, `build`, `vite`, `next`, hub). |
+| `services` | `DevframeServiceInput[]` | Wire services consumed: descriptors (`{ package, version?, required?, options? }`) imported against the devframe's own deps, or ready definitions. See [Cross-Devframe Services](/guide/services#wire-services). |
+| `clientAssets` | `string \| RemoteAssets` | Built SPA served as the UI: local dist dir or [remote assets](/guide/client-assets). Read by every UI-serving adapter (`dev`, `build`, `vite`, `next`, hub). |
| `rpc` | `{ snapshot?: (string \| { method, inputs })[] }` | RPC config. `rpc.snapshot` opts an RPC this devframe doesn't own into the static dump. Bare method id bakes the no-arg call; `{ method, inputs }` bakes one record per argument-tuple (`inputs` = tuples or async `(ctx) => tuples`). First tuple = fallback. |
-| `setup` | `(ctx, info?) => void \| Promise` | **Required.** Server-side entry point, run in every runtime. Optional 2nd arg carries runtime metadata — notably parsed CLI `flags` under `createCac`. |
+| `setup` | `(ctx, info?) => void \| Promise` | **Required.** Server-side entry point, run in every runtime. Optional 2nd arg carries runtime metadata, notably parsed CLI `flags` under `createCac`. |
| `cli` | `DevframeCliOptions` | CLI adapter defaults. See [CLI options](#cli-options). |
## CLI options
-The `cli` field's `DevframeCliOptions` — [CLI options](/guide/devframe-definition#cli-options).
+The `cli` field's `DevframeCliOptions`: [CLI options](/guide/devframe-definition#cli-options).
| Field | Type | Description |
|-------|------|-------------|
@@ -47,7 +47,7 @@ The `cli` field's `DevframeCliOptions` — [CLI options](/guide/devframe-definit
## Storage scopes
-The three classes `ctx.host.getStorageDir(scope)` places persisted state in — [Storage scopes](/guide/devframe-definition#storage-scopes).
+The three classes `ctx.host.getStorageDir(scope)` places persisted state in: [Storage scopes](/guide/devframe-definition#storage-scopes).
| Scope | Placement | For |
|-------|-----------|-----|
@@ -57,7 +57,7 @@ The three classes `ctx.host.getStorageDir(scope)` places persisted state in —
## RPC function types
-The `type` field of `defineRpcFunction` — [RPC](/guide/rpc).
+The `type` field of `defineRpcFunction`: [RPC](/guide/rpc).
| Type | Description | Cached | Static Dump |
|------|-------------|--------|-------------|
@@ -68,7 +68,7 @@ The `type` field of `defineRpcFunction` — [RPC](/guide/rpc).
## Broadcast options
-The options of `rpc.broadcast` — [Broadcasting](/guide/rpc#broadcasting).
+The options of `rpc.broadcast`: [Broadcasting](/guide/rpc#broadcasting).
| Option | Type | Description |
|--------|------|-------------|
@@ -80,18 +80,18 @@ The options of `rpc.broadcast` — [Broadcasting](/guide/rpc#broadcasting).
## Streaming lifecycle
-How each lifecycle event lands on both sides of a streaming channel — [Streaming](/guide/streaming#lifecycle-and-cancellation).
+How each lifecycle event lands on both sides of a streaming channel: [Streaming](/guide/streaming#lifecycle-and-cancellation).
| Event | Node side | Browser side |
|-------|--------|--------|
| `stream.close()` / `stream.error(err)` | broadcasts `end` | `for await` resolves or throws |
| `reader.cancel()` | aborts `stream.signal` on **last**-subscriber cancel | `for await` ends |
| WS disconnects | aborts `stream.signal` on **last**-subscriber drop | reader survives, resubscribes on re-trust |
-| `chat` panel closes | cancels upstream | — |
+| `chat` panel closes | cancels upstream | none |
## Remote assets options
-The fields of a `RemoteAssets` source for `clientAssets` and `hostStatic` — [Remote assets](/guide/client-assets#remote-assets).
+The fields of a `RemoteAssets` source for `clientAssets` and `hostStatic`: [Remote assets](/guide/client-assets#remote-assets).
| Field | Purpose |
|-------|---------|
@@ -104,21 +104,21 @@ The fields of a `RemoteAssets` source for `clientAssets` and `hostStatic` — [R
## `DevframeServicesHost`
-The methods on `ctx.services` — [Cross-Devframe Services](/guide/services#the-devframeserviceshost-api).
+The methods on `ctx.services`: [Cross-Devframe Services](/guide/services#the-devframeserviceshost-api).
| Method | Signature | Role |
|--------|-----------|------|
| `provide` | `(id, service) => revoke` | Publish an in-process service under a namespaced id. Throws [`DF0037`](/errors/DF0037) if the id is taken. |
| `get` | `(id) => service \| undefined` | The service currently provided under `id` (augmented type, else `unknown`). |
| `has` | `(id) => boolean` | Whether a service is provided under `id`. |
-| `whenAvailable` | `(id, cb) => unsubscribe` | Run `cb` as soon as the service exists — now if provided, else on `provide` — and re-fire on revoke/re-provide. |
+| `whenAvailable` | `(id, cb) => unsubscribe` | Run `cb` as soon as the service exists (now if provided, else on `provide`), and re-fire on revoke/re-provide. |
| `keys` | `() => string[]` | Ids of every currently-provided service. |
| `install` | `(input, options?) => Promise` | Install a [wire service](#wire-service-definition-fields) at runtime (the dynamic escape hatch; the common path is declarative). `options.resolveFrom` is the descriptor's resolution base. |
| `ready` | `() => Promise` | **Internal.** Construct every queued wire service before any `setup` runs. Adapters call it; application code uses declarative `services`. |
## Service tiers
-The two tiers a service can take — [Cross-Devframe Services](/guide/services).
+The two tiers a service can take: [Cross-Devframe Services](/guide/services).
| Tier | Shared how | Registers RPC | Advertised to clients |
|------|-----------|---------------|-----------------------|
@@ -127,11 +127,11 @@ The two tiers a service can take — [Cross-Devframe Services](/guide/services).
## Wire-service definition fields
-The fields of a `DevframeServiceDefinition` returned by a service package's `createService` factory — [Shipping a wire service](/guide/services#shipping-one).
+The fields of a `DevframeServiceDefinition` returned by a service package's `createService` factory: [Shipping a wire service](/guide/services#shipping-one).
| Field | Type | Description |
|-------|------|-------------|
-| `package` | `string` | **Required.** npm package name — also its registry key (`ctx.services.has(pkg)`). |
+| `package` | `string` | **Required.** npm package name, also its registry key (`ctx.services.has(pkg)`). |
| `version` | `string` | **Required.** Semver; advertised to clients, checked against declared ranges. |
| `scope` | `string` | **Required.** RPC namespace its functions register under (e.g. `devframes:service:open`); `setup` gets a context pre-scoped to it. |
| `meta` | `Record` | Extra advertised metadata (feature flags, defaults). Must be JSON-serializable. |
@@ -141,29 +141,29 @@ The fields of a `DevframeServiceDefinition` returned by a service package's `cre
## Wire-service descriptor fields
-The declarative reference form on `DevframeDefinition.services` / `initHub({ services })` — [Declaring services](/guide/services#declaring).
+The declarative reference form on `DevframeDefinition.services` / `initHub({ services })`: [Declaring services](/guide/services#declaring).
| Field | Type | Description |
|-------|------|-------------|
| `package` | `string` | **Required.** npm package name; its default export is the factory the host imports. |
| `version` | `string` | Accepted semver range. Unsatisfied warns ([`DF0069`](/errors/DF0069)), or throws ([`DF0068`](/errors/DF0068)) when `required`. |
-| `required` | `boolean` | Fail hard on a missing package ([`DF0067`](/errors/DF0067)) or unsatisfied range. Default `false` — a missing service is skipped and clients see `has() === false`. |
+| `required` | `boolean` | Fail hard on a missing package ([`DF0067`](/errors/DF0067)) or unsatisfied range. Default `false`: a missing service is skipped and clients see `has() === false`. |
| `options` | `Options` | Option set this installer contributes to the merge. |
## Advertised service meta
-Each installed service's entry in the `devframe:services` [shared state](/guide/shared-state), mirrored to RPC clients as `rpc.services` — [Feature-detecting on the RPC client](/guide/services#feature-detecting-on-the-rpc-client).
+Each installed service's entry in the `devframe:services` [shared state](/guide/shared-state), mirrored to RPC clients as `rpc.services`: [Feature-detecting on the RPC client](/guide/services#feature-detecting-on-the-rpc-client).
| Field | Description |
|-------|-------------|
-| `package` | npm package name — the registry key. |
+| `package` | npm package name, the registry key. |
| `version` | Installed version of the service. |
| `scope` | RPC namespace its functions live under. |
| `meta` | Extra service-declared metadata. |
## Diagnostic code prefixes
-Prefixes in use across the ecosystem — [Structured Diagnostics](/guide/diagnostics#code-conventions).
+Prefixes in use across the ecosystem: [Structured Diagnostics](/guide/diagnostics#code-conventions).
| Prefix | Owner |
|--------|-------|
@@ -174,18 +174,18 @@ Prefixes in use across the ecosystem — [Structured Diagnostics](/guide/diagnos
## Auth methods
-The wire-level RPC methods of the trust handshake — [Security](/guide/security#authentication-flow).
+The wire-level RPC methods of the trust handshake: [Security](/guide/security#authentication-flow).
| RPC method | Direction | Shape |
|------------|-----------|-------|
-| `anonymous:devframe:auth` | client → server | `{ authToken, ua, origin }` → `{ isTrusted }` — re-authenticate a stored token |
-| `anonymous:devframe:auth:exchange` | client → server | `{ code, ua, origin }` → `{ authToken \| null }` — exchange a code for a token |
+| `anonymous:devframe:auth` | client → server | `{ authToken, ua, origin }` → `{ isTrusted }`: re-authenticate a stored token |
+| `anonymous:devframe:auth:exchange` | client → server | `{ code, ua, origin }` → `{ authToken \| null }`: exchange a code for a token |
| `devframe:auth:revoke` | client → server | self-revoke the caller's own token |
-| `devframe:auth:revoked` | server → client | event — token revoked |
+| `devframe:auth:revoked` | server → client | event: token revoked |
## Node auth primitives
-The building blocks in `devframe/node/auth` — [Security](/guide/security#the-ready-made-layer).
+The building blocks in `devframe/node/auth`: [Security](/guide/security#the-ready-made-layer).
| Function | Role |
|----------|------|
@@ -197,10 +197,10 @@ The building blocks in `devframe/node/auth` — [Security](/guide/security#the-r
## MCP CLI commands
-The agent-facing CLI surface — [Agent-Native Devframe](/guide/agent-native).
+The agent-facing CLI surface: [Agent-Native Devframe](/guide/agent-native).
| Command | Description |
|---------|-------------|
| ` mcp` | Start the MCP server on `stdio`. |
| ` dev --mcp` | Serve the agent-consumable API on `/__mcp`. |
-| `devframe connect` | Discover running devframes and proxy their tools — see [MCP adapter](/adapters/mcp#discovery-devframe-connect). |
+| `devframe connect` | Discover running devframes and proxy their tools; see [MCP adapter](/adapters/mcp#discovery-devframe-connect). |
diff --git a/docs/content/8.references/5.browser-api.md b/docs/content/8.references/5.browser-api.md
index 044be5b1c..c7e43f8d0 100644
--- a/docs/content/8.references/5.browser-api.md
+++ b/docs/content/8.references/5.browser-api.md
@@ -9,7 +9,7 @@ Lookup tables for a devframe's browser side. Each section links the guide page t
## connectDevframe options
-The options of `connectDevframe()` / `getDevframeRpcClient()` — [Client](/guide/client).
+The options of `connectDevframe()` / `getDevframeRpcClient()`: [Client](/guide/client).
| Option | Description |
|--------|-------------|
@@ -18,24 +18,24 @@ The options of `connectDevframe()` / `getDevframeRpcClient()` — [Client](/guid
| `authToken` | Override the auth token (default: a locally-persisted id). |
| `cacheOptions` | `true` for default caching, or an options object. |
| `callTimeout` | Ms before a pending `rpc.call` rejects with a `'timeout'` `DevframeConnectionError`; `0`/omit = wait forever. |
-| `wsOptions` | Transport overrides — `onConnected` / `onError` / `onDisconnected` hooks, socket URL. |
+| `wsOptions` | Transport overrides: `onConnected` / `onError` / `onDisconnected` hooks, socket URL. |
| `rpcOptions` | Forwarded to `birpc`. |
| `connectionMeta` | Descriptor that skips the `__connection.json` fetch. |
## RPC client events
-Emitted over `rpc.events` — [Events](/guide/client#events).
+Emitted over `rpc.events`: [Events](/guide/client#events).
| Event | Fires when |
|-------|------------|
| `rpc:is-trusted:updated` | Trust granted, denied, or revoked. Carries the new `isTrusted` boolean. |
| `connection:status` | The [connection status](#connection-statuses) changes. Carries `(status, previous)`. |
-| `connection:error` | A connection-level failure — socket error or trust refused. Carries the `Error`. |
+| `connection:error` | A connection-level failure: socket error or trust refused. Carries the `Error`. |
| `rpc:error` | An `rpc.call` rejects, from the node side or a down connection. Carries `(error, method)`. |
## Connection statuses
-The values of `rpc.status` — [Handling connection and auth errors](/guide/client#handling-connection-and-auth-errors).
+The values of `rpc.status`: [Handling connection and auth errors](/guide/client#handling-connection-and-auth-errors).
| Status | Meaning |
|--------|---------|
@@ -43,17 +43,17 @@ The values of `rpc.status` — [Handling connection and auth errors](/guide/clie
| `connected` | Socket open and trusted; calls are served. |
| `unauthorized` | Socket open, trust refused. Prompt for [authentication](/guide/client#authenticating-with-a-one-time-code). |
| `disconnected` | Socket closed (dropped mid-session or never opened). |
-| `error` | Fatal — the socket errored or connection meta couldn't load. |
+| `error` | Fatal: the socket errored or connection meta couldn't load. |
## In-page channel error codes
-The `error.code` values of `InPageChannelError` — [Errors and fallbacks](/guide/in-page-channel#errors-and-fallbacks).
+The `error.code` values of `InPageChannelError`: [Errors and fallbacks](/guide/in-page-channel#errors-and-fallbacks).
| Code | When | What to do |
|------|------|------------|
-| `timeout` | A call outlived `callTimeoutMs` (default 15s), or `whenConnected(ms)` expired | The message carries the endpoint status — `connecting` usually means the page script isn't loaded in this context |
+| `timeout` | A call outlived `callTimeoutMs` (default 15s), or `whenConnected(ms)` expired | The message carries the endpoint status: `connecting` usually means the page script isn't loaded in this context |
| `closed` | The endpoint was closed with calls pending | Expected during teardown |
| `not-serializable` | A `jsonSerializable: true` payload contained a non-JSON value | The message names the offending path (e.g. `its arguments[0].nodes[2]` is a Map) |
-| `not-cloneable` | The port refused to clone a payload (`DataCloneError`) | Strip functions/DOM nodes/reactivity proxies — or declare `jsonSerializable: true` for the precise error above |
+| `not-cloneable` | The port refused to clone a payload (`DataCloneError`) | Strip functions/DOM nodes/reactivity proxies, or declare `jsonSerializable: true` for the precise error above |
| `invalid-args` | Incoming arguments failed their Standard-Schema validation | The message lists the schema issues |
| `state-uninitialized` | The page script read a shared state before providing its `initialValue` | Initialize on first access |
diff --git a/docs/content/8.references/6.hub-api.md b/docs/content/8.references/6.hub-api.md
index d7d2e1df3..035826dea 100644
--- a/docs/content/8.references/6.hub-api.md
+++ b/docs/content/8.references/6.hub-api.md
@@ -5,11 +5,11 @@ navigation:
description: 'Lookup tables for the hub: subsystems, launcher fields, duplication strategies, dock categories, the hub UI protocol, the namespace routes, the client runtime, the client context, and dock entry types.'
---
-Lookup tables for `@devframes/hub` — its node-side subsystems and its browser-side client runtime. Each section links the guide page that teaches the concept.
+Lookup tables for `@devframes/hub`: its node-side subsystems and its browser-side client runtime. Each section links the guide page that teaches the concept.
## Hub subsystems
-What `DevframeHubContext` adds to `DevframeNodeContext` — [Hub](/guide/hub).
+What `DevframeHubContext` adds to `DevframeNodeContext`: [Hub](/guide/hub).
| Subsystem | API | Purpose |
|---|---|---|
@@ -20,7 +20,7 @@ What `DevframeHubContext` adds to `DevframeNodeContext` — [Hub](/guide/hub).
## Launcher fields
-The optional `launcher` fields that make a `type: 'launcher'` dock entry a live process controller — [Process-control launchers](/guide/hub#process-control-launchers).
+The optional `launcher` fields that make a `type: 'launcher'` dock entry a live process controller: [Process-control launchers](/guide/hub#process-control-launchers).
| Field | Purpose |
|---|---|
@@ -30,7 +30,7 @@ The optional `launcher` fields that make a `type: 'launcher'` dock entry a live
## Duplication strategies
-The `duplicationStrategy` values deciding what happens when a devframe shares an already-mounted `id` — [Duplicate devframes](/guide/hub#duplicate-devframes).
+The `duplicationStrategy` values deciding what happens when a devframe shares an already-mounted `id`: [Duplicate devframes](/guide/hub#duplicate-devframes).
| Strategy | Behavior |
|---|---|
@@ -41,7 +41,7 @@ The `duplicationStrategy` values deciding what happens when a devframe shares an
## Dock categories
-`DEFAULT_CATEGORIES_ORDER` (from `@devframes/hub`, `/node`, `/client`, `/constants`) names the default dock-rail buckets — [The dual role of `category`](/guide/hub#the-dual-role-of-category).
+`DEFAULT_CATEGORIES_ORDER` (from `@devframes/hub`, `/node`, `/client`, `/constants`) names the default dock-rail buckets: [The dual role of `category`](/guide/hub#the-dual-role-of-category).
| Category | Weight | Typical use |
|---|---|---|
@@ -58,7 +58,7 @@ The `duplicationStrategy` values deciding what happens when a devframe shares an
## Hub UI protocol
-The shared-state keys and RPC methods a hub UI provider renders from — [The hub UI protocol](/guide/hub#the-hub-ui-protocol).
+The shared-state keys and RPC methods a hub UI provider renders from: [The hub UI protocol](/guide/hub#the-hub-ui-protocol).
| Channel | Type | What it carries |
|---|---|---|
@@ -71,7 +71,7 @@ The shared-state keys and RPC methods a hub UI provider renders from — [The hu
## Hub namespace routes
-What `initHub()` serves under its `base` — [The namespace](/guide/hub-initiate#the-namespace).
+What `initHub()` serves under its `base`: [The namespace](/guide/hub-initiate#the-namespace).
| Path | Serves |
| --- | --- |
@@ -86,34 +86,34 @@ What `initHub()` serves under its `base` — [The namespace](/guide/hub-initiate
## Client runtime options
-The options of `createDevframeClientRuntime()` — [The client runtime](/guide/client-context#the-client-runtime).
+The options of `createDevframeClientRuntime()`: [The client runtime](/guide/client-context#the-client-runtime).
| Option | Description |
|--------|-------------|
| `rpc` | An already-connected `DevframeRpcClient`; when omitted, created via `connectDevframe(connect)`. |
| `connect` | Forwarded to `connectDevframe` when `rpc` is omitted (e.g. `baseURL`). |
-| `clientType` | `'standalone'` (default) — owns the page; `'embedded'` — inside a user app alongside a panel. |
+| `clientType` | `'standalone'` (default) owns the page; `'embedded'` runs inside a user app alongside a panel. |
| `loadClientScripts` | Import and run dock client scripts (default `true`). |
| `renderers` | Dock renderers registered at boot, keyed by dock `type`; local wins over the hub's [renderer manifest](/guide/hub-initiate#renderer-modules). |
## Client context properties
-The properties of `DevframeClientContext` — [The client context](/guide/client-context#the-client-context).
+The properties of `DevframeClientContext`: [The client context](/guide/client-context#the-client-context).
| Property | Description |
|----------|-------------|
-| `rpc` | The [RPC client](/guide/client) — server/client functions, shared state. |
+| `rpc` | The [RPC client](/guide/client): server/client functions, shared state. |
| `clientType` | `'embedded'` (inside the user app) or `'standalone'` (independent hub page). |
| `docks` | `entries`, `selected`, `groupedEntries`, `switchEntry()`, `toggleEntry()`, `getStateById()`, `register()` / `update()` for [client-only docks](/guide/client-context#client-only-docks). |
| `panel` | Current `state`, local `events`, session, position, size, and drag/resize state for the dock panel. |
| `commands` | Command palette: `register()`, `execute()`, `getKeybindings()`. |
-| `renderers` | Dock-renderer registry — `register()`, `get()`, `has()`, `mount(entry, container)`. Routes a dock `type` to a renderer (local boot or the hub's [manifest](/guide/hub-initiate#renderer-modules); local wins). `mount()` resolves a `status`: `mounted` (with `dispose`), `missing-renderer`, or `load-error` (with `error`). |
+| `renderers` | Dock-renderer registry: `register()`, `get()`, `has()`, `mount(entry, container)`. Routes a dock `type` to a renderer (local boot or the hub's [manifest](/guide/hub-initiate#renderer-modules); local wins). `mount()` resolves a `status`: `mounted` (with `dispose`), `missing-renderer`, or `load-error` (with `error`). |
| `when` | The [when-clause](/references/when-clauses) context. |
-| `connection` | Live [connection status](/guide/client#handling-connection-and-auth-errors) — `status`, `error`, `events`. |
+| `connection` | Live [connection status](/guide/client#handling-connection-and-auth-errors): `status`, `error`, `events`. |
## Dock client script fields
-Which `ClientScriptEntry` field carries an entry's client script, and when it runs — [Dock client scripts](/guide/client-context#dock-client-scripts).
+Which `ClientScriptEntry` field carries an entry's client script, and when it runs: [Dock client scripts](/guide/client-context#dock-client-scripts).
| Entry kind | Field | Runs |
|---|---|---|
@@ -123,7 +123,7 @@ Which `ClientScriptEntry` field carries an entry's client script, and when it ru
## Frame-nav messages
-The origin-locked `postMessage` protocol on `devframe:frame-nav` — [Shared-iframe soft navigation](/guide/client-context#shared-iframe-soft-navigation).
+The origin-locked `postMessage` protocol on `devframe:frame-nav`: [Shared-iframe soft navigation](/guide/client-context#shared-iframe-soft-navigation).
| Message | Direction | Meaning |
|---|---|---|
@@ -133,7 +133,7 @@ The origin-locked `postMessage` protocol on `devframe:frame-nav` — [Shared-ifr
## Dock entry types
-The built-in variants of the open dock union (`DevframeDockEntryRegistry`, `@devframes/hub/types`) a hub UI provider renders — [Build Your Own Hub UI](/guide/build-your-own-hub-ui).
+The built-in variants of the open dock union (`DevframeDockEntryRegistry`, `@devframes/hub/types`) a hub UI provider renders: [Build Your Own Hub UI](/guide/build-your-own-hub-ui).
| Type | The hub UI provider renders |
|---|---|
diff --git a/docs/content/8.references/8.utilities.md b/docs/content/8.references/8.utilities.md
index 0bf24c074..7f7a38c7a 100644
--- a/docs/content/8.references/8.utilities.md
+++ b/docs/content/8.references/8.utilities.md
@@ -2,10 +2,10 @@
title: 'Utilities'
navigation:
icon: i-lucide-wrench
-description: 'Small, stable helpers under devframe/utils/* — bundled in, no npm install.'
+description: 'Small, stable helpers under devframe/utils/*, bundled in, no npm install.'
---
-Small, stable helpers under `devframe/utils/*` — bundled in, no `npm install`.
+Small, stable helpers under `devframe/utils/*`, bundled in, no `npm install`.
## Reference
@@ -91,8 +91,8 @@ Cryptographically-secure token helpers on WebCrypto (browser + Node).
```ts
import { randomDigits, randomToken, timingSafeEqual } from 'devframe/utils/crypto-token'
-randomToken() // 32-char hex, 128 bits of entropy — use as a bearer token
-randomDigits(6) // '047204' — uniform, leading zeros preserved
+randomToken() // 32-char hex, 128 bits of entropy; use as a bearer token
+randomDigits(6) // '047204', uniform, leading zeros preserved
timingSafeEqual(input, secret) // constant-time string comparison
```
@@ -120,12 +120,12 @@ const state = createSharedState({ initialValue: { count: 0 } })
state.mutate((draft) => {
draft.count += 1
})
-state.value() // { count: 1 }
+state.value() // => count is 1
```
### `devframe/utils/streaming-channel`
-Sink/reader primitives for streamed RPC payloads, via `ctx.rpc.streaming` — see [Streaming](/guide/streaming).
+Sink/reader primitives for streamed RPC payloads, via `ctx.rpc.streaming`; see [Streaming](/guide/streaming).
### `devframe/utils/when`
diff --git a/docs/content/8.references/index.md b/docs/content/8.references/index.md
index 476a9172e..bc01b8fa6 100644
--- a/docs/content/8.references/index.md
+++ b/docs/content/8.references/index.md
@@ -7,13 +7,13 @@ description: 'Lookup pages the guides link into: the canonical terms, the when-c
Lookup pages the guides link into:
-- [Terms](/references/terms) — the canonical vocabulary of these docs: one name per concept, with its anchoring API.
-- [When Clauses](/references/when-clauses) — the contexts and operators that gate docks, commands, and custom UI.
-- [Events Reference](/references/events) — every event, broadcast, shared-state key, and channel name, by direction and reach.
-- [Node-Side API](/references/node-api) — `DevframeDefinition` fields, CLI options, storage scopes, RPC function types, broadcast options, streaming lifecycle, remote assets, the `ctx.services` host and wire-service fields, diagnostics prefixes, and the auth surface.
-- [Browser-Side API](/references/browser-api) — `connectDevframe` options, RPC client events, connection statuses, and in-page channel error codes.
-- [Hub API](/references/hub-api) — hub subsystems, launcher fields, duplication strategies, dock categories, the hub UI protocol, the namespace routes, the client runtime, the client context, and dock entry types.
-- [Utilities](/references/utilities) — the small, stable helpers under `devframe/utils/*`, bundled into `devframe`.
-- [Interactive Auth](/references/interactive-auth) — the OTP auth recipe: handshake, resolver gate, connect-time trust, banner.
+- [Terms](/references/terms): the canonical vocabulary of these docs, one name per concept, with its anchoring API.
+- [When Clauses](/references/when-clauses): the contexts and operators that gate docks, commands, and custom UI.
+- [Events Reference](/references/events): every event, broadcast, shared-state key, and channel name, by direction and reach.
+- [Node-Side API](/references/node-api): `DevframeDefinition` fields, CLI options, storage scopes, RPC function types, broadcast options, streaming lifecycle, remote assets, the `ctx.services` host and wire-service fields, diagnostics prefixes, and the auth surface.
+- [Browser-Side API](/references/browser-api): `connectDevframe` options, RPC client events, connection statuses, and in-page channel error codes.
+- [Hub API](/references/hub-api): hub subsystems, launcher fields, duplication strategies, dock categories, the hub UI protocol, the namespace routes, the client runtime, the client context, and dock entry types.
+- [Utilities](/references/utilities): the small, stable helpers under `devframe/utils/*`, bundled into `devframe`.
+- [Interactive Auth](/references/interactive-auth): the OTP auth recipe: handshake, resolver gate, connect-time trust, banner.
The [error reference](/errors) documents each `DF*` diagnostic code, and [migrations](/migrations) each version step. The adapter, framework-kit, and add-on pages each carry their own package's options and RPC tables.
diff --git a/docs/content/9.posts/1.pluggable-extensible-playful-devtools.md b/docs/content/9.posts/1.pluggable-extensible-playful-devtools.md
index f1db75603..10e88f82b 100644
--- a/docs/content/9.posts/1.pluggable-extensible-playful-devtools.md
+++ b/docs/content/9.posts/1.pluggable-extensible-playful-devtools.md
@@ -56,7 +56,7 @@ import { inspectProject } from './rpc'
export default defineDevframe({
id: 'my-tool',
name: 'My Tool',
- // Package metadata and browser entry omitted...
+ /** Package metadata and browser entry omitted... */
setup(ctx) {
ctx.scope('my-tool').rpc.register(inspectProject)
},
@@ -104,7 +104,7 @@ import { createDevServer } from 'devframe/adapters/dev'
import { createMcpServer } from 'devframe/adapters/mcp'
import myDevframe from './my-tool'
-// Pick the entry points your package needs:
+/** Pick the entry points your package needs: */
export const runCli = () => createCac(myDevframe).parse()
export const startServer = () => createDevServer(myDevframe)
export const vitePlugin = createPluginFromDevframe(myDevframe)
@@ -247,18 +247,22 @@ import { createTerminalsDevframe } from '@devframes/plugin-terminals'
import { createXxxDevframe } from '...'
const hub = initHub({
- // The common base path for all mounted devframes.
- // `/__my-tool/` becomes `/__devframes/__my-tool/`.
+ /**
+ * The common base path for all mounted devframes.
+ * `/__my-tool/` becomes `/__devframes/__my-tool/`.
+ */
base: '/__devframes/',
- // The devframes are mounted into the hub.
+ /** The devframes are mounted into the hub. */
devframes: [
createTerminalsDevframe(),
createXxxDevframe(),
// ...
],
- // We ship a reference UI to make it easy to get started,
- // but you can provide your own layer to match
- // your product's design system and interaction model.
+ /**
+ * We ship a reference UI to make it easy to get started,
+ * but you can provide your own layer to match
+ * your product's design system and interaction model.
+ */
ui: await import('@devframes/hub-ui').then(m => m.createUi()),
})
diff --git a/docs/content/index.md b/docs/content/index.md
index 1b5ed7a8a..342bf12c1 100644
--- a/docs/content/index.md
+++ b/docs/content/index.md
@@ -63,7 +63,7 @@ A framework-neutral foundation for devtools. One definition becomes a Web Standa
target: _blank
class: 'max-w-3xl mx-auto mt-[-10]'
---
- Read the announcement — **Pluggable, Extensible, and Playful DevTools** — for the vision behind devframe.
+ Read the announcement, **Pluggable, Extensible, and Playful DevTools**, for the vision behind devframe.
:::
::
-->
@@ -76,7 +76,7 @@ Foundation
One definition, every entry point
#description
-`defineDevframe()` describes a tool once. `initDevframe()` turns it into a Web Standard `Request → Response` handler — and adapters reshape that same definition into whatever your package ships.
+`defineDevframe()` describes a tool once. `initDevframe()` turns it into a Web Standard `Request → Response` handler, and adapters reshape that same definition into whatever your package ships.
#default
:::landing-feature-card{icon="i-lucide-puzzle" to="/adapters/initiate"}
@@ -108,7 +108,7 @@ One definition, every entry point
Visual and Agentic
#description
- Expose the same internal state to a web UI and to coding agents over MCP — one source of truth, two interfaces.
+ Expose the same internal state to a web UI and to coding agents over MCP: one source of truth, two interfaces.
:::
:::landing-feature-card{icon="i-lucide-layout-dashboard" to="/guide/hub"}
@@ -124,7 +124,7 @@ One definition, every entry point
Built-in Devframes, Any Framework
#description
- The built-in devframes span Vue, Svelte, Solid, and React — devframe owns the protocol and leaves the UI framework to the author.
+ The built-in devframes span Vue, Svelte, Solid, and React: devframe owns the protocol and leaves the UI framework to the author.
:::
::
@@ -152,7 +152,7 @@ Portability
The same handler, mounted natively
#description
-A devframe's boundary is simply the Web Standard `Request` and `Response`. Any framework that speaks that — or connect-style middleware — mounts the same tool and inherits the whole ecosystem. Only the host-framework-facing glue changes. [See all adapters](/adapters/initiate).
+A devframe's boundary is simply the Web Standard `Request` and `Response`. Any framework that speaks that (or connect-style middleware) mounts the same tool and inherits the whole ecosystem. Only the host-framework-facing glue changes. [See all adapters](/adapters/initiate).
#code-0
```ts [server.ts]
@@ -217,7 +217,7 @@ Adapters
Package it the way your tool ships
#description
-The handler is the smallest common denominator. Higher-level adapters package that same definition into familiar forms — pick the entry points your package needs. [Browse the adapters](/adapters).
+The handler is the smallest common denominator. Higher-level adapters package that same definition into familiar forms; pick the entry points your package needs. [Browse the adapters](/adapters).
#code-0
```ts [cli.ts]
@@ -270,7 +270,7 @@ Interfaces
One capability, two interfaces
#description
-RPC functions stay private by default and opt into agent exposure explicitly. The [MCP adapter](/adapters/mcp) translates those functions, resources, and selected shared state into an agent-consumable interface — the presentation changes, the source of truth stays the same.
+RPC functions stay private by default and opt into agent exposure explicitly. The [MCP adapter](/adapters/mcp) translates those functions, resources, and selected shared state into an agent-consumable interface: the presentation changes, the source of truth stays the same.
#code-0
```ts [rpc.ts]
@@ -288,7 +288,7 @@ RPC functions stay private by default and opt into agent exposure explicitly. Th
export const inspectBuild = defineRpcFunction({
name: 'inspect-build',
type: 'query',
- // opt this capability into agent exposure
+ /** opt this capability into agent exposure */
agent: { description: 'Read the current build graph and chunk sizes.' },
handler: () => readBuildGraph(),
})
@@ -364,6 +364,6 @@ links:
Ship your devtool everywhere
#description
-Start from one `DevframeDefinition` and pick the entry points your package ships — hosted, standalone, embedded, or agentic.
+Start from one `DevframeDefinition` and pick the entry points your package ships: hosted, standalone, embedded, or agentic.
::
diff --git a/docs/nuxt.config.ts b/docs/nuxt.config.ts
index a3483adb5..0bdfefa82 100644
--- a/docs/nuxt.config.ts
+++ b/docs/nuxt.config.ts
@@ -3,8 +3,10 @@ import process from 'node:process'
export default defineNuxtConfig({
compatibilityDate: '2026-08-21',
- // Develop against a local checkout of the layer:
- // COMARK_DOCS_LAYER=../../comark-docs pnpm docs
+ /**
+ * Develop against a local checkout of the layer:
+ * COMARK_DOCS_LAYER=../../comark-docs pnpm docs
+ */
extends: [process.env.COMARK_DOCS_LAYER || 'comark-docs'],
css: [
@@ -21,11 +23,11 @@ export default defineNuxtConfig({
domain: 'https://devfra.me',
title: 'Devframe',
description:
- 'Framework-neutral foundation for building devtools — one definition becomes a Web Standard handler, a CLI, a static report, an MCP server, or a hub dock.',
+ 'Framework-neutral foundation for building devtools: one definition becomes a Web Standard handler, a CLI, a static report, an MCP server, or a hub dock.',
full: {
title: 'Devframe Documentation',
description:
- 'Complete Devframe documentation as plain markdown — guide, adapters, frameworks, add-ons, references, and the error reference.',
+ 'Complete Devframe documentation as plain markdown: guide, adapters, frameworks, add-ons, references, and the error reference.',
},
},
diff --git a/eslint.config.js b/eslint.config.js
index 2f6e13900..7a1a7a0cd 100644
--- a/eslint.config.js
+++ b/eslint.config.js
@@ -1,25 +1,46 @@
// @ts-check
-import antfu from '@antfu/eslint-config'
+import antfu, { parserPlain } from '@antfu/eslint-config'
-export default antfu({
- pnpm: true,
- ignores: [
- 'skills',
- 'plans',
- '**/dist',
- '**/storybook-static',
- '**/.next',
- '**/.nitro',
- '**/.output',
- '**/out',
- '**/next-env.d.ts',
- '**/.nuxt',
- ],
-}, {
- // MDC component syntax (`::u-page-hero`, `#title` slot markers) is not
- // ATX-heading markdown - don't lint it as such.
- files: ['docs/content/**/*.md'],
- rules: {
- 'markdown/no-missing-atx-heading-space': 'off',
+export default antfu(
+ {
+ pnpm: true,
+ antislop: {
+ slop: {
+ inspection: 'full',
+ },
+ },
+ ignores: [
+ 'skills',
+ 'plans',
+ '**/dist',
+ '**/storybook-static',
+ '**/.next',
+ '**/.nitro',
+ '**/.output',
+ '**/out',
+ '**/next-env.d.ts',
+ '**/.nuxt',
+ ],
},
-})
+ {
+ /**
+ * The antislop `no-em-dash` rule scans every source glob, including CSS,
+ * HTML, and Vue/Svelte `
-
@@ -33,7 +33,7 @@ const meta = {
export default meta
type Story = StoryObj
-/** Ready — the editor fills the panel, with no chrome over it. */
+/** Ready: the editor fills the panel, with no chrome over it. */
export const Running: Story = {
args: {
connect: { url: MOCK_EDITOR },
diff --git a/plugins/code-server/src/spa/components/LauncherView.stories.ts b/plugins/code-server/src/spa/components/LauncherView.stories.ts
index a6ab37bba..bf0fe2100 100644
--- a/plugins/code-server/src/spa/components/LauncherView.stories.ts
+++ b/plugins/code-server/src/spa/components/LauncherView.stories.ts
@@ -15,7 +15,7 @@ const meta = {
title: 'Code Server/LauncherView',
component: LauncherView,
parameters: { layout: 'fullscreen' },
- // The view is absolutely positioned; give it a full-height relative host.
+ /** The view is absolutely positioned; give it a full-height relative host. */
render: args => ({
components: { LauncherView },
setup: () => ({ args }),
@@ -36,7 +36,7 @@ export const Connecting: Story = {
},
}
-/** No editor binary found — install instructions and links. */
+/** No editor binary found, showing install instructions and links. */
export const NotInstalled: Story = {
args: {
phase: 'not-installed',
@@ -46,7 +46,7 @@ export const NotInstalled: Story = {
},
}
-/** Installed and idle — the launch screen (code-server backend). */
+/** Installed and idle, showing the launch screen (code-server backend). */
export const Launch: Story = {
args: {
phase: 'launch',
@@ -66,7 +66,7 @@ export const LaunchServeWeb: Story = {
},
}
-/** A previous launch failed — the error surfaces above the launch button. */
+/** A previous launch failed, so the error surfaces above the launch button. */
export const LaunchError: Story = {
args: {
phase: 'launch',
diff --git a/plugins/code-server/src/spa/components/LauncherView.vue b/plugins/code-server/src/spa/components/LauncherView.vue
index 1de8fb8b1..3582cd858 100644
--- a/plugins/code-server/src/spa/components/LauncherView.vue
+++ b/plugins/code-server/src/spa/components/LauncherView.vue
@@ -147,7 +147,7 @@ const errorText = computed(() => (props.server.status === 'error' ? props.server
{{ detection.mode === 'tunnel'
? 'Open a code tunnel and edit this workspace from the hosted vscode.dev editor, right here.'
- : 'Start an editor scoped to this workspace and open VS Code right here — signed in automatically.' }}
+ : 'Start an editor scoped to this workspace and open VS Code right here, signed in automatically.' }}
{
// Reflect the live connection: a dropped socket or refused auth swaps the
// panel to a clear state instead of leaving a stale/blank editor.
client.events.on('connection:status', () => applyStatus(client))
- // Best-effort trust handshake — shared-state subscription needs it, so kick
+ // Best-effort trust handshake, which shared-state subscription needs, so kick
// it off and ignore failures/timeouts on the single-user standalone server.
if (client.connectionMeta.backend === 'websocket')
client.ensureTrusted(5000).catch(() => {})
diff --git a/plugins/code-server/src/spa/vite.config.ts b/plugins/code-server/src/spa/vite.config.ts
index 12ab261ba..f52f449f6 100644
--- a/plugins/code-server/src/spa/vite.config.ts
+++ b/plugins/code-server/src/spa/vite.config.ts
@@ -6,14 +6,16 @@ import { defineConfig } from 'vite'
import { alias } from '../../../../alias'
import { createCodeServerDevframe } from '../index'
-// The launcher SPA. `base: './'` keeps every asset URL relative so the bundle
-// is mount-path portable — it discovers its runtime base from
-// `document.baseURI` and connects via `connectDevframe()`. The build is copied
-// verbatim by `createBuild`; no HTML rewriting.
-//
-// `devframeViteBridge()` runs a side-car devframe RPC + WS server during
-// `vite dev` so the launcher can detect/start/stop the editor while Vite
-// serves the UI source with HMR.
+/**
+ * The launcher SPA. `base: './'` keeps every asset URL relative so the bundle
+ * is mount-path portable, discovering its runtime base from
+ * `document.baseURI` and connecting via `connectDevframe()`. The build is copied
+ * verbatim by `createBuild`; no HTML rewriting.
+ *
+ * `devframeViteBridge()` runs a side-car devframe RPC + WS server during
+ * `vite dev` so the launcher can detect/start/stop the editor while Vite
+ * serves the UI source with HMR.
+ */
export default defineConfig({
base: './',
root: fileURLToPath(new URL('.', import.meta.url)),
@@ -23,8 +25,10 @@ export default defineConfig({
UnoCSS(),
devframeViteBridge(createCodeServerDevframe(), { base: '/' }),
],
- // `@antfu/design` ships raw `.ts`/`.vue`; let `@vitejs/plugin-vue` compile its
- // SFCs instead of esbuild pre-bundling them.
+ /**
+ * `@antfu/design` ships raw `.ts`/`.vue`; let `@vitejs/plugin-vue` compile its
+ * SFCs instead of esbuild pre-bundling them.
+ */
optimizeDeps: { exclude: ['@antfu/design'] },
build: {
outDir: fileURLToPath(new URL('../../assets-pkg/dist', import.meta.url)),
diff --git a/plugins/code-server/src/types.ts b/plugins/code-server/src/types.ts
index 8d42e9200..c2cfab5e0 100644
--- a/plugins/code-server/src/types.ts
+++ b/plugins/code-server/src/types.ts
@@ -4,11 +4,11 @@ export type CodeServerStatus = 'stopped' | 'starting' | 'running' | 'error'
/**
* Which editor server binary the plugin launches in `mode: 'local'`:
*
- * - `'code-server'` — Coder's open-source
+ * - `'code-server'`: Coder's open-source
* [code-server](https://github.com/coder/code-server) (`code-server …`). The
* plugin runs it with password auth and hands the client a session cookie, so
* the embedded editor opens already signed in.
- * - `'ms-code-serve-web'` — Microsoft's official
+ * - `'ms-code-serve-web'`: Microsoft's official
* [`code serve-web`](https://code.visualstudio.com/docs/remote/vscode-server)
* (ships with the `code` CLI). The plugin generates a connection token and
* hands it to the client as a `?tkn=` query parameter.
@@ -18,9 +18,9 @@ export type CodeServerBackend = 'code-server' | 'ms-code-serve-web'
/**
* How the editor is served:
*
- * - `'local'` — a local server ({@link CodeServerBackend}) embedded from this
+ * - `'local'`: a local server ({@link CodeServerBackend}) embedded from this
* machine's origin.
- * - `'tunnel'` — Microsoft's `code tunnel`, which registers a remote tunnel and
+ * - `'tunnel'`: Microsoft's `code tunnel`, which registers a remote tunnel and
* embeds the hosted `vscode.dev` editor. First launch prints a device-login
* prompt (surfaced as {@link CodeServerLogin}); authentication is handled by
* `vscode.dev` itself, not this plugin.
@@ -75,7 +75,7 @@ export interface CodeServerServerInfo {
/**
* The full shared-state payload broadcast to subscribed clients. Deliberately
- * carries no authentication material — see {@link CodeServerConnect}.
+ * carries no authentication material; see {@link CodeServerConnect}.
*/
export interface CodeServerSharedState {
detection: CodeServerDetection
@@ -85,7 +85,7 @@ export interface CodeServerSharedState {
/**
* How the client reaches the running editor. May carry a secret (session
* cookie or connection token), so it is returned only from the `start` /
- * `status` RPCs to the already-authorized client — never published to shared
+ * `status` RPCs to the already-authorized client, never published to shared
* state.
*
* - `url` set → embed it verbatim (tunnel mode's `vscode.dev` URL).
@@ -102,12 +102,12 @@ export interface CodeServerConnect {
cookie?: { name: string, value: string }
}
-/** Result of the `status` query — shared state plus connect info when running. */
+/** Result of the `status` query: shared state plus connect info when running. */
export interface CodeServerStatusResult extends CodeServerSharedState {
connect?: CodeServerConnect
}
-/** Result of the `start` action — identical shape to {@link CodeServerStatusResult}. */
+/** Result of the `start` action, identical shape to {@link CodeServerStatusResult}. */
export type CodeServerStartResult = CodeServerStatusResult
/** Wire payload for the `start` RPC. */
@@ -176,7 +176,7 @@ export interface CodeServerOptions {
random?: boolean
/**
* Require the trust handshake on the standalone launcher server. Enabled
- * by default — `--open` embeds the current OTP in the opened URL, so the
+ * by default; `--open` embeds the current OTP in the opened URL, so the
* tab authenticates automatically without extra prompts. Hosted adapters
* manage their own auth and ignore this.
*/
diff --git a/plugins/code-server/test/_utils.ts b/plugins/code-server/test/_utils.ts
index c67d67f95..458f1ab58 100644
--- a/plugins/code-server/test/_utils.ts
+++ b/plugins/code-server/test/_utils.ts
@@ -7,7 +7,7 @@ import { join } from 'node:path'
import process from 'node:process'
import { createHostContext } from 'devframe/node'
-/** Minimal in-memory host — enough to drive RPC + shared state in tests. */
+/** Minimal in-memory host, enough to drive RPC + shared state in tests. */
function createTestHost(): DevframeHost {
return {
mountStatic: () => {},
diff --git a/plugins/code-server/test/code-server.test.ts b/plugins/code-server/test/code-server.test.ts
index 65d89e338..18a6f9fb6 100644
--- a/plugins/code-server/test/code-server.test.ts
+++ b/plugins/code-server/test/code-server.test.ts
@@ -76,7 +76,7 @@ describe('@devframes/plugin-code-server', () => {
expect(result.connect?.path).toBe('/')
// The cookie value handed to the client must equal HASHED_PASSWORD the
- // server was launched with — that is what makes the iframe auto-auth.
+ // server was launched with; that is what makes the iframe auto-auth.
const hashed = readFileSync(dumpEnvTo, 'utf8')
expect(hashed).toBe(result.connect?.cookie?.value)
@@ -206,7 +206,7 @@ describe('@devframes/plugin-code-server', () => {
const bin = writeFakeCodeServer({ version: '4.99.0', dumpEnvTo })
const ctx = await createTestContext()
const terminals = createFakeHubTerminals()
- ;(ctx as unknown as { terminals: typeof terminals }).terminals = terminals
+ ;(ctx as { terminals?: typeof terminals }).terminals = terminals
const supervisor = await setupCodeServer(ctx, { bin })
supervisors.push(supervisor)
@@ -236,7 +236,7 @@ describe('@devframes/plugin-code-server', () => {
const bin = writeFakeCodeServer({ version: '4.99.0' })
const ctx = await createTestContext()
const terminals = createFakeHubTerminals()
- ;(ctx as unknown as { terminals: typeof terminals }).terminals = terminals
+ ;(ctx as { terminals?: typeof terminals }).terminals = terminals
const supervisor = await setupCodeServer(ctx, { bin })
supervisors.push(supervisor)
diff --git a/plugins/code-server/tsdown.config.ts b/plugins/code-server/tsdown.config.ts
index 2e6c0f34d..5c2b73e5d 100644
--- a/plugins/code-server/tsdown.config.ts
+++ b/plugins/code-server/tsdown.config.ts
@@ -11,14 +11,14 @@ const deps = {
],
}
-// Browser-loaded module — the launcher/iframe shell. Kept in its own
+// Browser-loaded module: the launcher/iframe shell. Kept in its own
// rolldown graph so the node-only supervisor never leaks into the client
// bundle.
const clientEntries = {
'client/index': 'src/client/index.ts',
}
-// Node + neutral modules — the devframe definition/factory, RPC functions,
+// Node + neutral modules: the devframe definition/factory, RPC functions,
// the code-server supervisor, and the host adapters.
const serverEntries = {
'index': 'src/index.ts',
@@ -30,11 +30,13 @@ const serverEntries = {
'types': 'src/types.ts',
}
-// Three configs, mirroring `packages/devframe/tsdown.config.ts`:
-// 1. browser client build (independent graph, `.mjs`),
-// 2. node server build (appends to the same dist/),
-// 3. combined dts so `declare module 'devframe'` augmentations resolve
-// across every entry.
+/**
+ * Three configs, mirroring `packages/devframe/tsdown.config.ts`:
+ * 1. browser client build (independent graph, `.mjs`),
+ * 2. node server build (appends to the same dist/),
+ * 3. combined dts so `declare module 'devframe'` augmentations resolve
+ * across every entry.
+ */
export default defineConfig([
{
clean: true,
diff --git a/plugins/code-server/uno.config.ts b/plugins/code-server/uno.config.ts
index 2929b5ad7..7207ce2ee 100644
--- a/plugins/code-server/uno.config.ts
+++ b/plugins/code-server/uno.config.ts
@@ -1,10 +1,12 @@
import { mergeConfigs } from 'unocss'
import { designConfig } from '../../design/uno.config'
-// The code-server launcher composes the shared devframe base (see
-// `design/uno.config.ts`) and adds only its own extraction globs. Vue templates
-// are scanned by default; `.ts` is opted in for class strings authored in
-// composables/helpers. The SPA and Storybook generate CSS from this config.
+/**
+ * The code-server launcher composes the shared devframe base (see
+ * `design/uno.config.ts`) and adds only its own extraction globs. Vue templates
+ * are scanned by default; `.ts` is opted in for class strings authored in
+ * composables/helpers. The SPA and Storybook generate CSS from this config.
+ */
export default mergeConfigs([
designConfig,
{
diff --git a/plugins/data-inspector/.storybook/main.ts b/plugins/data-inspector/.storybook/main.ts
index 28cbadfa5..43fc9da03 100644
--- a/plugins/data-inspector/.storybook/main.ts
+++ b/plugins/data-inspector/.storybook/main.ts
@@ -16,8 +16,10 @@ const config: StorybookConfig = {
return mergeConfig(config, {
resolve: { alias },
plugins: [vue(), UnoCSS()],
- // Dev tool reached from arbitrary hostnames (LAN IPs, tunnels,
- // tailnets), e.g. when iframed by the storybook hub.
+ /**
+ * Dev tool reached from arbitrary hostnames (LAN IPs, tunnels,
+ * tailnets), e.g. when iframed by the storybook hub.
+ */
server: { allowedHosts: true },
})
},
diff --git a/plugins/data-inspector/.storybook/preview.ts b/plugins/data-inspector/.storybook/preview.ts
index bab616f23..f7ff9c3f6 100644
--- a/plugins/data-inspector/.storybook/preview.ts
+++ b/plugins/data-inspector/.storybook/preview.ts
@@ -5,7 +5,7 @@ import '../src/spa/style.css'
// Drive the shared `@antfu/design` tokens off the toolbar theme toggle: dark mode
// is the `.dark` class on ``, and the canvas takes the semantic
-// `bg-base`/`color-base` surface — matching every other devframe surface.
+// `bg-base`/`color-base` surface, matching every other devframe surface.
function applyTheme(theme: string): void {
document.documentElement.classList.toggle('dark', theme !== 'light')
document.body.classList.add('bg-base', 'color-base', 'font-sans')
diff --git a/plugins/data-inspector/README.md b/plugins/data-inspector/README.md
index 164585b5b..80d91de77 100644
--- a/plugins/data-inspector/README.md
+++ b/plugins/data-inspector/README.md
@@ -1,10 +1,10 @@
# @devframes/plugin-data-inspector
-Inspect live server-side objects interactively. Other devframes and host frameworks register **data sources**; the workbench composes [jora](https://github.com/discoveryjs/jora) queries against them — executed in the process that owns the objects — and renders normalized results in a [discovery.js](https://github.com/discoveryjs/discovery) struct view with type badges, a shape panel, saved queries, and shareable URL state. Deep graphs expand a level at a time (`load deeper` fetches each subtree on demand), an optional poller re-runs the query every N seconds, and a toolbar offers expand/collapse-all and copy.
+Inspect live server-side objects interactively. Other devframes and host frameworks register **data sources**; the workbench composes [jora](https://github.com/discoveryjs/jora) queries against them (executed in the process that owns the objects) and renders normalized results in a [discovery.js](https://github.com/discoveryjs/discovery) struct view with type badges, a shape panel, saved queries, and shareable URL state. Deep graphs expand a level at a time (`load deeper` fetches each subtree on demand), an optional poller re-runs the query every N seconds, and a toolbar offers expand/collapse-all and copy.
## Register a data source
-The registry is **process-global** — register from anywhere, before or after the devframe mounts:
+The registry is **process-global**: register from anywhere, before or after the devframe mounts:
```ts
import { registerDataSource } from '@devframes/plugin-data-inspector/registry'
@@ -28,7 +28,7 @@ ctx.services.whenAvailable('devframes:plugin:data-inspector:sources', (sources)
## Writable sources
-Sources opt into live edits with `writable: true`: on the root view (`$`), every value grows an edit affordance that opens a side panel — set a value (string / number / boolean / null / undefined / JSON), add or delete entries, rename keys — and the mutation is applied **in place to the live object** through the `write` RPC. Read-only stays the default; `static: true` sources are memoized snapshots and always stay read-only (declaring both reports `DP_DATA_INSPECTOR_0004`).
+Sources opt into live edits with `writable: true`: on the root view (`$`), every value grows an edit affordance that opens a side panel where you set a value (string / number / boolean / null / undefined / JSON), add or delete entries, or rename keys; the mutation is applied **in place to the live object** through the `write` RPC. Read-only stays the default; `static: true` sources are memoized snapshots and always stay read-only (declaring both reports `DP_DATA_INSPECTOR_0004`).
`registerDataSource` returns a handle; call `notifyChanged()` whenever the data changes outside the inspector so connected views re-run, or hand the devframe a bridge to the source's own change signal via `subscribe`:
@@ -50,7 +50,7 @@ handle.notifyChanged() // or notify imperatively
## Mount
```ts
-// the default export is the factory — call it for an instance:
+// the default export is the factory; call it for an instance:
import createDataInspectorDevframe from '@devframes/plugin-data-inspector'
// Vite
import { devframeVite } from '@devframes/vite/single'
@@ -90,8 +90,8 @@ On the zero-code path there's nowhere to call `registerDataSource`, so the injec
The inject entry binds `127.0.0.1`, requires devframe's trust handshake with a per-run token by default, and advertises its endpoint in `node_modules/.data-inspector/discovery.json`, which `pnpx @devframes/plugin-data-inspector attach` picks up automatically.
> [!WARNING]
-> A connected inspector runs eval-grade jora queries against live objects: queries can invoke functions reachable as own properties and fire getters. Treat the inject endpoint like a debugger port — keep it on loopback and keep auth on.
+> A connected inspector runs eval-grade jora queries against live objects: queries can invoke functions reachable as own properties and fire getters. Treat the inject endpoint like a debugger port: keep it on loopback and keep auth on.
## Saved queries
-Recipes (`{ query, title?, description?, ...filters }`) persist id-keyed in two scopes: **workspace** (committable, `getStorageDir('workspace')/data-inspector/queries.json` — shared with the team) and **project** (per-checkout, under `node_modules`).
+Recipes (`{ query, title?, description?, ...filters }`) persist id-keyed in two scopes: **workspace** (committable, `getStorageDir('workspace')/data-inspector/queries.json`, shared with the team) and **project** (per-checkout, under `node_modules`).
diff --git a/plugins/data-inspector/src/cli.ts b/plugins/data-inspector/src/cli.ts
index 78462b71a..7f632b09c 100644
--- a/plugins/data-inspector/src/cli.ts
+++ b/plugins/data-inspector/src/cli.ts
@@ -1,5 +1,5 @@
/**
- * Standalone CLI — `devframe-data-inspector`:
+ * Standalone CLI for `devframe-data-inspector`:
*
* ```sh
* devframe-data-inspector stats.json trace.jsonl # inspect local data files
diff --git a/plugins/data-inspector/src/engine/contract.ts b/plugins/data-inspector/src/engine/contract.ts
index 0c4c9251e..29000d3f6 100644
--- a/plugins/data-inspector/src/engine/contract.ts
+++ b/plugins/data-inspector/src/engine/contract.ts
@@ -1,5 +1,5 @@
/**
- * Wire types shared by the server RPC functions and the SPA. Types only —
+ * Wire types shared by the server RPC functions and the SPA. Types only,
* safe to import from browser code without dragging jora into the bundle.
*/
@@ -66,12 +66,12 @@ export type WriteValue
* the server resolves the path and dispatches on what it finds there
* (object / array / Map / Set).
*
- * - `set` — replace the value at `path`.
- * - `delete` — remove the node at `path` from its container.
- * - `add` — `path` addresses the CONTAINER; insert `key`/`value`
+ * - `set` replace the value at `path`.
+ * - `delete` remove the node at `path` from its container.
+ * - `add` `path` addresses the CONTAINER; insert `key`/`value`
* (objects and Maps need `key`; arrays take an optional index
* `key` to splice at, else append; Sets take just `value`).
- * - `rename` — re-key the node at `path` under `key`, atomically
+ * - `rename` re-key the node at `path` under `key`, atomically
* (objects and Maps; the renamed key lands last).
*/
export type WriteRequest
@@ -126,7 +126,7 @@ export type SkeletonOutcome
| { ok: false, error: { name: string, message: string } }
/**
- * Where a saved query persists — mirrors the host storage scopes:
+ * Where a saved query persists, mirroring the host storage scopes:
* `workspace` is committable and shared with the team, `project` is
* per-checkout private (node_modules).
*/
diff --git a/plugins/data-inspector/src/engine/jora.d.ts b/plugins/data-inspector/src/engine/jora.d.ts
index eea347bd6..2348cbd7c 100644
--- a/plugins/data-inspector/src/engine/jora.d.ts
+++ b/plugins/data-inspector/src/engine/jora.d.ts
@@ -1,5 +1,5 @@
/**
- * Minimal jora typings — the package ships none. Referenced via a
+ * Minimal jora typings, since the package ships none. Referenced via a
* triple-slash directive from `query-engine.ts` so every TS program that
* pulls the engine in (this package, the SPA, source-aliased consumers)
* sees the declaration.
diff --git a/plugins/data-inspector/src/engine/normalize.ts b/plugins/data-inspector/src/engine/normalize.ts
index c1045d32f..2d93b2b24 100644
--- a/plugins/data-inspector/src/engine/normalize.ts
+++ b/plugins/data-inspector/src/engine/normalize.ts
@@ -103,7 +103,7 @@ export function navigate(value: unknown, path: NodePath, options: Pick= w.opts.maxDepth) {
+ w.stats.truncatedDepth++
+ return { $truncated: 'depth', $preview: preview(obj), $path: segs }
+ }
+
+ w.seen.set(obj, path)
+
+ if (Array.isArray(obj))
+ return walkArray(obj, w, depth, path, segs)
+ if (ArrayBuffer.isView(obj))
+ return walkTypedArray(obj)
+ if (obj instanceof Map)
+ return walkMap(obj, w, depth, path, segs)
+ if (obj instanceof Set)
+ return walkSet(obj, w, depth, path, segs)
+ return walkObject(obj, w, depth, path, segs)
+}
+
+/** Serialize the leaf scalar/function forms; `handled: false` means recurse into the object. */
+function walkPrimitive(value: unknown, w: Walker): { handled: true, value: unknown } | { handled: false } {
if (value === null || value === undefined)
- return value ?? null
+ return { handled: true, value: value ?? null }
const t = typeof value
if (t === 'string') {
const s = value as string
- if (s.length > w.opts.maxString)
- return `${s.slice(0, w.opts.maxString)}… [$truncated string, ${s.length} chars]`
- return s
+ const out = s.length > w.opts.maxString
+ ? `${s.slice(0, w.opts.maxString)}… [$truncated string, ${s.length} chars]`
+ : s
+ return { handled: true, value: out }
}
if (t === 'number')
- return Number.isFinite(value as number) ? value : String(value)
+ return { handled: true, value: Number.isFinite(value as number) ? value : String(value) }
if (t === 'boolean')
- return value
+ return { handled: true, value }
if (t === 'bigint')
- return { $type: 'bigint', value: String(value) }
+ return { handled: true, value: { $type: 'bigint', value: String(value) } }
if (t === 'symbol')
- return { $type: 'symbol', value: String(value) }
+ return { handled: true, value: { $type: 'symbol', value: String(value) } }
if (t === 'function') {
const fn = value as { name?: string }
- return { $type: 'function', name: fn.name || '(anonymous)' }
- }
-
- // ── objects ─────────────────────────────────────────────────────────
- const obj = value as object
-
- const seenPath = w.seen.get(obj)
- if (seenPath !== undefined) {
- w.stats.refs++
- return { $ref: seenPath }
+ return { handled: true, value: { $type: 'function', name: fn.name || '(anonymous)' } }
}
+ return { handled: false }
+}
- // Cheap non-recursive exotic types first.
+/** Tag the cheap non-recursive exotic types, or `undefined` to keep walking. */
+function walkExotic(obj: object): Record | undefined {
if (obj instanceof Date)
return { $type: 'Date', value: Number.isNaN(obj.getTime()) ? 'Invalid Date' : obj.toISOString() }
if (obj instanceof RegExp)
return { $type: 'RegExp', value: String(obj) }
if (obj instanceof URL)
return { $type: 'URL', value: obj.href }
- if (obj instanceof Error) {
+ if (obj instanceof Error)
return { $type: 'Error', name: obj.name, message: obj.message }
- }
if (obj instanceof Promise)
return { $type: 'Promise' }
for (const [ctor, tag] of OPAQUE_TAGS) {
if (obj instanceof ctor)
return { $type: tag }
}
+ return undefined
+}
- if (depth >= w.opts.maxDepth) {
- w.stats.truncatedDepth++
- return { $truncated: 'depth', $preview: preview(obj), $path: segs }
+function walkArray(arr: unknown[], w: Walker, depth: number, path: string, segs: NodePath): unknown[] {
+ const source = w.opts.excludeFunctions ? arr.filter(item => typeof item !== 'function') : arr
+ const cap = Math.min(source.length, w.opts.maxEntries)
+ const out: unknown[] = Array.from({ length: cap })
+ for (let i = 0; i < cap; i++)
+ out[i] = walk(source[i], w, depth + 1, `${path}[${i}]`, seg(segs, ['i', i]))
+ if (source.length > cap) {
+ w.stats.truncatedEntries++
+ out.push({ $truncated: 'entries', $total: source.length, $shown: cap })
}
+ return out
+}
- w.seen.set(obj, path)
-
- if (Array.isArray(obj)) {
- const source = w.opts.excludeFunctions ? obj.filter(item => typeof item !== 'function') : obj
- const cap = Math.min(source.length, w.opts.maxEntries)
- const out: unknown[] = Array.from({ length: cap })
- for (let i = 0; i < cap; i++)
- out[i] = walk(source[i], w, depth + 1, `${path}[${i}]`, seg(segs, ['i', i]))
- if (source.length > cap) {
- w.stats.truncatedEntries++
- out.push({ $truncated: 'entries', $total: source.length, $shown: cap })
- }
- return out
- }
+function walkTypedArray(obj: object): Record {
+ const view = obj as ArrayBufferView & { length?: number }
+ return { $type: obj.constructor?.name ?? 'TypedArray', length: view.length ?? view.byteLength }
+}
- if (ArrayBuffer.isView(obj)) {
- const view = obj as unknown as { length?: number, byteLength: number }
- return { $type: obj.constructor?.name ?? 'TypedArray', length: view.length ?? view.byteLength }
+function walkMap(map: Map, w: Walker, depth: number, path: string, segs: NodePath): unknown {
+ const entries = [...map.entries()].slice(0, w.opts.maxEntries)
+ if (map.size > entries.length)
+ w.stats.truncatedEntries++
+ const allStringKeys = entries.every(([k]) => typeof k === 'string')
+ if (allStringKeys) {
+ const value: Record = {}
+ for (const [k, v] of entries)
+ value[k as string] = walk(v, w, depth + 1, `${path}.${String(k)}`, seg(segs, ['k', k as string]))
+ return { $type: 'Map', size: map.size, value }
}
-
- if (obj instanceof Map) {
- const entries = [...obj.entries()].slice(0, w.opts.maxEntries)
- if (obj.size > entries.length)
- w.stats.truncatedEntries++
- const allStringKeys = entries.every(([k]) => typeof k === 'string')
- if (allStringKeys) {
- const value: Record = {}
- for (const [k, v] of entries)
- value[k as string] = walk(v, w, depth + 1, `${path}.${String(k)}`, seg(segs, ['k', k as string]))
- return { $type: 'Map', size: obj.size, value }
- }
- return {
- $type: 'Map',
- size: obj.size,
- entries: entries.map(([k, v], i) => ({
- key: walk(k, w, depth + 1, `${path}~keys[${i}]`, seg(segs, ['mk', i])),
- value: walk(v, w, depth + 1, `${path}~values[${i}]`, seg(segs, ['mv', i])),
- })),
- }
+ return {
+ $type: 'Map',
+ size: map.size,
+ entries: entries.map(([k, v], i) => ({
+ key: walk(k, w, depth + 1, `${path}~keys[${i}]`, seg(segs, ['mk', i])),
+ value: walk(v, w, depth + 1, `${path}~values[${i}]`, seg(segs, ['mv', i])),
+ })),
}
+}
- if (obj instanceof Set) {
- const values = [...obj].slice(0, w.opts.maxEntries)
- if (obj.size > values.length)
- w.stats.truncatedEntries++
- return { $type: 'Set', size: obj.size, values: values.map((v, i) => walk(v, w, depth + 1, `${path}~set[${i}]`, seg(segs, ['s', i]))) }
- }
+function walkSet(set: Set, w: Walker, depth: number, path: string, segs: NodePath): unknown {
+ const values = [...set].slice(0, w.opts.maxEntries)
+ if (set.size > values.length)
+ w.stats.truncatedEntries++
+ return { $type: 'Set', size: set.size, values: values.map((v, i) => walk(v, w, depth + 1, `${path}~set[${i}]`, seg(segs, ['s', i]))) }
+}
- // Plain object or class instance: own enumerable string-keyed props.
+/** Plain object or class instance: own enumerable string-keyed props. */
+function walkObject(obj: object, w: Walker, depth: number, path: string, segs: NodePath): Record {
const proto = Object.getPrototypeOf(obj)
const className = proto && proto !== Object.prototype && proto !== null
? (proto.constructor?.name as string | undefined)
@@ -246,20 +271,8 @@ function walk(value: unknown, w: Walker, depth: number, path: string, segs: Node
const keys = Object.keys(obj).filter(key => !isExcludedKey(key, w.opts))
const cap = Math.min(keys.length, w.opts.maxProps)
- for (let i = 0; i < cap; i++) {
- const key = keys[i]
- let v: unknown
- try {
- v = (obj as Record)[key] // own getters may fire or throw
- }
- catch (error) {
- out[key] = { $type: 'getter-error', message: error instanceof Error ? error.message : String(error) }
- continue
- }
- if (w.opts.excludeFunctions && typeof v === 'function')
- continue
- out[key] = walk(v, w, depth + 1, `${path}.${key}`, seg(segs, ['k', key]))
- }
+ for (let i = 0; i < cap; i++)
+ walkObjectKey(obj, keys[i], w, depth, path, segs, out)
if (keys.length > cap) {
w.stats.truncatedProps++
out.$truncated = `props: showing ${cap} of ${keys.length}`
@@ -267,6 +280,21 @@ function walk(value: unknown, w: Walker, depth: number, path: string, segs: Node
return out
}
+/** Read one own property (getters may throw) and walk it into `out`. */
+function walkObjectKey(obj: object, key: string, w: Walker, depth: number, path: string, segs: NodePath, out: Record): void {
+ let v: unknown
+ try {
+ v = (obj as Record)[key]
+ }
+ catch (error) {
+ out[key] = { $type: 'getter-error', message: error instanceof Error ? error.message : String(error) }
+ return
+ }
+ if (w.opts.excludeFunctions && typeof v === 'function')
+ return
+ out[key] = walk(v, w, depth + 1, `${path}.${key}`, seg(segs, ['k', key]))
+}
+
/** Append one structural step to a path, returning a fresh array. */
function seg(path: NodePath, step: PathSegment): NodePath {
return [...path, step]
diff --git a/plugins/data-inspector/src/engine/query-engine.ts b/plugins/data-inspector/src/engine/query-engine.ts
index 5cd7c4732..6d21730d1 100644
--- a/plugins/data-inspector/src/engine/query-engine.ts
+++ b/plugins/data-inspector/src/engine/query-engine.ts
@@ -17,7 +17,7 @@
* for parsing jora. jora is a `devDependency` (`catalog:inlined` in the
* workspace catalog) rather than a regular `dependency`, so tsdown vendors
* it straight into this package's own `dist` on both the node and browser
- * builds — the on-demand `import()` resolves a local chunk, and neither
+ * builds; the on-demand `import()` resolves a local chunk, and neither
* side needs consumers to install jora themselves.
*/
import type { Jora } from 'jora'
@@ -58,7 +58,7 @@ function isSetLike(v: unknown): v is Set {
type CreateQuery = ReturnType
/**
- * jora loads on first use and is cached for the process lifetime — a single
+ * jora loads on first use and is cached for the process lifetime: a single
* `import('jora')` + `setup()`, however many queries follow.
*/
let createQueryPromise: Promise | undefined
@@ -159,7 +159,7 @@ interface JoraStatEntry {
/**
* jora stat mode: evaluates the (tolerant) query against the target and
* reports completions for the given cursor position. Each stat entry carries
- * its candidates in a nested `suggestions` array — flattened here into plain,
+ * its candidates in a nested `suggestions` array, flattened here into plain,
* RPC-safe completion items.
*/
export async function suggest(target: unknown, query: string, pos: number, limit = 30): Promise {
diff --git a/plugins/data-inspector/src/engine/skeleton.ts b/plugins/data-inspector/src/engine/skeleton.ts
index 407718246..581e84371 100644
--- a/plugins/data-inspector/src/engine/skeleton.ts
+++ b/plugins/data-inspector/src/engine/skeleton.ts
@@ -1,7 +1,7 @@
/**
* "What data are available": walks a live object into a compact type
* SKELETON (keys and type names, no values) so users can see the shape of a
- * source while composing queries — independent of any query.
+ * source while composing queries, independent of any query.
*
* - primitives -> their type name ('string', 'number', ...)
* - functions -> 'function'
@@ -91,36 +91,45 @@ function walk(value: unknown, w: SkeletonWalker, depth: number): unknown {
}
function walkObject(obj: object, w: SkeletonWalker, depth: number): unknown {
- if (Array.isArray(obj)) {
- const items = w.opts.excludeFunctions ? obj.filter(item => typeof item !== 'function') : obj
- if (items.length === 0)
- return []
- const first = walk(items[0], w, depth + 1)
- return items.length > 1 ? [first, `+${items.length - 1} more`] : [first]
- }
-
+ if (Array.isArray(obj))
+ return walkArraySkeleton(obj, w, depth)
if (ArrayBuffer.isView(obj))
return obj.constructor?.name ?? 'TypedArray'
+ if (isMapLike(obj))
+ return walkMapSkeleton(obj, w, depth)
+ if (isSetLike(obj))
+ return walkSetSkeleton(obj, w, depth)
+ return walkPlainObject(obj, w, depth)
+}
- if (isMapLike(obj)) {
- const first = obj.entries().next().value as [unknown, unknown] | undefined
- if (!first)
- return `Map(0)`
- return {
- [`Map(${obj.size})`]: {
- key: walk(first[0], w, depth + 1),
- value: walk(first[1], w, depth + 1),
- },
- }
- }
+function walkArraySkeleton(arr: unknown[], w: SkeletonWalker, depth: number): unknown[] {
+ const items = w.opts.excludeFunctions ? arr.filter(item => typeof item !== 'function') : arr
+ if (items.length === 0)
+ return []
+ const first = walk(items[0], w, depth + 1)
+ return items.length > 1 ? [first, `+${items.length - 1} more`] : [first]
+}
- if (isSetLike(obj)) {
- const first = obj[Symbol.iterator]().next().value
- return first === undefined
- ? `Set(0)`
- : { [`Set(${obj.size})`]: walk(first, w, depth + 1) }
+function walkMapSkeleton(map: Map, w: SkeletonWalker, depth: number): unknown {
+ const first = map.entries().next().value as [unknown, unknown] | undefined
+ if (!first)
+ return `Map(0)`
+ return {
+ [`Map(${map.size})`]: {
+ key: walk(first[0], w, depth + 1),
+ value: walk(first[1], w, depth + 1),
+ },
}
+}
+function walkSetSkeleton(set: Set, w: SkeletonWalker, depth: number): unknown {
+ const first = set[Symbol.iterator]().next().value
+ return first === undefined
+ ? `Set(0)`
+ : { [`Set(${set.size})`]: walk(first, w, depth + 1) }
+}
+
+function walkPlainObject(obj: object, w: SkeletonWalker, depth: number): Record {
const proto = Object.getPrototypeOf(obj)
const className = proto && proto !== Object.prototype ? (proto.constructor?.name as string | undefined) : undefined
@@ -130,21 +139,23 @@ function walkObject(obj: object, w: SkeletonWalker, depth: number): unknown {
const keys = Object.keys(obj).filter(key => !isExcludedKey(key, w.opts))
const cap = Math.min(keys.length, w.opts.maxProps)
- for (let i = 0; i < cap; i++) {
- const key = keys[i]
- let v: unknown
- try {
- v = (obj as Record)[key]
- }
- catch {
- out[key] = 'getter-error'
- continue
- }
- if (w.opts.excludeFunctions && typeof v === 'function')
- continue
- out[key] = walk(v, w, depth + 1)
- }
+ for (let i = 0; i < cap; i++)
+ walkPlainObjectKey(obj, keys[i], w, depth, out)
if (keys.length > cap)
out['...'] = `+${keys.length - cap} more props`
return out
}
+
+function walkPlainObjectKey(obj: object, key: string, w: SkeletonWalker, depth: number, out: Record): void {
+ let v: unknown
+ try {
+ v = (obj as Record)[key]
+ }
+ catch {
+ out[key] = 'getter-error'
+ return
+ }
+ if (w.opts.excludeFunctions && typeof v === 'function')
+ return
+ out[key] = walk(v, w, depth + 1)
+}
diff --git a/plugins/data-inspector/src/engine/write.ts b/plugins/data-inspector/src/engine/write.ts
index dcdcea1c0..1123ff1ae 100644
--- a/plugins/data-inspector/src/engine/write.ts
+++ b/plugins/data-inspector/src/engine/write.ts
@@ -4,7 +4,7 @@
* Ops are container-generic on the wire (`set` / `delete` / `add` / `rename`);
* this module resolves the path with the same descent semantics as the
* normalizer's `navigate` (filter options shift array indices) and dispatches
- * on the container it finds — plain object, array, Map, or Set. Every failure
+ * on the container it finds, whether plain object, array, Map, or Set. Every failure
* returns a named error outcome; nothing here throws.
*/
import type { NodePath, PathSegment, WriteOutcome, WriteRequest, WriteValue } from './contract'
@@ -99,38 +99,42 @@ function resolveParent(root: unknown, path: NodePath, opts: WriteApplyOptions):
return parent
}
+/** Set an own property, requiring it already exists and is writable. */
+function setObjectProperty(parent: object, key: string, value: unknown): void {
+ assertMutableObject(parent)
+ assertSafeObjectKey(key)
+ if (!Object.hasOwn(parent, key))
+ throw new WriteError('PathNotFound', `property "${key}" does not exist`)
+ const desc = Object.getOwnPropertyDescriptor(parent, key)!
+ if (!desc.writable && !desc.set)
+ throw new WriteError('ReadonlyProperty', `property "${key}" has no setter`)
+ // The property is verified own, so bracket assignment only runs this
+ // object's own setter (or writes its own slot), never an inherited one.
+ const record = parent as Record
+ record[key] = value
+}
+
+function setArrayIndex(parent: object, at: number, value: unknown, opts: WriteApplyOptions): void {
+ if (!Array.isArray(parent))
+ throw new WriteError('WrongContainer', 'an index step needs an array')
+ const index = realIndex(parent, at, opts)
+ if (index < 0 || index >= parent.length)
+ throw new WriteError('PathNotFound', `array index ${at} does not exist`)
+ parent[index] = value
+}
+
function setAt(parent: object, seg: PathSegment, value: unknown, opts: WriteApplyOptions): void {
const [kind, at] = seg
switch (kind) {
- case 'k': {
- if (parent instanceof Map) {
+ case 'k':
+ if (parent instanceof Map)
parent.set(at, value)
- return
- }
- assertMutableObject(parent)
- const key = at as string
- assertSafeObjectKey(key)
- if (!Object.hasOwn(parent, key))
- throw new WriteError('PathNotFound', `property "${key}" does not exist`)
- const desc = Object.getOwnPropertyDescriptor(parent, key)!
- if (!desc.writable && !desc.set)
- throw new WriteError('ReadonlyProperty', `property "${key}" has no setter`)
- // The property is verified own, so bracket assignment can only run
- // this object's own setter (or write its own data slot) — never one
- // inherited from a shared prototype.
- const record = parent as Record
- record[key] = value
+ else
+ setObjectProperty(parent, at as string, value)
return
- }
- case 'i': {
- if (!Array.isArray(parent))
- throw new WriteError('WrongContainer', 'an index step needs an array')
- const index = realIndex(parent, at as number, opts)
- if (index < 0 || index >= parent.length)
- throw new WriteError('PathNotFound', `array index ${at} does not exist`)
- parent[index] = value
+ case 'i':
+ setArrayIndex(parent, at as number, value, opts)
return
- }
case 's': {
if (!(parent instanceof Set))
throw new WriteError('WrongContainer', 'a set step needs a Set')
@@ -156,32 +160,38 @@ function setAt(parent: object, seg: PathSegment, value: unknown, opts: WriteAppl
}
}
+function deleteObjectProperty(parent: object, key: string): void {
+ assertMutableObject(parent)
+ if (!Object.hasOwn(parent, key))
+ throw new WriteError('PathNotFound', `property "${key}" does not exist`)
+ if (!delete (parent as Record)[key])
+ throw new WriteError('ReadonlyProperty', `property "${key}" cannot be deleted`)
+}
+
+function deleteArrayIndex(parent: object, at: number, opts: WriteApplyOptions): void {
+ if (!Array.isArray(parent))
+ throw new WriteError('WrongContainer', 'an index step needs an array')
+ const index = realIndex(parent, at, opts)
+ if (index < 0 || index >= parent.length)
+ throw new WriteError('PathNotFound', `array index ${at} does not exist`)
+ parent.splice(index, 1)
+}
+
function deleteAt(parent: object, seg: PathSegment, opts: WriteApplyOptions): void {
const [kind, at] = seg
switch (kind) {
- case 'k': {
+ case 'k':
if (parent instanceof Map) {
if (!parent.delete(at))
throw new WriteError('PathNotFound', `Map key "${at}" does not exist`)
- return
}
- assertMutableObject(parent)
- const key = at as string
- if (!Object.hasOwn(parent, key))
- throw new WriteError('PathNotFound', `property "${key}" does not exist`)
- if (!delete (parent as Record)[key])
- throw new WriteError('ReadonlyProperty', `property "${key}" cannot be deleted`)
+ else {
+ deleteObjectProperty(parent, at as string)
+ }
return
- }
- case 'i': {
- if (!Array.isArray(parent))
- throw new WriteError('WrongContainer', 'an index step needs an array')
- const index = realIndex(parent, at as number, opts)
- if (index < 0 || index >= parent.length)
- throw new WriteError('PathNotFound', `array index ${at} does not exist`)
- parent.splice(index, 1)
+ case 'i':
+ deleteArrayIndex(parent, at as number, opts)
return
- }
case 's': {
if (!(parent instanceof Set))
throw new WriteError('WrongContainer', 'a set step needs a Set')
@@ -231,43 +241,53 @@ function addTo(container: object, key: WriteValue | undefined, value: unknown, o
defineOwnDataProperty(container, propKey, value)
}
+function renameMapNamedKey(map: Map, at: string | number, newKey: unknown): void {
+ if (!map.has(at))
+ throw new WriteError('PathNotFound', `Map key "${at}" does not exist`)
+ if (newKey === at)
+ return
+ const value = map.get(at)
+ map.delete(at)
+ map.set(newKey, value)
+}
+
+function renameObjectKey(parent: object, key: string, newKey: unknown): void {
+ assertMutableObject(parent)
+ if (!Object.hasOwn(parent, key))
+ throw new WriteError('PathNotFound', `property "${key}" does not exist`)
+ if (typeof newKey !== 'string')
+ throw new WriteError('InvalidKey', 'an object property key must be a string')
+ assertSafeObjectKey(newKey)
+ if (newKey === key)
+ return
+ const value = (parent as Record)[key]
+ delete (parent as Record)[key]
+ // The new key is fresh to this object; define it directly rather than
+ // assigning through the prototype chain.
+ defineOwnDataProperty(parent, newKey, value)
+}
+
+function renameMapEntry(parent: object, at: number, newKey: unknown): void {
+ if (!(parent instanceof Map))
+ throw new WriteError('WrongContainer', 'a map-entry step needs a Map')
+ const [oldKey, value] = entryAt(parent, at)
+ if (newKey === oldKey)
+ return
+ parent.delete(oldKey)
+ parent.set(newKey, value)
+}
+
function renameAt(parent: object, seg: PathSegment, newKey: unknown): void {
const [kind, at] = seg
- if (kind === 'k' && parent instanceof Map) {
- if (!parent.has(at))
- throw new WriteError('PathNotFound', `Map key "${at}" does not exist`)
- if (newKey === at)
- return
- const value = parent.get(at)
- parent.delete(at)
- parent.set(newKey, value)
- return
- }
if (kind === 'k') {
- assertMutableObject(parent)
- const key = at as string
- if (!Object.hasOwn(parent, key))
- throw new WriteError('PathNotFound', `property "${key}" does not exist`)
- if (typeof newKey !== 'string')
- throw new WriteError('InvalidKey', 'an object property key must be a string')
- assertSafeObjectKey(newKey)
- if (newKey === key)
- return
- const value = (parent as Record)[key]
- delete (parent as Record)[key]
- // The new key is fresh to this object; define it directly rather than
- // assigning through the prototype chain.
- defineOwnDataProperty(parent, newKey, value)
+ if (parent instanceof Map)
+ renameMapNamedKey(parent, at, newKey)
+ else
+ renameObjectKey(parent, at as string, newKey)
return
}
if (kind === 'mk' || kind === 'mv') {
- if (!(parent instanceof Map))
- throw new WriteError('WrongContainer', 'a map-entry step needs a Map')
- const [oldKey, value] = entryAt(parent, at as number)
- if (newKey === oldKey)
- return
- parent.delete(oldKey)
- parent.set(newKey, value)
+ renameMapEntry(parent, at as number, newKey)
return
}
throw new WriteError('WrongContainer', 'only keyed entries (objects, Maps) can be renamed')
diff --git a/plugins/data-inspector/src/index.ts b/plugins/data-inspector/src/index.ts
index 3cb58a8b5..06639a354 100644
--- a/plugins/data-inspector/src/index.ts
+++ b/plugins/data-inspector/src/index.ts
@@ -3,7 +3,7 @@ import { defineDevframe } from 'devframe'
import pkg from '../package.json' with { type: 'json' }
import { setupDataInspector } from './node/index'
-/** Default devframe id — also the RPC namespace. */
+/** Default devframe id, also the RPC namespace. */
const DEFAULT_ID = 'devframes:plugin:data-inspector'
/** Preferred standalone CLI port. */
@@ -34,14 +34,14 @@ export interface DataInspectorDevframeOptions {
port?: number
/**
* Require the trust handshake on the standalone server. Enabled by
- * default — `--open` embeds the current OTP in the opened URL, so the
+ * default; `--open` embeds the current OTP in the opened URL, so the
* tab authenticates automatically without extra prompts. The in-process
* inject endpoint (`@devframes/plugin-data-inspector/inject`) uses its own
* pre-shared-token scheme and is unaffected by this option.
*/
auth?: boolean
/**
- * Register the built-in example source — a small live playground graph
+ * Register the built-in example source, a small live playground graph
* with suggested queries (default `true`). Disable once your own sources
* cover the first-run experience.
*/
@@ -53,7 +53,7 @@ export interface DataInspectorDevframeOptions {
* jora query workbench over data sources registered by other plugins, hosts,
* files, or attached processes.
*
- * The plugin is fully headless about sources — register them via
+ * The plugin is fully headless about sources; register them via
* `@devframes/plugin-data-inspector/registry` (process-global, no context
* needed) or through the `devframes:plugin:data-inspector:sources` context
* service.
diff --git a/plugins/data-inspector/src/inject/index.ts b/plugins/data-inspector/src/inject/index.ts
index b7e0bba66..1b76bf267 100644
--- a/plugins/data-inspector/src/inject/index.ts
+++ b/plugins/data-inspector/src/inject/index.ts
@@ -1,11 +1,11 @@
/**
- * Inject the data inspector into a running process — expose that process's
+ * Inject the data inspector into a running process: expose that process's
* registered data sources to an external data-inspector UI.
*
* Two ways in:
*
* ```ts
- * // 1. explicit, from the target's code — pass sources inline …
+ * // 1. explicit, from the target's code: pass sources inline …
* import { exposeDataInspector } from '@devframes/plugin-data-inspector/inject'
*
* await exposeDataInspector({
@@ -19,7 +19,7 @@
* ```
*
* ```sh
- * # 2. zero code change — preload the inject entry into any Node process
+ * # 2. zero code change: preload the inject entry into any Node process
* DEVFRAME_DATA_INSPECTOR=1 node --import @devframes/plugin-data-inspector/inject server.js
* ```
*
@@ -33,7 +33,7 @@
* and written (with the endpoint) to the discovery file
* `/node_modules/.data-inspector/discovery.json`, which
* `devframe-data-inspector attach` consumes automatically. Connected
- * inspectors run eval-grade queries against live objects in this process —
+ * inspectors run eval-grade queries against live objects in this process, so
* treat the endpoint like a debugger port.
*/
import type { DevframeHost, DevframeNodeContext } from 'devframe'
@@ -155,7 +155,7 @@ export async function exposeDataInspector(options: ExposeDataInspectorOptions =
? createInteractiveAuth(context, { clientAuthTokens: [token!], banner: () => {} })
: false
- // A bare WS RPC endpoint — no SPA, no discovery routes — so the inject endpoint
+ // A bare WS RPC endpoint, with no SPA and no discovery routes, so the inject endpoint
// binds the still-public transport primitives directly rather than the
// full-instance factories. The socket claims every upgrade on the port, so
// the advertised endpoint stays the bare `ws://127.0.0.1:`.
@@ -220,19 +220,21 @@ if (process.env.DEVFRAME_DATA_INSPECTOR === '1' || process.env.DEVFRAME_DATA_INS
auth: process.env.DEVFRAME_DATA_INSPECTOR_AUTH !== '0',
token: process.env.DEVFRAME_DATA_INSPECTOR_TOKEN,
exampleSource: process.env.DEVFRAME_DATA_INSPECTOR_EXAMPLE !== '0',
- // Zero-code path: with no chance to call `registerDataSource`, expose
- // `globalThis` so assigning to it is enough to inspect anything.
+ /**
+ * Zero-code path: with no chance to call `registerDataSource`, expose
+ * `globalThis` so assigning to it is enough to inspect anything.
+ */
sources: process.env.DEVFRAME_DATA_INSPECTOR_GLOBAL !== '0' ? [createGlobalThisDataSource()] : undefined,
}).catch((error) => {
console.error('[data-inspector] inject endpoint failed to start:', error)
})
}
-/** @deprecated Renamed — use {@link DISCOVERY_FILE} (the file moved to `discovery.json`; `attach` still falls back to the old `agent.json`). */
+/** @deprecated Renamed; use {@link DISCOVERY_FILE} (the file moved to `discovery.json`; `attach` still falls back to the old `agent.json`). */
export const AGENT_DISCOVERY_FILE: string = DISCOVERY_FILE
-/** @deprecated Renamed — use {@link InjectDiscovery}. */
+/** @deprecated Renamed; use {@link InjectDiscovery}. */
export type AgentDiscovery = InjectDiscovery
-/** @deprecated Renamed — use {@link DataInspectorEndpoint}. */
+/** @deprecated Renamed; use {@link DataInspectorEndpoint}. */
export type DataInspectorAgent = DataInspectorEndpoint
diff --git a/plugins/data-inspector/src/node/example-source.ts b/plugins/data-inspector/src/node/example-source.ts
index e3c0a0cf9..ff5241d7a 100644
--- a/plugins/data-inspector/src/node/example-source.ts
+++ b/plugins/data-inspector/src/node/example-source.ts
@@ -90,7 +90,7 @@ function createExampleData(ctx?: DevframeNodeContext): Record {
}
/**
- * The built-in example source — always registered unless opted out
+ * The built-in example source, always registered unless opted out
* (`exampleSource: false`). Lets the viewer query simple environment info
* (the devframe context: registered RPC functions, services, storage dirs;
* OS and live process stats) plus a small playground branch exercising
@@ -105,8 +105,10 @@ export function createExampleDataSource(ctx?: DevframeNodeContext): DataSourceEn
description: 'Devframe context, OS and process info, plus a playground graph.',
icon: 'i-ph:flask-duotone',
data: () => data ??= createExampleData(ctx),
- // The factory memoizes, so live edits stick between queries — the
- // playground doubles as a demo of writable sources.
+ /**
+ * The factory memoizes, so live edits stick between queries; the
+ * playground doubles as a demo of writable sources.
+ */
writable: true,
queries: [
...(ctx
diff --git a/plugins/data-inspector/src/node/index.ts b/plugins/data-inspector/src/node/index.ts
index fcf025e01..c64a98897 100644
--- a/plugins/data-inspector/src/node/index.ts
+++ b/plugins/data-inspector/src/node/index.ts
@@ -7,7 +7,7 @@ import { createExampleDataSource, EXAMPLE_SOURCE_ID } from './example-source'
export const SOURCES_CHANGED_EVENT = 'devframes:plugin:data-inspector:sources:changed'
/**
- * Broadcast whenever a source's DATA changes — a successful `write`, a
+ * Broadcast whenever a source's DATA changes: a successful `write`, a
* `notifyChanged()` handle call, or a source's own `subscribe` bridge.
* Carries the source id so clients refresh only the affected view.
*/
diff --git a/plugins/data-inspector/src/node/saved-queries.ts b/plugins/data-inspector/src/node/saved-queries.ts
index dc1376956..83e3b06e6 100644
--- a/plugins/data-inspector/src/node/saved-queries.ts
+++ b/plugins/data-inspector/src/node/saved-queries.ts
@@ -45,7 +45,7 @@ function slugify(text: string): string {
.slice(0, 60)
}
-/** djb2 — stable short id for untitled queries (same query, same id). */
+/** djb2, a stable short id for untitled queries (same query, same id). */
function hashOf(text: string): string {
let hash = 5381
for (let i = 0; i < text.length; i++)
@@ -87,7 +87,7 @@ export function saveQuery(ctx: DevframeNodeContext, input: SaveQueryInput): Save
byScope[input.scope].mutate((draft) => {
draft.queries[id] = record
})
- // The id is the storage key across both scopes — saving into one scope
+ // The id is the storage key across both scopes, so saving into one scope
// moves the query there rather than leaving a stale twin behind.
const other: SavedQueryScope = input.scope === 'project' ? 'workspace' : 'project'
if (byScope[other].value().queries[id]) {
diff --git a/plugins/data-inspector/src/registry/index.ts b/plugins/data-inspector/src/registry/index.ts
index 5816b0b41..bf191eb38 100644
--- a/plugins/data-inspector/src/registry/index.ts
+++ b/plugins/data-inspector/src/registry/index.ts
@@ -1,10 +1,10 @@
/**
- * The data-source registry — how anything in the process hands the
+ * The data-source registry: how anything in the process hands the
* data-inspector an object to query.
*
* The store is **process-global**, held under a `Symbol.for` key on
* `globalThis`: registrations need no devframe context (register before any
- * context exists — CLI, inject endpoint, early setup code), duplicate copies of this
+ * context exists: CLI, inject endpoint, early setup code), duplicate copies of this
* module converge on one store, and setup ordering can never drop a source.
*
* ```ts
@@ -30,7 +30,7 @@ import type { DataSourceMeta, Query } from '../engine/contract'
import { diagnostics } from '../node/diagnostics'
export interface DataSourceEntry {
- /** Unique id — namespace it with your plugin id (`my-plugin:thing`). */
+ /** Unique id; namespace it with your plugin id (`my-plugin:thing`). */
id: string
title: string
description?: string
@@ -38,7 +38,7 @@ export interface DataSourceEntry {
icon?: string
/**
* The data to inspect: a plain value, or a factory returning it (sync or
- * async). Live objects passed directly stay live — queries read their
+ * async). Live objects passed directly stay live, so queries read their
* current state. Wrap functions you want to inspect in a factory.
*/
data: unknown | (() => unknown | Promise)
@@ -50,7 +50,7 @@ export interface DataSourceEntry {
/**
* Opt this source into live edits (default `false`): connected inspectors
* may mutate the resolved object in place through the `write` RPC.
- * Contradicts `static: true` — a memoized snapshot is read-only, so the
+ * Contradicts `static: true`, since a memoized snapshot is read-only, so the
* combination reports a diagnostic and stays read-only.
*/
writable?: boolean
@@ -65,7 +65,7 @@ export interface DataSourceEntry {
queries?: Query[]
}
-/** Handle returned by `registerDataSource` — notify clients or unregister. */
+/** Handle returned by `registerDataSource`, to notify clients or unregister. */
export interface DataSourceHandle {
/** Broadcast that this source's data changed, so connected UIs re-run. */
notifyChanged: () => void
@@ -229,7 +229,7 @@ export function onDataSourceDataChanged(listener: (sourceId: string) => void): (
}
}
-/** Drop every registration and cache — test isolation helper. */
+/** Drop every registration and cache; a test isolation helper. */
export function resetDataSources(): void {
const registry = store()
for (const id of [...registry.subscriptions.keys()])
diff --git a/plugins/data-inspector/src/rpc/functions/_define.ts b/plugins/data-inspector/src/rpc/functions/_define.ts
index cc564319a..226906cb2 100644
--- a/plugins/data-inspector/src/rpc/functions/_define.ts
+++ b/plugins/data-inspector/src/rpc/functions/_define.ts
@@ -3,5 +3,5 @@ import { createDefineWrapperWithContext } from 'devframe/rpc'
export const defineDataInspectorRpc = createDefineWrapperWithContext()
-/** RPC namespace — the plugin id. */
+/** RPC namespace, the plugin id. */
export const NS = 'devframes:plugin:data-inspector'
diff --git a/plugins/data-inspector/src/rpc/functions/query-path.ts b/plugins/data-inspector/src/rpc/functions/query-path.ts
index 6cfa5ead8..842cdce35 100644
--- a/plugins/data-inspector/src/rpc/functions/query-path.ts
+++ b/plugins/data-inspector/src/rpc/functions/query-path.ts
@@ -7,7 +7,7 @@ import { defineDataInspectorRpc, NS } from './_define'
* Lazily expand a depth-truncated node. Re-runs the base jora query against
* the live source, re-descends to the node addressed by `path` (a `NodePath`
* lifted from the `$truncated: 'depth'` marker the client is expanding), and
- * returns just that subtree normalized with a fresh depth budget — so huge
+ * returns just that subtree normalized with a fresh depth budget, so huge
* graphs load a level at a time instead of all at once.
*/
export const queryPath = defineDataInspectorRpc({
diff --git a/plugins/data-inspector/src/rpc/functions/sources.ts b/plugins/data-inspector/src/rpc/functions/sources.ts
index 73fa7fbb6..55585d423 100644
--- a/plugins/data-inspector/src/rpc/functions/sources.ts
+++ b/plugins/data-inspector/src/rpc/functions/sources.ts
@@ -1,7 +1,7 @@
import { listDataSources } from '../../registry/index'
import { defineDataInspectorRpc, NS } from './_define'
-/** Every registered data source (meta only — no data). */
+/** Every registered data source (meta only, no data). */
export const sources = defineDataInspectorRpc({
name: `${NS}:sources`,
type: 'query',
diff --git a/plugins/data-inspector/src/spa/components/AppHeader.vue b/plugins/data-inspector/src/spa/components/AppHeader.vue
index 6f1992b23..dd3fa06f2 100644
--- a/plugins/data-inspector/src/spa/components/AppHeader.vue
+++ b/plugins/data-inspector/src/spa/components/AppHeader.vue
@@ -42,7 +42,7 @@ const conn = computed(() => connectionIndicator(connection.status))
as="a"
href="https://devfra.me/plugins/data-inspector"
target="_blank"
- title="Data Inspector docs — using the plugin and providing data sources"
+ title="Data Inspector docs: using the plugin and providing data sources"
/>
No data sources registered yet. Call
registerDataSource()
- from your plugin or host —
+ from your plugin or host;
/**
* The edit side panel: one panel handling every write op for the node the
- * pencil was clicked on — set (with a type picker), rename key, add an
+ * pencil was clicked on: set (with a type picker), rename key, add an
* entry to a container, and delete. Values travel as discriminated
* `WriteValue` payloads so `undefined` survives JSON transport.
*/
@@ -31,7 +31,7 @@ const node = computed(() => navigateNormalized(wb.result.value, props.path))
const breadcrumb = computed(() => formatNodePath(props.path))
-/** Container kind of the node — decides whether the "add" section shows. */
+/** Container kind of the node, deciding whether the "add" section shows. */
const containerKind = computed<'object' | 'array' | 'map' | 'set' | null>(() => {
const value = node.value
if (Array.isArray(value))
diff --git a/plugins/data-inspector/src/spa/components/QueryEditor.vue b/plugins/data-inspector/src/spa/components/QueryEditor.vue
index 6c364a968..4b3f4dec8 100644
--- a/plugins/data-inspector/src/spa/components/QueryEditor.vue
+++ b/plugins/data-inspector/src/spa/components/QueryEditor.vue
@@ -4,7 +4,7 @@
* @discoveryjs/discovery (which bundles CM5, registers the `jora` mode and
* a show-hint fork with popup positioning + a per-item custom-apply hook).
*
- * Integration choice — discovery's sync-hint plumbing over ad-hoc
+ * Integration choice: discovery's sync-hint plumbing over ad-hoc
* `showHint(options)` calls: discovery's `Editor` re-invokes the
* constructor-supplied hint callback on every `cursorActivity`/`focus`
* while completion is enabled, so a one-shot completion source passed to a
@@ -12,7 +12,7 @@
* constructor one. Instead the constructor `hint` reads the latest
* `suggestions` prop synchronously (our completions arrive async over
* RPC), and a watcher re-triggers `cm.showHint()` when fresh items land
- * while the editor is focused — the same "sync callback + re-trigger"
+ * while the editor is focused, the same "sync callback + re-trigger"
* pattern discovery's own query page uses. Every hint item carries a
* custom `hint()` apply hook (the fork then skips its own
* `replaceRange`), so accepting only emits `accept` and the workbench
@@ -283,7 +283,7 @@ watch(() => props.suggestions, (items) => {
--at-apply: 'bg-secondary border border-base rounded-lg';
/* Absolute inside the relative host: the editor tracks the pane's size
while CM's content height stays out of the layout's min-content chain
- (a tall document must scroll internally, never inflate the pane —
+ (a tall document must scroll internally, never inflate the pane;
the old
diff --git a/plugins/data-inspector/src/spa/components/_fixtures.ts b/plugins/data-inspector/src/spa/components/_fixtures.ts
index 53578ff88..058884f20 100644
--- a/plugins/data-inspector/src/spa/components/_fixtures.ts
+++ b/plugins/data-inspector/src/spa/components/_fixtures.ts
@@ -1,8 +1,9 @@
import type { DataSourceMeta, FilterOptions, Query, SavedQuery } from '../../engine'
-// Shared, static sample data so the presentational components render in
-// isolation without a live RPC connection to a server-side data source.
-
+/**
+ * Shared, static sample data so the presentational components render in
+ * isolation without a live RPC connection to a server-side data source.
+ */
export const sampleSources: DataSourceMeta[] = [
{
id: 'devframe',
diff --git a/plugins/data-inspector/src/spa/composables/display-transform.ts b/plugins/data-inspector/src/spa/composables/display-transform.ts
index c1a306834..33e23a464 100644
--- a/plugins/data-inspector/src/spa/composables/display-transform.ts
+++ b/plugins/data-inspector/src/spa/composables/display-transform.ts
@@ -69,7 +69,7 @@ export function decodeExpandHref(href: string): NodePath | null {
}
/**
- * Node path this render is rooted at — empty for the top-level result, and the
+ * Node path this render is rooted at, empty for the top-level result, and the
* expanded node's path for a lazily fetched subtree, so its own truncation
* markers carry absolute paths back to the root. Set for the duration of each
* synchronous `prepareForDisplay` call.
@@ -83,7 +83,7 @@ export const keyBadges = new WeakMap
@@ -53,7 +53,7 @@ function toggle(): void {
- Execute — positional args as a JSON array
+ Execute with positional args as a JSON array
- No commands registered — commands are a `@devframes/hub` feature; this connection isn't mounted inside a hub.
+ No commands registered. Commands are a `@devframes/hub` feature; this connection isn't mounted inside a hub.
No commands match "{{ search }}".
diff --git a/plugins/inspect/src/spa/components/FunctionRow.vue b/plugins/inspect/src/spa/components/FunctionRow.vue
index f781df3f5..28c1ebccb 100644
--- a/plugins/inspect/src/spa/components/FunctionRow.vue
+++ b/plugins/inspect/src/spa/components/FunctionRow.vue
@@ -65,7 +65,7 @@ function toggle(): void {
- Invoke — positional args as a JSON array
+ Invoke with positional args as a JSON array
- {{ fn.type }} functions may carry side effects — the inspector does not invoke them.
+ {{ fn.type }} functions may carry side effects, so the inspector does not invoke them.
diff --git a/plugins/inspect/src/spa/components/InstancesView.vue b/plugins/inspect/src/spa/components/InstancesView.vue
index 819f4cf98..508e36614 100644
--- a/plugins/inspect/src/spa/components/InstancesView.vue
+++ b/plugins/inspect/src/spa/components/InstancesView.vue
@@ -54,8 +54,8 @@ function formatUptime(startedAt: number): string {
Nothing shows up when only static/build servers are running, when
discovery is turned off (DEVFRAME_DISABLE_INSTANCE_REGISTRY=1),
or when an in-process host hasn't opted in. Start another
- devframe dev server — or a hub host that calls
- registerDevframeInstance() — then hit refresh.
+ devframe dev server (or a hub host that calls
+ registerDevframeInstance()), then hit refresh.
diff --git a/plugins/inspect/src/spa/composables/rpc.ts b/plugins/inspect/src/spa/composables/rpc.ts
index 252354c67..6611e2f39 100644
--- a/plugins/inspect/src/spa/composables/rpc.ts
+++ b/plugins/inspect/src/spa/composables/rpc.ts
@@ -82,7 +82,7 @@ export async function connect(): Promise {
// Reflect the live connection: a dropped socket or refused auth swaps the
// panel to a clear state instead of leaving stale data on screen.
client.events.on('connection:status', () => applyStatus(client))
- // Best-effort trust handshake — data calls succeed regardless on the
+ // Best-effort trust handshake; data calls succeed regardless on the
// single-user standalone server, but shared-state subscription needs
// it, so kick it off and ignore failures/timeouts.
if (client.connectionMeta.backend === 'websocket')
diff --git a/plugins/inspect/src/spa/utils/color.ts b/plugins/inspect/src/spa/utils/color.ts
index 793d457dc..6db53500f 100644
--- a/plugins/inspect/src/spa/utils/color.ts
+++ b/plugins/inspect/src/spa/utils/color.ts
@@ -24,7 +24,7 @@ export interface NamespaceSegment {
text: string
/** The separator that follows this segment (`:` or `/`), or `''` for the last one. */
separator: string
- /** Whether this is the trailing segment — the function's own name rather than a namespace. */
+ /** Whether this is the trailing segment: the function's own name rather than a namespace. */
isLeaf: boolean
/** Hash color for namespace segments; `undefined` for the leaf (rendered in the default foreground). */
color?: string
diff --git a/plugins/inspect/src/spa/vite.config.ts b/plugins/inspect/src/spa/vite.config.ts
index 20783f122..f18803d6f 100644
--- a/plugins/inspect/src/spa/vite.config.ts
+++ b/plugins/inspect/src/spa/vite.config.ts
@@ -6,10 +6,12 @@ import { defineConfig } from 'vite'
import { alias } from '../../../../alias'
import createInspectDevframe from '../index'
-// The inspector SPA. `base: './'` keeps every asset URL relative so the
-// bundle is mount-path portable — it discovers its runtime base from
-// `document.baseURI` and connects via `connectDevframe()`. The build is
-// copied verbatim by `createBuild`; no HTML rewriting.
+/**
+ * The inspector SPA. `base: './'` keeps every asset URL relative so the
+ * bundle is mount-path portable; it discovers its runtime base from
+ * `document.baseURI` and connects via `connectDevframe()`. The build is
+ * copied verbatim by `createBuild`; no HTML rewriting.
+ */
export default defineConfig({
base: './',
root: fileURLToPath(new URL('.', import.meta.url)),
@@ -19,13 +21,17 @@ export default defineConfig({
UnoCSS(),
devframeVite(createInspectDevframe(), { bridge: true, base: '/' }),
],
- // `@antfu/design` ships raw `.ts`/`.vue`; let `@vitejs/plugin-vue` compile its
- // SFCs instead of esbuild pre-bundling them.
+ /**
+ * `@antfu/design` ships raw `.ts`/`.vue`; let `@vitejs/plugin-vue` compile its
+ * SFCs instead of esbuild pre-bundling them.
+ */
optimizeDeps: { exclude: ['@antfu/design'] },
build: {
- // Emit into the sibling `@devframes/plugin-inspect--assets` package, which
- // ships these assets to npm; the node package stays slim and serves them
- // on demand through devframe's remote-assets back-proxy.
+ /**
+ * Emit into the sibling `@devframes/plugin-inspect--assets` package, which
+ * ships these assets to npm; the node package stays slim and serves them
+ * on demand through devframe's remote-assets back-proxy.
+ */
outDir: fileURLToPath(new URL('../../assets-pkg/dist', import.meta.url)),
emptyOutDir: true,
},
diff --git a/plugins/inspect/src/types.ts b/plugins/inspect/src/types.ts
index 8e402d345..ac6813c8e 100644
--- a/plugins/inspect/src/types.ts
+++ b/plugins/inspect/src/types.ts
@@ -17,14 +17,14 @@ export interface RpcFunctionAgentInfo {
/**
* Serializable description of a single registered RPC function. Returned
- * by `devframes:plugin:inspect:list-functions`. JSON-safe by construction
- * — Standard Schema args/return schemas are projected to JSON Schema (best
+ * by `devframes:plugin:inspect:list-functions`. JSON-safe by construction:
+ * Standard Schema args/return schemas are projected to JSON Schema (best
* effort), never sent as live objects.
*/
export interface RpcFunctionInfo {
/** Full namespaced function name (e.g. `my-plugin:do-thing`). */
name: string
- /** Function type — `query`, `static`, `action`, or `event`. */
+ /** Function type: `query`, `static`, `action`, or `event`. */
type: 'query' | 'static' | 'action' | 'event'
/** Whether args/return are declared strictly JSON-serializable. */
jsonSerializable: boolean
@@ -56,7 +56,7 @@ export interface RpcFunctionInfo {
* Serializable projection of a single command registered on a hub's
* commands host (`DevframeServerCommandEntry`/`DevframeCommandBase` in
* `@devframes/hub`), returned by `devframes:plugin:inspect:list-commands`.
- * Populated only when this connection is mounted inside a hub — a plain
+ * Populated only when this connection is mounted inside a hub; a plain
* devframe connection (no hub) returns an empty list.
*/
export interface DevframeInspectCommandInfo {
@@ -76,7 +76,7 @@ export interface DevframeInspectCommandInfo {
/**
* Serializable projection of a single running devframe instance discovered
* in the machine-wide instance registry (`~/.devframe/instances/`), returned
- * by `devframes:plugin:inspect:list-instances`. A live, node-only view — the
+ * by `devframes:plugin:inspect:list-instances`. A live, node-only view; the
* inspector's Instances tab renders these as a read-only directory of the
* other devframes running alongside this one.
*/
@@ -91,7 +91,7 @@ export interface DevframeInspectInstanceInfo {
origin: string
/** Base path the devframe is mounted at (trailing slash). */
basePath: string
- /** Full SPA URL (`origin` + `basePath`) — the link the tab opens. */
+ /** Full SPA URL (`origin` + `basePath`), the link the tab opens. */
url: string
/** Process id of the instance's dev server. */
pid: number
diff --git a/plugins/inspect/test/_utils.ts b/plugins/inspect/test/_utils.ts
index 63b69198b..201259e2b 100644
--- a/plugins/inspect/test/_utils.ts
+++ b/plugins/inspect/test/_utils.ts
@@ -30,7 +30,7 @@ function localSpaDir(): string {
const resolved = resolveStaticAssetsSource(inspectDevframe.cli!.distDir!, path.join(os.tmpdir(), 'devframes_plugin_inspect-test'), inspectDevframe.importMetaUrl)
if (typeof resolved !== 'string') {
throw new TypeError(
- '[devframes_plugin_inspect] client SPA missing — run `pnpm -C plugins/inspect run build` first.',
+ '[devframes_plugin_inspect] client SPA missing; run `pnpm -C plugins/inspect run build` first.',
)
}
return resolved
@@ -44,7 +44,7 @@ function localSpaDir(): string {
export function assertSpaBuilt(): void {
if (!existsSync(path.join(localSpaDir(), 'index.html'))) {
throw new Error(
- '[devframes_plugin_inspect] client SPA missing — run `pnpm -C plugins/inspect run build` first.',
+ '[devframes_plugin_inspect] client SPA missing; run `pnpm -C plugins/inspect run build` first.',
)
}
}
@@ -65,7 +65,7 @@ interface BootOptions {
* controllable lifecycle. Bound to 127.0.0.1 to avoid the IPv4/IPv6 race.
*
* With `hub: true` the context comes from `@devframes/hub`'s
- * `createHubContext`, so `ctx.commands` is a live host — the surface the
+ * `createHubContext`, so `ctx.commands` is a live host, the surface the
* Commands tab reads from when mounted inside a hub. Without it, the plain
* context exercises the no-hub path (empty list, thrown diagnostic).
*/
@@ -105,12 +105,12 @@ async function boot(options: BootOptions): Promise {
return Object.assign(server, { basePath, ctx })
}
-/** Standalone boot — plain devframe context, no hub commands host. */
+/** Standalone boot: plain devframe context, no hub commands host. */
export function startInspectorServer(): Promise {
return boot({})
}
-/** Hub boot — `createHubContext` attaches a live `ctx.commands` host. */
+/** Hub boot: `createHubContext` attaches a live `ctx.commands` host. */
export async function startInspectorHubServer(): Promise> {
return await boot({ hub: true }) as InspectorServer
}
diff --git a/plugins/inspect/test/static-build.test.ts b/plugins/inspect/test/static-build.test.ts
index c095442c7..5c4383ee3 100644
--- a/plugins/inspect/test/static-build.test.ts
+++ b/plugins/inspect/test/static-build.test.ts
@@ -42,13 +42,13 @@ describe('inspector static build', () => {
await readFile(path.join(outDir, DEVFRAME_RPC_DUMP_MANIFEST_FILENAME), 'utf-8'),
) as Record
- // `invoke` is an `action` with no dump — it must not appear.
+ // `invoke` is an `action` with no dump, so it must not appear.
expect(manifest['devframes:plugin:inspect:invoke']).toBeUndefined()
// The snapshot `query` functions bake into the static dump.
expect(manifest['devframes:plugin:inspect:list-functions']).toBeTruthy()
expect(manifest['devframes:plugin:inspect:list-state-keys']).toBeTruthy()
expect(manifest['devframes:plugin:inspect:describe-agent']).toBeTruthy()
- // list-commands is a snapshot query too — bakes to an empty list outside a hub.
+ // list-commands is a snapshot query too, baking to an empty list outside a hub.
expect(manifest['devframes:plugin:inspect:list-commands']).toBeTruthy()
})
})
diff --git a/plugins/inspect/tsdown.config.ts b/plugins/inspect/tsdown.config.ts
index bb24e5736..8aec4c8ea 100644
--- a/plugins/inspect/tsdown.config.ts
+++ b/plugins/inspect/tsdown.config.ts
@@ -8,7 +8,7 @@ const clientEntries = {
'client/index': 'src/client/index.ts',
}
-// Node-side entries — the devframe definition, the CLI/Vite host
+// Node-side entries: the devframe definition, the CLI/Vite host
// adapters, the setup module, and the RPC registry.
const serverEntries = {
'index': 'src/index.ts',
@@ -17,12 +17,14 @@ const serverEntries = {
'rpc/index': 'src/rpc/index.ts',
}
-// Three configs mirror `packages/devframe`:
-// 1. browser runtime build (`dts: false`, `clean: true`) — clears dist/
-// and emits the client bundle in an isolated graph;
-// 2. node runtime build (`dts: false`, `clean: false`) — appends;
-// 3. combined dts (`emitDtsOnly`) — one rolldown graph so the
-// `declare module 'devframe'` RPC augmentation resolves once.
+/**
+ * Three configs mirror `packages/devframe`:
+ * 1. browser runtime build (`dts: false`, `clean: true`): clears dist/
+ * and emits the client bundle in an isolated graph;
+ * 2. node runtime build (`dts: false`, `clean: false`): appends;
+ * 3. combined dts (`emitDtsOnly`): one rolldown graph so the
+ * `declare module 'devframe'` RPC augmentation resolves once.
+ */
export default defineConfig([
{
clean: true,
diff --git a/plugins/inspect/uno.config.ts b/plugins/inspect/uno.config.ts
index 92a0973ae..ba1ef8ed6 100644
--- a/plugins/inspect/uno.config.ts
+++ b/plugins/inspect/uno.config.ts
@@ -1,9 +1,11 @@
import { mergeConfigs } from 'unocss'
import { designConfig } from '../../design/uno.config'
-// The inspector composes the shared devframe base (see `design/uno.config.ts`)
-// and adds only its own extraction globs. Vue templates are scanned by default;
-// `.ts` is opted in for class strings authored in composables/helpers.
+/**
+ * The inspector composes the shared devframe base (see `design/uno.config.ts`)
+ * and adds only its own extraction globs. Vue templates are scanned by default;
+ * `.ts` is opted in for class strings authored in composables/helpers.
+ */
export default mergeConfigs([
designConfig,
{
diff --git a/plugins/messages/.storybook/main.ts b/plugins/messages/.storybook/main.ts
index cecaf8c13..e6a304aea 100644
--- a/plugins/messages/.storybook/main.ts
+++ b/plugins/messages/.storybook/main.ts
@@ -16,8 +16,10 @@ const config: StorybookConfig = {
return mergeConfig(config, {
resolve: { alias },
plugins: [vue(), UnoCSS()],
- // Dev tool reached from arbitrary hostnames (LAN IPs, tunnels,
- // tailnets), e.g. when iframed by the storybook-hub example.
+ /**
+ * Dev tool reached from arbitrary hostnames (LAN IPs, tunnels,
+ * tailnets), e.g. when iframed by the storybook-hub example.
+ */
server: { allowedHosts: true },
})
},
diff --git a/plugins/messages/.storybook/preview.ts b/plugins/messages/.storybook/preview.ts
index ca8390306..c8e542461 100644
--- a/plugins/messages/.storybook/preview.ts
+++ b/plugins/messages/.storybook/preview.ts
@@ -5,7 +5,7 @@ import '../src/client/style.css'
// Drive the shared `@antfu/design` tokens off the toolbar theme toggle: dark mode
// is the `.dark` class on ``, and the canvas takes the semantic
-// `bg-base`/`color-base` surface — matching every other devframe surface.
+// `bg-base`/`color-base` surface, matching every other devframe surface.
function applyTheme(theme: string): void {
document.documentElement.classList.toggle('dark', theme !== 'light')
document.body.classList.add('bg-base', 'color-base', 'font-sans')
diff --git a/plugins/messages/README.md b/plugins/messages/README.md
index 3603e1ffa..a37563c51 100644
--- a/plugins/messages/README.md
+++ b/plugins/messages/README.md
@@ -22,7 +22,7 @@ import createMessagesDevframe from '@devframes/plugin-messages'
await hubContext.install(createMessagesDevframe())
```
-The hub's `ctx.messages` feeds the panel live — every
+The hub's `ctx.messages` feeds the panel live: every
`ctx.messages.add(...)` from any mounted tool shows up, updates stream over
the `devframe:messages:updated` broadcast, and dismissals write back through
the devframe's namespaced RPCs. On a plain (non-hub) context the devframe warns
@@ -34,7 +34,7 @@ the devframe's namespaced RPCs. On a plain (non-hub) context the devframe warns
import { mountMessages } from '@devframes/plugin-messages/client'
const handle = await mountMessages(document.querySelector('#panel')!, {
- rpc, // optional — reuse the host page's client
+ rpc, // optional; reuse the host page's client
})
```
diff --git a/plugins/messages/src/cli.ts b/plugins/messages/src/cli.ts
index 2229b9fa2..2cc98a208 100644
--- a/plugins/messages/src/cli.ts
+++ b/plugins/messages/src/cli.ts
@@ -3,7 +3,7 @@ import { createCac } from 'devframe/adapters/cac'
import createMessagesDevframe from './index'
/**
- * Build the standalone CLI for the messages panel — backs the package `bin`
+ * Build the standalone CLI for the messages panel; backs the package `bin`
* (`devframe-messages`) and `pnpx @devframes/plugin-messages`. Wraps the
* default {@link createMessagesDevframe} definition with devframe's
* `dev` / `build` / `mcp` command shell.
diff --git a/plugins/messages/src/client/App.vue b/plugins/messages/src/client/App.vue
index ab120b84d..2b5ffc23e 100644
--- a/plugins/messages/src/client/App.vue
+++ b/plugins/messages/src/client/App.vue
@@ -111,7 +111,7 @@ async function onOpenFile(entry: DevframeMessageEntry): Promise {
if (!entry.filePosition)
return
const { file, line, column } = entry.filePosition
- // Call the open wire service directly — it resolves the workspace-relative
+ // Call the open wire service directly; it resolves the workspace-relative
// path itself. `file` may be relative or absolute.
const open = props.rpc.services.get('@devframes/service-open')
await open?.rpc.call('open-in-editor', { path: file, line, column })
diff --git a/plugins/messages/src/client/components/MessagesView.vue b/plugins/messages/src/client/components/MessagesView.vue
index 63af392eb..199cc11e3 100644
--- a/plugins/messages/src/client/components/MessagesView.vue
+++ b/plugins/messages/src/client/components/MessagesView.vue
@@ -11,7 +11,7 @@ import MessageList from './MessageList.vue'
// mutations go out as emits (the wrapper maps them onto the
// `devframes:plugin:messages:*` RPCs).
//
-// TODO(toasts): the upstream view also participates in toast selection —
+// TODO(toasts): the upstream view also participates in toast selection.
// `pendingSelectId` (set by clicking a toast) selects + scrolls an entry into
// view, and `markMessagesAsRead()` resets the unread counter `onMounted`.
// Reintroduce both alongside a ToastOverlay port when a viewer needs them.
diff --git a/plugins/messages/src/client/components/_fixtures.ts b/plugins/messages/src/client/components/_fixtures.ts
index 0f3e92ec2..3a7c3f2bf 100644
--- a/plugins/messages/src/client/components/_fixtures.ts
+++ b/plugins/messages/src/client/components/_fixtures.ts
@@ -1,6 +1,6 @@
import type { DevframeMessageEntry } from '@devframes/hub/types'
-/** Shared story fixtures — a feed that exercises every entry facet. */
+/** Shared story fixtures: a feed that exercises every entry facet. */
export function makeSampleEntries(now: number = Date.now()): DevframeMessageEntry[] {
return [
{
diff --git a/plugins/messages/src/client/components/message-styles.ts b/plugins/messages/src/client/components/message-styles.ts
index 619650a74..d32b3c494 100644
--- a/plugins/messages/src/client/components/message-styles.ts
+++ b/plugins/messages/src/client/components/message-styles.ts
@@ -1,7 +1,6 @@
import type { DevframeMessageEntryFrom, DevframeMessageLevel } from '@devframes/hub/types'
-// @unocss-include
-
+/** @unocss-include */
export interface LevelStyle {
icon: string
color: string
diff --git a/plugins/messages/src/client/index.ts b/plugins/messages/src/client/index.ts
index 068dc30d9..28073a3c9 100644
--- a/plugins/messages/src/client/index.ts
+++ b/plugins/messages/src/client/index.ts
@@ -31,7 +31,7 @@ export interface MessagesHandle {
}
/**
- * Mount the messages panel into a DOM container — the embeddable form a
+ * Mount the messages panel into a DOM container, the embeddable form a
* hub `custom-render` dock uses. Styles are injected by the bundle; the
* host page owns the `.dark` class on ``.
*/
diff --git a/plugins/messages/src/client/state/messages.ts b/plugins/messages/src/client/state/messages.ts
index 990ea78c8..b53b81581 100644
--- a/plugins/messages/src/client/state/messages.ts
+++ b/plugins/messages/src/client/state/messages.ts
@@ -9,7 +9,7 @@ export interface MessagesState {
}
// TODO(toasts): vitejs/devtools layers toast notifications and unread
-// tracking over this store — `notify` entries pop as toasts (`addToast`),
+// tracking over this store: `notify` entries pop as toasts (`addToast`),
// never-seen entries bump an `unreadCount` reset by `markMessagesAsRead()`,
// and `selectMessage(id)` lets a toast click focus its entry in the view.
// Port those alongside a ToastOverlay component when a viewer needs them.
@@ -37,14 +37,14 @@ export function useMessages(rpc: DevframeRpcClient): Reactive {
let queue: Promise = Promise.resolve()
function refresh(): Promise {
queue = queue.then(async () => {
- // Omit the cursor on the first call — static builds serve the baked
+ // Omit the cursor on the first call: static builds serve the baked
// no-args snapshot; live servers return the full list either way.
const result = (lastVersion == null
? await rpc.call('devframes:plugin:messages:list')
: await rpc.call('devframes:plugin:messages:list', lastVersion)) as DevframeMessagesListDelta
if (result.full)
entryMap.clear()
- // Apply removals before upserts — an id can be evicted and re-added
+ // Apply removals before upserts, since an id can be evicted and re-added
// within one delta window.
for (const id of result.removedIds)
entryMap.delete(id)
@@ -53,14 +53,14 @@ export function useMessages(rpc: DevframeRpcClient): Reactive {
state!.entries = Array.from(entryMap.values())
lastVersion = result.version
}).catch(() => {
- // Transport hiccup — the next broadcast or trust flip retries.
+ // Transport hiccup; the next broadcast or trust flip retries.
})
return queue
}
// React to the hub's change broadcast. Another consumer sharing this rpc
// client (e.g. a host page embedding the panel) may have registered the
- // handler already — chain onto it instead of replacing it.
+ // handler already, so chain onto it instead of replacing it.
const existing = rpc.client.definitions.get(MESSAGES_UPDATED_EVENT)
if (existing) {
const prev = existing.handler
diff --git a/plugins/messages/src/client/vite.config.ts b/plugins/messages/src/client/vite.config.ts
index 0570615b3..9f6e4d070 100644
--- a/plugins/messages/src/client/vite.config.ts
+++ b/plugins/messages/src/client/vite.config.ts
@@ -21,9 +21,11 @@ export default defineConfig({
fileName: () => 'index.mjs',
},
rollupOptions: {
- // Don't externalize vue so the panel works out of the box in
- // custom-render docks, but do externalize devframe/client since the
- // host provides it.
+ /**
+ * Don't externalize vue so the panel works out of the box in
+ * custom-render docks, but do externalize devframe/client since the
+ * host provides it.
+ */
external: ['devframe/client'],
},
},
diff --git a/plugins/messages/src/constants.ts b/plugins/messages/src/constants.ts
index e33d28b11..ff9cdb879 100644
--- a/plugins/messages/src/constants.ts
+++ b/plugins/messages/src/constants.ts
@@ -1,4 +1,4 @@
-/** Devframe id — drives the hosted mount path `/__/`. */
+/** Devframe id, drives the hosted mount path `/__/`. */
export const PLUGIN_ID = 'devframes_plugin_messages'
/** Preferred standalone CLI port (901x band shared by the core-ish plugins). */
diff --git a/plugins/messages/src/diagnostics.ts b/plugins/messages/src/diagnostics.ts
index 2ae922a76..92053104c 100644
--- a/plugins/messages/src/diagnostics.ts
+++ b/plugins/messages/src/diagnostics.ts
@@ -11,7 +11,7 @@ export const diagnostics = defineDiagnostics({
codes: {
DP_MESSAGES_0001: {
why: (p: { id: string }) =>
- `"${p.id}" is mounted on a context without a hub messages host (\`ctx.messages\`) — its RPC surface stays registered but no-ops, so the panel will show an empty feed.`,
+ `"${p.id}" is mounted on a context without a hub messages host (\`ctx.messages\`); its RPC surface stays registered but no-ops, so the panel will show an empty feed.`,
fix: 'Mount this devframe through a hub host (`@devframes/hub`\'s `initHub`, or `createHubContext` + `ctx.install`) to get a live message feed.',
},
},
diff --git a/plugins/messages/src/index.ts b/plugins/messages/src/index.ts
index 3bac4f2b0..6f0c74340 100644
--- a/plugins/messages/src/index.ts
+++ b/plugins/messages/src/index.ts
@@ -12,8 +12,7 @@ const remoteAssets: RemoteAssets = {
package: `${pkg.name}--assets`,
version: pkg.version,
}
-// The panel `clientScript` bundle (`dist/client`) stays in this node package.
-
+/** The panel `clientScript` bundle (`dist/client`) stays in this node package. */
export interface MessagesDevframeOptions {
/** Override the devframe id (and default CLI command / mount path). */
id?: string
@@ -30,7 +29,7 @@ export interface MessagesDevframeOptions {
port?: number
/**
* Require the trust handshake on the standalone server. Enabled by
- * default — `--open` embeds the current OTP in the opened URL, so the
+ * default; `--open` embeds the current OTP in the opened URL, so the
* tab authenticates automatically without extra prompts. Hosted adapters
* manage their own auth and ignore this.
*/
@@ -38,7 +37,7 @@ export interface MessagesDevframeOptions {
}
/**
- * Build a {@link DevframeDefinition} for the hub message feed panel —
+ * Build a {@link DevframeDefinition} for the hub message feed panel,
* a portable view over `ctx.messages`, ported from vitejs/devtools'
* built-in Messages view. The same definition runs standalone
* (`/cli`, `/build`) and mounts into a host (`/vite`, hub);
@@ -63,16 +62,20 @@ export function createMessagesDevframe(options: MessagesDevframeOptions = {}): D
command: id,
port: options.port ?? DEFAULT_PORT,
distDir: remoteAssets,
- // Gate the standalone server by default; `maybeOpenBrowser` folds the
- // current OTP into the `--open` URL so the tab lands already trusted.
- // Hosted adapters (Vite/hub) supply their own auth layer and ignore this.
+ /**
+ * Gate the standalone server by default; `maybeOpenBrowser` folds the
+ * current OTP into the `--open` URL so the tab lands already trusted.
+ * Hosted adapters (Vite/hub) supply their own auth layer and ignore this.
+ */
auth: options.auth ?? true,
},
dock: {
category: '~builtin',
},
- // Backs the detail panel's "open file" affordance; the panel hides it
- // when the service isn't advertised.
+ /**
+ * Backs the detail panel's "open file" affordance; the panel hides it
+ * when the service isn't advertised.
+ */
services: [{ package: '@devframes/service-open' }],
setup(ctx) {
setupMessages(ctx)
@@ -82,7 +85,7 @@ export function createMessagesDevframe(options: MessagesDevframeOptions = {}): D
export default createMessagesDevframe
export { DEFAULT_PORT, MESSAGES_UPDATED_EVENT, PLUGIN_ID } from './constants'
-// The plugin's data vocabulary is the hub's — re-exported so the SPA, the
+// The plugin's data vocabulary is the hub's, re-exported so the SPA, the
// embeddable client, and consumers can type against the plugin package alone.
export type {
DevframeMessageEntry,
diff --git a/plugins/messages/src/node/index.ts b/plugins/messages/src/node/index.ts
index 60104df2b..7d7527ab0 100644
--- a/plugins/messages/src/node/index.ts
+++ b/plugins/messages/src/node/index.ts
@@ -11,7 +11,7 @@ import { serverFunctions } from '../rpc/index'
*
* The plugin reads the feed from the hub-attached `ctx.messages` host. On a
* plain (non-hub) context it warns once and keeps the RPC surface registered
- * as no-ops, so the panel still renders — with an empty feed.
+ * as no-ops, so the panel still renders, with an empty feed.
*/
export function setupMessages(ctx: DevframeNodeContext): void {
if (!getMessagesHost(ctx))
@@ -19,7 +19,7 @@ export function setupMessages(ctx: DevframeNodeContext): void {
// The detail panel's "open file" affordance calls the
// `@devframes/service-open` wire service (declared in the definition's
- // `services`) directly from the client — the service resolves the
+ // `services`) directly from the client; the service resolves the
// workspace-relative file position itself, so the plugin needs no bridge.
for (const fn of serverFunctions)
ctx.rpc.register(fn)
diff --git a/plugins/messages/src/rpc/functions/_define.ts b/plugins/messages/src/rpc/functions/_define.ts
index 67ab3e53f..a6d4efc94 100644
--- a/plugins/messages/src/rpc/functions/_define.ts
+++ b/plugins/messages/src/rpc/functions/_define.ts
@@ -12,7 +12,7 @@ export const defineMessagesRpc = createDefineWrapperWithContext ({
handler: async (since?: number | null): Promise => {
diff --git a/plugins/messages/src/rpc/functions/update.ts b/plugins/messages/src/rpc/functions/update.ts
index 289e0c118..75573c162 100644
--- a/plugins/messages/src/rpc/functions/update.ts
+++ b/plugins/messages/src/rpc/functions/update.ts
@@ -2,7 +2,7 @@ import type { DevframeMessageEntry, DevframeMessageEntryInput } from '@devframes
import { defineMessagesRpc, getMessagesHost } from './_define'
/**
- * Partially update an existing message entry by id — e.g. the panel resets
+ * Partially update an existing message entry by id, e.g. the panel resets
* `autoDelete` to keep an entry alive while its detail view is open. Returns
* the updated entry, or `null` when the id is unknown or no messages host is
* attached.
diff --git a/plugins/messages/src/rpc/index.ts b/plugins/messages/src/rpc/index.ts
index 6ff4bcc19..f0e5deccb 100644
--- a/plugins/messages/src/rpc/index.ts
+++ b/plugins/messages/src/rpc/index.ts
@@ -6,7 +6,7 @@ import { messagesRemove } from './functions/remove'
import { messagesUpdate } from './functions/update'
/**
- * The message-feed RPC functions registered by the plugin — thin, typed
+ * The message-feed RPC functions registered by the plugin: thin, typed
* wrappers over the hub's `ctx.messages` host. Namespaced
* `devframes:plugin:messages:*` per the plugin convention.
*/
diff --git a/plugins/messages/src/spa/dev-host.ts b/plugins/messages/src/spa/dev-host.ts
index 9be658e3b..a712a1255 100644
--- a/plugins/messages/src/spa/dev-host.ts
+++ b/plugins/messages/src/spa/dev-host.ts
@@ -10,7 +10,7 @@ import { createMessagesDevframe } from '../index'
* and reads whatever hub host it's mounted on; this harness stands in for a
* hub by attaching a real `DevframeMessagesHost` to the plain devframe
* context, wiring the change broadcast the way `createHubContext` does, and
- * seeding a lively demo feed. Production adapters never load this module —
+ * seeding a lively demo feed. Production adapters never load this module -
* the hub import stays lazy so loading the Vite config needs no hub build.
*/
export function createMessagesDevDevframe(): DevframeDefinition {
@@ -42,7 +42,7 @@ function seedDemoMessages(messages: DevframeMessagesHostType): void {
void messages.add({
level: 'success',
message: 'Messages dev harness started',
- description: 'This feed is seeded demo data — a hub host feeds the real one.',
+ description: 'This feed is seeded demo data; a hub host feeds the real one.',
category: 'demo',
})
void messages.add({
@@ -92,7 +92,7 @@ function seedDemoMessages(messages: DevframeMessagesHostType): void {
category: 'runtime',
})
- // A loading entry that resolves — exercises the update path end to end.
+ // A loading entry that resolves, exercising the update path end to end.
void messages.add({
id: 'demo:typecheck',
level: 'info',
@@ -110,7 +110,7 @@ function seedDemoMessages(messages: DevframeMessagesHostType): void {
})
}, 4000)
- // A slow heartbeat with `autoDelete` — exercises removals + delta sync.
+ // A slow heartbeat with `autoDelete`, exercising removals + delta sync.
let beat = 0
setInterval(() => {
beat += 1
diff --git a/plugins/messages/src/spa/main.ts b/plugins/messages/src/spa/main.ts
index eb707412c..8ccbdd379 100644
--- a/plugins/messages/src/spa/main.ts
+++ b/plugins/messages/src/spa/main.ts
@@ -2,7 +2,7 @@ import { mountMessages } from '../client/index'
// The shared design tokens flip on the `.dark` class; mirror the OS preference
// onto (the other devframe plugins follow the same approach). The
-// embeddable client mount leaves this to the host page — only the standalone
+// embeddable client mount leaves this to the host page; only the standalone
// SPA owns the document.
const mq = window.matchMedia('(prefers-color-scheme: dark)')
function applyScheme(dark: boolean): void {
diff --git a/plugins/messages/src/spa/vite.config.ts b/plugins/messages/src/spa/vite.config.ts
index e70b13e27..464991cf4 100644
--- a/plugins/messages/src/spa/vite.config.ts
+++ b/plugins/messages/src/spa/vite.config.ts
@@ -6,13 +6,15 @@ import { defineConfig } from 'vite'
import { alias } from '../../../../alias'
import { createMessagesDevDevframe } from './dev-host'
-// The messages panel SPA. `base: './'` keeps every asset URL relative so the
-// bundle is mount-path portable — it discovers its runtime base from
-// `document.baseURI` and connects via `connectDevframe()`. The build is
-// copied verbatim by `createBuild`; no HTML rewriting.
-//
-// `pnpm dev` self-hosts through the demo-seeded dev harness (a stand-in hub
-// messages host) so the feed is lively without a full hub host.
+/**
+ * The messages panel SPA. `base: './'` keeps every asset URL relative so the
+ * bundle is mount-path portable, discovering its runtime base from
+ * `document.baseURI` and connecting via `connectDevframe()`. The build is
+ * copied verbatim by `createBuild`; no HTML rewriting.
+ *
+ * `pnpm dev` self-hosts through the demo-seeded dev harness (a stand-in hub
+ * messages host) so the feed is lively without a full hub host.
+ */
export default defineConfig({
base: './',
root: fileURLToPath(new URL('.', import.meta.url)),
@@ -22,8 +24,10 @@ export default defineConfig({
UnoCSS(),
devframeViteBridge(createMessagesDevDevframe(), { base: '/' }),
],
- // `@antfu/design` ships raw `.ts`/`.vue`; let `@vitejs/plugin-vue` compile its
- // SFCs instead of esbuild pre-bundling them.
+ /**
+ * `@antfu/design` ships raw `.ts`/`.vue`; let `@vitejs/plugin-vue` compile its
+ * SFCs instead of esbuild pre-bundling them.
+ */
optimizeDeps: { exclude: ['@antfu/design'] },
build: {
outDir: fileURLToPath(new URL('../../assets-pkg/dist', import.meta.url)),
diff --git a/plugins/messages/test/_utils.ts b/plugins/messages/test/_utils.ts
index 2eab6fb5c..3f91ba13d 100644
--- a/plugins/messages/test/_utils.ts
+++ b/plugins/messages/test/_utils.ts
@@ -21,11 +21,11 @@ import { serveTestContext } from '../../../tests/helpers/serve-test-context'
const messagesDevframe = createMessagesDevframe()
const SPA_DIST = localDistDir()
-/** Resolve the SPA to a local dir — the workspace-linked `--assets` package in dev. */
+/** Resolve the SPA to a local dir: the workspace-linked `--assets` package in dev. */
function localDistDir(): string {
const resolved = resolveStaticAssetsSource(messagesDevframe.cli!.distDir!, path.join(os.tmpdir(), 'devframes_plugin_messages-test'), messagesDevframe.importMetaUrl)
if (typeof resolved !== 'string')
- throw new TypeError('these tests serve the local client SPA — build the plugin first')
+ throw new TypeError('these tests serve the local client SPA; build the plugin first')
return resolved
}
@@ -37,7 +37,7 @@ function localDistDir(): string {
export function assertSpaBuilt(): void {
if (!existsSync(path.join(SPA_DIST, 'index.html'))) {
throw new Error(
- '[devframes_plugin_messages] dist/spa missing — run `pnpm -C plugins/messages run build` first.',
+ '[devframes_plugin_messages] dist/spa missing; run `pnpm -C plugins/messages run build` first.',
)
}
}
@@ -58,7 +58,7 @@ interface BootOptions {
* controllable lifecycle. Bound to 127.0.0.1 to avoid the IPv4/IPv6 race.
*
* With `hub: true` the context comes from `@devframes/hub`'s
- * `createHubContext`, so `ctx.messages` is a live host — the shape the
+ * `createHubContext`, so `ctx.messages` is a live host, the shape the
* plugin is designed for. Without it, the plain context exercises the
* warn-and-noop path.
*/
@@ -104,12 +104,12 @@ async function boot(options: BootOptions): Promise {
return Object.assign(server, { basePath, ctx })
}
-/** Standalone boot — plain devframe context, no messages host (noop path). */
+/** Standalone boot: plain devframe context, no messages host (noop path). */
export function startMessagesServer(): Promise {
return boot({})
}
-/** Hub boot — `createHubContext` attaches a live `ctx.messages` host. */
+/** Hub boot: `createHubContext` attaches a live `ctx.messages` host. */
export async function startMessagesHubServer(): Promise> {
return await boot({ hub: true }) as MessagesServer
}
diff --git a/plugins/messages/test/dev-server.test.ts b/plugins/messages/test/dev-server.test.ts
index 58d968e8e..a7cf4dc5b 100644
--- a/plugins/messages/test/dev-server.test.ts
+++ b/plugins/messages/test/dev-server.test.ts
@@ -99,7 +99,7 @@ describe('messages dev-server (hub context)', () => {
})
})
-describe('messages dev-server (plain context — warn + noop)', () => {
+describe('messages dev-server (plain context: warn + noop)', () => {
let server: MessagesServer
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {})
diff --git a/plugins/messages/tsdown.config.ts b/plugins/messages/tsdown.config.ts
index 8fb61bb46..4a896822a 100644
--- a/plugins/messages/tsdown.config.ts
+++ b/plugins/messages/tsdown.config.ts
@@ -2,14 +2,14 @@ import { defineConfig } from 'tsdown'
const tsconfig = '../../tsconfig.base.json'
-// Browser-loaded entry — the embeddable Vue panel. Its runtime bundle is
+// Browser-loaded entry: the embeddable Vue panel. Its runtime bundle is
// produced by the Vite lib build (`src/client/vite.config.ts`, CSS injected
// via JS); tsdown only emits its declarations below.
const clientEntries = {
'client/index': 'src/client/index.ts',
}
-// Node + neutral modules — the devframe definition/factory, the RPC
+// Node + neutral modules: the devframe definition/factory, the RPC
// functions, and the host adapters.
const serverEntries = {
'index': 'src/index.ts',
@@ -19,10 +19,12 @@ const serverEntries = {
'rpc/index': 'src/rpc/index.ts',
}
-// Two configs mirror `plugins/terminals`:
-// 1. node runtime build (`dts: false`, `clean: true`);
-// 2. combined dts (`emitDtsOnly`) — one rolldown graph so the
-// `declare module 'devframe'` RPC augmentation resolves once.
+/**
+ * Two configs mirror `plugins/terminals`:
+ * 1. node runtime build (`dts: false`, `clean: true`);
+ * 2. combined dts (`emitDtsOnly`): one rolldown graph so the
+ * `declare module 'devframe'` RPC augmentation resolves once.
+ */
export default defineConfig([
{
clean: true,
@@ -35,13 +37,15 @@ export default defineConfig([
clean: false,
platform: 'neutral',
tsconfig,
- // `client/index.ts` re-exports `useMessages(): Reactive` —
- // a genuine Vue reactivity type, not just a documentation import. Without
- // this, the dts bundler inlines Vue's entire runtime-core/reactivity type
- // surface to describe `Reactive` (≈935 KB); `neverBundle` keeps the
- // reference as `import('vue').Reactive<...>` instead. This build is
- // `emitDtsOnly`, so it has no effect on the JS output (built separately
- // by the Vite lib build for the client, and by the node build above).
+ /**
+ * `client/index.ts` re-exports `useMessages(): Reactive`,
+ * a genuine Vue reactivity type, not just a documentation import. Without
+ * this, the dts bundler inlines Vue's entire runtime-core/reactivity type
+ * surface to describe `Reactive` (≈935 KB); `neverBundle` keeps the
+ * reference as `import('vue').Reactive<...>` instead. This build is
+ * `emitDtsOnly`, so it has no effect on the JS output (built separately
+ * by the Vite lib build for the client, and by the node build above).
+ */
deps: { neverBundle: ['vue'] },
dts: { emitDtsOnly: true },
outExtensions: () => ({ dts: '.d.mts' }),
diff --git a/plugins/messages/uno.config.ts b/plugins/messages/uno.config.ts
index 4d5542ffb..72414f87b 100644
--- a/plugins/messages/uno.config.ts
+++ b/plugins/messages/uno.config.ts
@@ -1,10 +1,12 @@
import { mergeConfigs } from 'unocss'
import { designConfig } from '../../design/uno.config'
-// The messages panel composes the shared devframe base (see
-// `design/uno.config.ts`) and adds only its own extraction globs. Vue templates
-// are scanned by default; `.ts` is opted in for class strings authored in
-// helpers (e.g. the level/source style maps).
+/**
+ * The messages panel composes the shared devframe base (see
+ * `design/uno.config.ts`) and adds only its own extraction globs. Vue templates
+ * are scanned by default; `.ts` is opted in for class strings authored in
+ * helpers (e.g. the level/source style maps).
+ */
export default mergeConfigs([
designConfig,
{
diff --git a/plugins/og/.storybook/main.ts b/plugins/og/.storybook/main.ts
index 28cbadfa5..43fc9da03 100644
--- a/plugins/og/.storybook/main.ts
+++ b/plugins/og/.storybook/main.ts
@@ -16,8 +16,10 @@ const config: StorybookConfig = {
return mergeConfig(config, {
resolve: { alias },
plugins: [vue(), UnoCSS()],
- // Dev tool reached from arbitrary hostnames (LAN IPs, tunnels,
- // tailnets), e.g. when iframed by the storybook hub.
+ /**
+ * Dev tool reached from arbitrary hostnames (LAN IPs, tunnels,
+ * tailnets), e.g. when iframed by the storybook hub.
+ */
server: { allowedHosts: true },
})
},
diff --git a/plugins/og/.storybook/preview.ts b/plugins/og/.storybook/preview.ts
index b2bef5cdb..734229066 100644
--- a/plugins/og/.storybook/preview.ts
+++ b/plugins/og/.storybook/preview.ts
@@ -5,7 +5,7 @@ import '../src/spa/app/assets/main.css'
// Drive the shared `@antfu/design` tokens off the toolbar theme toggle: dark mode
// is the `.dark` class on ``, and the canvas takes the semantic
-// `bg-base`/`color-base` surface — matching every other devframe surface.
+// `bg-base`/`color-base` surface, matching every other devframe surface.
function applyTheme(theme: string): void {
document.documentElement.classList.toggle('dark', theme !== 'light')
document.body.classList.add('bg-base', 'color-base', 'font-sans')
diff --git a/plugins/og/README.md b/plugins/og/README.md
index 6b57f07a9..342161c30 100644
--- a/plugins/og/README.md
+++ b/plugins/og/README.md
@@ -6,4 +6,4 @@ Inspect Open Graph and Twitter metadata for any reachable page, then compare its
pnpx @devframes/plugin-og
```
-The package exports `createOgDevframe()` for custom definitions — mount it into a Vite host with `devframeVite()` from `@devframes/vite/single`. Pass `defaultUrl` to bake a shareable report with the devframe build adapter.
+The package exports `createOgDevframe()` for custom definitions; mount it into a Vite host with `devframeVite()` from `@devframes/vite/single`. Pass `defaultUrl` to bake a shareable report with the devframe build adapter.
diff --git a/plugins/og/src/node/metadata.ts b/plugins/og/src/node/metadata.ts
index 43a0dd03f..0f55c0c10 100644
--- a/plugins/og/src/node/metadata.ts
+++ b/plugins/og/src/node/metadata.ts
@@ -53,7 +53,7 @@ function resolveTagValue(name: string, value: string, baseUrl: string): string {
}
export function parseOgMetadata(html: string, url: string): OgHeadTag[] {
- const document = parse(html) as unknown as HtmlNode
+ const document = parse(html) as HtmlNode
const htmlElement = findElement(document, 'html')
const head = findElement(document, 'head')
if (!head)
diff --git a/plugins/og/src/rpc/functions/resolve-metadata.ts b/plugins/og/src/rpc/functions/resolve-metadata.ts
index ec211e072..c2ba3e85c 100644
--- a/plugins/og/src/rpc/functions/resolve-metadata.ts
+++ b/plugins/og/src/rpc/functions/resolve-metadata.ts
@@ -55,8 +55,10 @@ export function createResolveMetadataRpc(options: ResolveMetadataOptions = {}) {
return { records: [{ inputs: [input], output: snapshot }], fallback: snapshot }
},
setup: () => ({
- // The RPC runtime awaits handlers before validating `returns`; its public
- // setup type currently models schema-backed returns as synchronous.
+ /**
+ * The RPC runtime awaits handlers before validating `returns`; its public
+ * setup type currently models schema-backed returns as synchronous.
+ */
handler: (async ({ url = '' }): Promise => {
const target = url.trim() || options.defaultUrl?.trim()
if (!target)
diff --git a/plugins/og/src/spa/app/components/_fixtures.ts b/plugins/og/src/spa/app/components/_fixtures.ts
index cc88d2e71..5531f568d 100644
--- a/plugins/og/src/spa/app/components/_fixtures.ts
+++ b/plugins/og/src/spa/app/components/_fixtures.ts
@@ -1,13 +1,14 @@
import type { OgHeadTag, OgSnapshot } from '../../../types'
-// A static, fully-populated Open Graph snapshot so the presentational
-// components render in isolation without a live fetch. Image URLs are
-// illustrative — they resolve to the broken-image placeholder offline, which
-// is itself a useful preview state.
-
+/**
+ * A static, fully-populated Open Graph snapshot so the presentational
+ * components render in isolation without a live fetch. Image URLs are
+ * illustrative, since they resolve to the broken-image placeholder offline, which
+ * is itself a useful preview state.
+ */
export const fullTags: OgHeadTag[] = [
- { tag: 'title', name: 'title', value: 'Devframe — the container for one devtool integration' },
- { tag: 'meta', name: 'description', value: 'Build a single devtool — its RPC, SPA, diagnostics — portable across viewers.' },
+ { tag: 'title', name: 'title', value: 'Devframe: the container for one devtool integration' },
+ { tag: 'meta', name: 'description', value: 'Build a single devtool (its RPC, SPA, diagnostics) portable across viewers.' },
{ tag: 'html', name: 'lang', value: 'en' },
{ tag: 'link', name: 'icon', value: 'https://devfra.me/favicon.svg' },
{ tag: 'meta', name: 'og:title', value: 'Devframe' },
@@ -20,7 +21,7 @@ export const fullTags: OgHeadTag[] = [
{ tag: 'meta', name: 'twitter:image', value: 'https://devfra.me/og.png' },
]
-/** A snapshot missing every Open Graph / Twitter tag — exercises MissingTags. */
+/** A snapshot missing every Open Graph / Twitter tag; exercises MissingTags. */
export const sparseTags: OgHeadTag[] = [
{ tag: 'title', name: 'title', value: 'Untitled page' },
{ tag: 'meta', name: 'description', value: 'A page with only the basics filled in.' },
diff --git a/plugins/og/test/_utils.ts b/plugins/og/test/_utils.ts
index 9b5fe4146..e64e32462 100644
--- a/plugins/og/test/_utils.ts
+++ b/plugins/og/test/_utils.ts
@@ -28,7 +28,7 @@ export async function testFetch(_url: string): Promise {
const testDevframe = createOgDevframe({ fetch: testFetch })
-/** Resolve the SPA to a local dir — the workspace-linked `--assets` package in dev. */
+/** Resolve the SPA to a local dir: the workspace-linked `--assets` package in dev. */
function localSpaDir(): string {
const resolved = resolveStaticAssetsSource(testDevframe.cli!.distDir!, path.join(os.tmpdir(), 'devframes_plugin_og-test'), testDevframe.importMetaUrl)
if (typeof resolved !== 'string')
diff --git a/plugins/og/uno.config.ts b/plugins/og/uno.config.ts
index 996852fc0..36b55f4da 100644
--- a/plugins/og/uno.config.ts
+++ b/plugins/og/uno.config.ts
@@ -1,8 +1,10 @@
import { mergeConfigs } from 'unocss'
import { designConfig } from '../../design/uno.config'
-// The Open Graph viewer composes the shared devframe base (see
-// `design/uno.config.ts`) and adds only its own extraction globs.
+/**
+ * The Open Graph viewer composes the shared devframe base (see
+ * `design/uno.config.ts`) and adds only its own extraction globs.
+ */
export default mergeConfigs([
designConfig,
{
diff --git a/plugins/terminals/.storybook/main.ts b/plugins/terminals/.storybook/main.ts
index fedd81676..f863e4eac 100644
--- a/plugins/terminals/.storybook/main.ts
+++ b/plugins/terminals/.storybook/main.ts
@@ -10,17 +10,21 @@ const config: StorybookConfig = {
name: '@storybook/svelte-vite',
options: {},
},
- // `@storybook/svelte-vite` only wires Svelte docgen — it expects the Svelte
- // compiler plugin to come from a project `vite.config` (ours lives at a
- // non-default path), so add `svelte()` here. UnoCSS auto-loads the plugin-root
- // `uno.config.ts`; the shared aliases let `devframe/*` imports resolve without
- // a prior build.
+ /**
+ * `@storybook/svelte-vite` only wires Svelte docgen; it expects the Svelte
+ * compiler plugin to come from a project `vite.config` (ours lives at a
+ * non-default path), so add `svelte()` here. UnoCSS auto-loads the plugin-root
+ * `uno.config.ts`; the shared aliases let `devframe/*` imports resolve without
+ * a prior build.
+ */
async viteFinal(config) {
return mergeConfig(config, {
resolve: { alias },
plugins: [svelte(), UnoCSS()],
- // Dev tool reached from arbitrary hostnames (LAN IPs, tunnels,
- // tailnets), e.g. when iframed by the storybook-hub example.
+ /**
+ * Dev tool reached from arbitrary hostnames (LAN IPs, tunnels,
+ * tailnets), e.g. when iframed by the storybook-hub example.
+ */
server: { allowedHosts: true },
})
},
diff --git a/plugins/terminals/.storybook/preview.ts b/plugins/terminals/.storybook/preview.ts
index 6eaae8373..f845aa50b 100644
--- a/plugins/terminals/.storybook/preview.ts
+++ b/plugins/terminals/.storybook/preview.ts
@@ -5,7 +5,7 @@ import '../src/client/styles.css'
// Drive the shared `@antfu/design` tokens off the toolbar theme toggle: dark mode
// is the `.dark` class on ``, and the canvas takes the semantic
-// `bg-base`/`color-base` surface — matching every other devframe surface.
+// `bg-base`/`color-base` surface, matching every other devframe surface.
function applyTheme(theme: string): void {
document.documentElement.classList.toggle('dark', theme !== 'light')
document.body.classList.add('bg-base', 'color-base', 'font-sans')
diff --git a/plugins/terminals/src/cli.ts b/plugins/terminals/src/cli.ts
index eb8f4c752..fb9e154b7 100644
--- a/plugins/terminals/src/cli.ts
+++ b/plugins/terminals/src/cli.ts
@@ -4,8 +4,8 @@ import { createCac } from 'devframe/adapters/cac'
import { createTerminalsDevframe } from './index'
/**
- * Build a standalone CLI for the terminals panel — `dev` / `build` / `mcp`
- * subcommands, backed by {@link createTerminalsDevframe}. Used by the
+ * Build a standalone CLI for the terminals panel, exposing `dev` / `build` /
+ * `mcp` subcommands, backed by {@link createTerminalsDevframe}. Used by the
* package `bin`.
*/
export function createTerminalsCli(
diff --git a/plugins/terminals/src/client/App.stories.ts b/plugins/terminals/src/client/App.stories.ts
index 044a52b6f..ee16950af 100644
--- a/plugins/terminals/src/client/App.stories.ts
+++ b/plugins/terminals/src/client/App.stories.ts
@@ -33,7 +33,7 @@ const meta = {
export default meta
type Story = StoryObj
-/** No sessions yet — the empty state with a "New terminal" affordance. */
+/** No sessions yet: the empty state with a "New terminal" affordance. */
export const Empty: Story = {
args: { rpc: mockRpc(), autostart: false },
}
diff --git a/plugins/terminals/src/client/index.ts b/plugins/terminals/src/client/index.ts
index 2a4ed7f45..5a7402496 100644
--- a/plugins/terminals/src/client/index.ts
+++ b/plugins/terminals/src/client/index.ts
@@ -21,7 +21,7 @@ export async function mountTerminals(
container: HTMLElement,
options: MountTerminalsOptions = {},
): Promise {
- const rpc = options.rpc ?? (await connectDevframe()) as unknown as DevframeRpcClient
+ const rpc = options.rpc ?? await connectDevframe()
const app = mount(App, {
target: container,
diff --git a/plugins/terminals/src/client/vite.config.ts b/plugins/terminals/src/client/vite.config.ts
index 1a359cfcc..63a03457d 100644
--- a/plugins/terminals/src/client/vite.config.ts
+++ b/plugins/terminals/src/client/vite.config.ts
@@ -21,8 +21,10 @@ export default defineConfig({
fileName: () => 'index.mjs',
},
rollupOptions: {
- // Don't externalize xterm/xterm-addon-fit so it works out of the box in custom-render,
- // but do externalize devframe/client since the host provides it.
+ /**
+ * Don't externalize xterm/xterm-addon-fit so it works out of the box in custom-render,
+ * but do externalize devframe/client since the host provides it.
+ */
external: ['devframe/client'],
},
},
diff --git a/plugins/terminals/src/constants.ts b/plugins/terminals/src/constants.ts
index faada371a..b78b1f045 100644
--- a/plugins/terminals/src/constants.ts
+++ b/plugins/terminals/src/constants.ts
@@ -26,7 +26,7 @@ export const PRESETS_STATE_KEY = 'devframes:plugin:terminals:presets'
/**
* Shared-state key the hub (`@devframes/hub`) mirrors the most recent dock
* activation into. When a mounted devframe asks the hub to switch to this
- * dock — e.g. Vite DevTools navigating to the build it just spawned — the
+ * dock (e.g. Vite DevTools navigating to the build it just spawned), the
* request lands here as `{ activation: { dockId, params } }`. The UI reads
* `params.sessionId` off it (when `dockId` is this plugin) to focus a specific
* session, converging even when it mounts *because* of the switch. Kept as a
diff --git a/plugins/terminals/src/index.ts b/plugins/terminals/src/index.ts
index bb38e1405..820246cef 100644
--- a/plugins/terminals/src/index.ts
+++ b/plugins/terminals/src/index.ts
@@ -22,7 +22,7 @@ export {
/**
* Build a {@link DevframeDefinition} for the terminals panel. The same
* definition runs standalone (`createCac`), mounts into a Vite host
- * (`/vite`), or docks inside a hub — its `setup` only relies on the core
+ * (`/vite`), or docks inside a hub, since its `setup` only relies on the core
* devframe RPC surface.
*
* @experimental This plugin is experimental and may change without a major
@@ -59,16 +59,20 @@ export function createTerminalsDevframe(options: TerminalsOptions = {}): Devfram
homepage: pkg.homepage,
description: pkg.description,
icon: 'ph:terminal-window-duotone',
- // Leave undefined so `resolveBasePath` picks `/` standalone and
- // `/__/` when hosted. Authors override via `options.basePath`.
+ /**
+ * Leave undefined so `resolveBasePath` picks `/` standalone and
+ * `/__/` when hosted. Authors override via `options.basePath`.
+ */
basePath: options.basePath,
cli: {
command: options.command ?? 'devframe-terminals',
port: options.port ?? DEFAULT_PORT,
distDir,
- // Gate the standalone server by default — shell access is sensitive.
- // `maybeOpenBrowser` folds the current OTP into the `--open` URL so
- // the tab lands already trusted.
+ /**
+ * Gate the standalone server by default, since shell access is sensitive.
+ * `maybeOpenBrowser` folds the current OTP into the `--open` URL so
+ * the tab lands already trusted.
+ */
auth: options.auth ?? true,
},
dock: {
diff --git a/plugins/terminals/src/node/backend.ts b/plugins/terminals/src/node/backend.ts
index 4ac9a8adc..ee0a1c8e8 100644
--- a/plugins/terminals/src/node/backend.ts
+++ b/plugins/terminals/src/node/backend.ts
@@ -53,7 +53,7 @@ async function loadZigpty(): Promise {
}
/**
- * Whether real pseudo-terminals are available in this runtime — i.e. zigpty's
+ * Whether real pseudo-terminals are available in this runtime, i.e. zigpty's
* native bindings loaded. Without them interactive sessions still run through
* zigpty's pipe-based emulation, with degraded TUI fidelity.
*/
@@ -64,7 +64,7 @@ export async function isPtyAvailable(): Promise {
/**
* Spawn an interactive terminal via zigpty. Uses a real PTY when the native
* bindings are available, and zigpty's pipe-based emulation (line discipline,
- * signal translation, best-effort resize) otherwise — the reported `backend`
+ * signal translation, best-effort resize) otherwise; the reported `backend`
* reflects which one the session got. Returns `undefined` when the module
* itself is unavailable or spawning throws.
*/
@@ -127,7 +127,7 @@ async function spawnPty(options: SpawnBackendOptions): Promise {
try {
// On Windows the backend may fall back to the TERM name rather than
- // the foreground process — don't surface that as a session label.
+ // the foreground process, so don't surface that as a session label.
const name = proc.process
return name && name !== PTY_TERM_NAME ? name : undefined
}
@@ -148,11 +148,10 @@ function spawnPipe(options: SpawnBackendOptions): TerminalProcess {
const exitCbs: ((code: number) => void)[] = []
let exited = false
- // A piped child has no controlling TTY, so its stdout/stderr carry bare `\n`
- // line endings — a real PTY would apply the kernel's ONLCR translation. xterm
- // only returns the cursor to column 0 on `\r`, so forwarding bare `\n` renders
- // a staircase. Translate lone `\n` to `\r\n`, tracking a `\r` left dangling at
- // a chunk boundary so an existing `\r\n` split across chunks isn't doubled.
+ // A piped child has no TTY, so its output carries bare `\n` (a PTY would apply
+ // ONLCR). xterm only returns to column 0 on `\r`, so bare `\n` renders a
+ // staircase. Translate lone `\n` to `\r\n`, tracking a dangling `\r` so a
+ // `\r\n` split across chunks isn't doubled.
let pendingCr = false
const normalizeNewlines = (data: string): string => {
const out = data.replace(/\r?\n/g, (match, offset: number) =>
diff --git a/plugins/terminals/src/node/index.ts b/plugins/terminals/src/node/index.ts
index ad9053656..49eb3e2ca 100644
--- a/plugins/terminals/src/node/index.ts
+++ b/plugins/terminals/src/node/index.ts
@@ -15,7 +15,7 @@ export { TerminalManager } from './manager'
* state, and register the control RPC functions. Returns the manager so
* callers can spawn sessions or dispose it on shutdown.
*
- * Works in any devframe runtime (CLI, Vite, build) — it only depends on the
+ * Works in any devframe runtime (CLI, Vite, build), since it only depends on the
* core `ctx.rpc` streaming + shared-state surface, not on the hub.
*/
export async function setupTerminals(
diff --git a/plugins/terminals/src/node/manager.ts b/plugins/terminals/src/node/manager.ts
index a4bbbd056..27c857d5e 100644
--- a/plugins/terminals/src/node/manager.ts
+++ b/plugins/terminals/src/node/manager.ts
@@ -97,8 +97,8 @@ const HUB_STATUS: Record = {
/**
* Normalize a hub dock icon (`ph:code-duotone`, or a light/dark pair) to the
* UnoCSS `preset-icons` class the client renders (`i-ph-code-duotone`). The
- * client can only render icons the SPA's UnoCSS build statically emitted — see
- * the safelist in `uno.config.ts` — so unknown icons resolve to `undefined`.
+ * client can only render icons the SPA's UnoCSS build statically emitted (see
+ * the safelist in `uno.config.ts`), so unknown icons resolve to `undefined`.
*/
function toIconClass(icon?: HubTerminalEntry['icon']): string | undefined {
const raw = typeof icon === 'string' ? icon : icon?.light
@@ -509,8 +509,8 @@ export class TerminalManager {
}
/**
- * Tear a single session down — kill its process, stop polling, dispose the
- * OSC inspector, close the sink, and drop it from the store — without
+ * Tear a single session down: kill its process, stop polling, dispose the
+ * OSC inspector, close the sink, and drop it from the store, all without
* publishing. Callers publish once they've finished mutating the store.
*/
private disposeSession(id: string, session: ManagedSession): void {
@@ -525,7 +525,7 @@ export class TerminalManager {
this.sessions.delete(id)
}
- /** Tear everything down — used on server shutdown and in tests. */
+ /** Tear everything down; used on server shutdown and in tests. */
dispose(): void {
for (const session of this.sessions.values()) {
this.stopProcessPoll(session)
@@ -559,7 +559,7 @@ export class TerminalManager {
/**
* Reflect the live session list into the hub's terminals subsystem when this
* devframe is mounted in a hub. `ctx.terminals` only exists on a
- * `DevframeHubContext`, so it's accessed by duck-typing — standalone runtimes
+ * `DevframeHubContext`, so it's accessed by duck-typing: standalone runtimes
* (CLI / Vite / build) have no such property and skip silently. This is what
* surfaces the plugin's sessions in the hub's own terminals panel.
*/
diff --git a/plugins/terminals/src/types.ts b/plugins/terminals/src/types.ts
index 36c07bba8..2d589d73f 100644
--- a/plugins/terminals/src/types.ts
+++ b/plugins/terminals/src/types.ts
@@ -1,10 +1,10 @@
/**
* How a session is driven.
*
- * - `interactive` — a PTY-backed session that accepts keystrokes, resize,
+ * - `interactive`: a PTY-backed session that accepts keystrokes, resize,
* and renders full-screen TUIs (vim, htop, Claude Code, …). Falls back to
* a piped child process when no PTY backend is available.
- * - `readonly` — a piped child process whose combined output is streamed to
+ * - `readonly`: a piped child process whose combined output is streamed to
* viewers; stdin is rejected. Ideal for long-running logs / dev servers.
*/
export type TerminalMode = 'interactive' | 'readonly'
@@ -57,7 +57,7 @@ export interface TerminalSessionInfo {
channel?: string
/**
* Whether the session may be restarted in place. `false` hides the restart
- * control and makes the restart RPC reject it — used for sessions whose
+ * control and makes the restart RPC reject it, used for sessions whose
* lifecycle is owned elsewhere (surfaced from the hub's `restartable` flag).
* Own sessions leave this unset (always restartable).
*/
@@ -139,7 +139,7 @@ export interface TerminalsOptions {
port?: number
/**
* Require the trust handshake on the standalone server. Enabled by
- * default — `--open` embeds the current OTP in the opened URL, so the
+ * default; `--open` embeds the current OTP in the opened URL, so the
* tab authenticates automatically without extra prompts. Hosted adapters
* manage their own auth and ignore this.
*/
diff --git a/plugins/terminals/test/_utils.ts b/plugins/terminals/test/_utils.ts
index e1009012e..f3f2693aa 100644
--- a/plugins/terminals/test/_utils.ts
+++ b/plugins/terminals/test/_utils.ts
@@ -38,8 +38,8 @@ export interface FakeHubTerminals {
}
/**
- * Minimal stand-in for the hub's `ctx.terminals` aggregation host — a sessions
- * map plus a `terminals:session:updated` emitter — so tests can exercise how the
+ * Minimal stand-in for the hub's `ctx.terminals` aggregation host (a sessions
+ * map plus a `terminals:session:updated` emitter), so tests can exercise how the
* terminals plugin surfaces sessions contributed by *other* devframes.
*/
export function createFakeHubTerminals(): FakeHubTerminals {
@@ -117,7 +117,7 @@ export interface TestClient {
}
/**
- * Minimal RPC + streaming client over the WS transport — mirrors the
+ * Minimal RPC + streaming client over the WS transport, mirroring the
* streaming-chat example harness. `connectDevframe` is skipped because it
* needs a browser-like environment for connection-meta lookup.
*/
diff --git a/plugins/terminals/test/terminals.test.ts b/plugins/terminals/test/terminals.test.ts
index 96784d737..6527511ac 100644
--- a/plugins/terminals/test/terminals.test.ts
+++ b/plugins/terminals/test/terminals.test.ts
@@ -189,7 +189,7 @@ describe('@devframes/plugin-terminals', () => {
const client = bootClient(server.port)
await new Promise(r => setTimeout(r, 50))
- // OSC parsing rides the output stream, so it works for every backend —
+ // OSC parsing rides the output stream, so it works for every backend;
// a readonly piped session keeps this test deterministic cross-platform.
const info = await call(client, 'devframes:plugin:terminals:spawn', {
command: NODE,
diff --git a/plugins/terminals/tsdown.config.ts b/plugins/terminals/tsdown.config.ts
index 322e846d2..60006a58d 100644
--- a/plugins/terminals/tsdown.config.ts
+++ b/plugins/terminals/tsdown.config.ts
@@ -11,13 +11,13 @@ const deps = {
],
}
-// Browser-loaded modules — the xterm-powered renderer. Kept in its own
+// Browser-loaded modules: the xterm-powered renderer. Kept in its own
// rolldown graph so node-only imports never leak into the client bundle.
const clientEntries = {
'client/index': 'src/client/index.ts',
}
-// Node + neutral modules — the devframe definition/factory, RPC functions,
+// Node + neutral modules: the devframe definition/factory, RPC functions,
// the PTY/child-process manager, and the host adapters.
const serverEntries = {
'index': 'src/index.ts',
@@ -29,9 +29,11 @@ const serverEntries = {
'types': 'src/types.ts',
}
-// Three configs:
-// 1. node server build (clean: true, outputs dist/node, dist/rpc, etc.)
-// 2. combined dts so augmentations resolve
+/**
+ * Three configs:
+ * 1. node server build (clean: true, outputs dist/node, dist/rpc, etc.)
+ * 2. combined dts so augmentations resolve
+ */
export default defineConfig([
{
clean: true,
diff --git a/plugins/terminals/uno.config.ts b/plugins/terminals/uno.config.ts
index 60579e3a1..d9768d3f2 100644
--- a/plugins/terminals/uno.config.ts
+++ b/plugins/terminals/uno.config.ts
@@ -1,17 +1,21 @@
import { mergeConfigs } from 'unocss'
import { designConfig } from '../../design/uno.config'
-// The terminals panel composes the shared devframe base (see
-// `design/uno.config.ts`) and adds only its own extraction globs and safelist.
-// Svelte is scanned by default; `.ts` (the co-located `design.ts` class helpers)
-// is opted in.
+/**
+ * The terminals panel composes the shared devframe base (see
+ * `design/uno.config.ts`) and adds only its own extraction globs and safelist.
+ * Svelte is scanned by default; `.ts` (the co-located `design.ts` class helpers)
+ * is opted in.
+ */
export default mergeConfigs([
designConfig,
{
- // Icons for terminal sessions contributed by *other* devframes through the
- // hub (e.g. code-server) arrive as runtime strings, so UnoCSS can't extract
- // them from source. Safelist the built-in plugins' dock icons so those
- // aggregated sessions render with their proper glyph.
+ /**
+ * Icons for terminal sessions contributed by *other* devframes through the
+ * hub (e.g. code-server) arrive as runtime strings, so UnoCSS can't extract
+ * them from source. Safelist the built-in plugins' dock icons so those
+ * aggregated sessions render with their proper glyph.
+ */
safelist: [
'i-ph-code-duotone',
'i-ph-terminal-window-duotone',
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 94f0e6402..3f0d7da48 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -350,14 +350,20 @@ catalogs:
version: 4.1.11
tooling:
'@antfu/eslint-config':
- specifier: ^9.3.0
- version: 9.3.0
+ specifier: ^9.5.1
+ version: 9.5.1
bumpp:
specifier: ^12.2.2
version: 12.2.2
eslint:
specifier: ^10.9.1
version: 10.9.1
+ eslint-plugin-slop:
+ specifier: ^0.1.1
+ version: 0.1.1
+ eslint-plugin-sonarjs:
+ specifier: ^4.2.0
+ version: 4.2.0
knip:
specifier: ^6.33.0
version: 6.33.0
@@ -439,7 +445,7 @@ importers:
version: 0.4.0(@antfu/utils@9.3.0)(@iconify-json/catppuccin@1.2.17)(@tanstack/vue-virtual@3.13.36(vue@3.5.42(typescript@6.0.3)))(@unocss/core@66.8.1)(colorjs.io@0.6.1)(dompurify@3.4.14)(floating-vue@5.2.2(vue@3.5.42(typescript@6.0.3)))(playwright@1.62.1)(reka-ui@2.10.4(vue@3.5.42(typescript@6.0.3)))(splitpanes@4.1.2(vue@3.5.42(typescript@6.0.3)))(unocss@66.8.1(@unocss/postcss@66.8.1(postcss@8.5.26))(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0)))(vue@3.5.42(typescript@6.0.3))
'@antfu/eslint-config':
specifier: catalog:tooling
- version: 9.3.0(@typescript-eslint/typescript-estree@8.67.0(supports-color@10.2.2)(typescript@6.0.3))(@typescript-eslint/utils@8.67.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3))(@vue/compiler-sfc@3.5.42)(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3)(vitest@4.1.11(@opentelemetry/api@1.9.1)(@types/node@26.4.0)(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0)))
+ version: 9.5.1(@typescript-eslint/typescript-estree@8.69.0(supports-color@10.2.2)(typescript@6.0.3))(@typescript-eslint/utils@8.69.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3))(@vue/compiler-sfc@3.5.42)(eslint-plugin-slop@0.1.1(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2)))(eslint-plugin-sonarjs@4.2.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2)))(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3)(vitest@4.1.11(@opentelemetry/api@1.9.1)(@types/node@26.4.0)(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0)))
'@antfu/utils':
specifier: catalog:inlined
version: 9.3.0
@@ -473,6 +479,12 @@ importers:
eslint:
specifier: catalog:tooling
version: 10.9.1(jiti@2.7.0)(supports-color@10.2.2)
+ eslint-plugin-slop:
+ specifier: catalog:tooling
+ version: 0.1.1(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))
+ eslint-plugin-sonarjs:
+ specifier: catalog:tooling
+ version: 4.2.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))
h3:
specifier: catalog:deps
version: 2.0.1-rc.29(crossws@0.4.12(srvx@0.12.7))
@@ -553,10 +565,10 @@ importers:
version: 1.2.4
'@shikijs/magic-move':
specifier: catalog:frontend
- version: 4.4.3(react@19.2.8)(shiki@4.4.3)(solid-js@1.9.15)(svelte@5.57.0(@typescript-eslint/types@8.67.0))(vue@3.5.42(typescript@6.0.3))
+ version: 4.4.3(react@19.2.8)(shiki@4.4.3)(solid-js@1.9.15)(svelte@5.57.0(@typescript-eslint/types@8.69.0))(vue@3.5.42(typescript@6.0.3))
comark-docs:
specifier: catalog:docs
- version: https://codeload.github.com/comarkdown/comark-docs/tar.gz/f97dc864b0aa702d54c600f868589b7a2c185b3a(patch_hash=5f1078be206123f957de74141ae02eaae510555cc7444404bffbfaae8d407e33)(16cf1b447d22766aa84945436e8d9e61)
+ version: https://codeload.github.com/comarkdown/comark-docs/tar.gz/f97dc864b0aa702d54c600f868589b7a2c185b3a(patch_hash=5f1078be206123f957de74141ae02eaae510555cc7444404bffbfaae8d407e33)(33a9239c8daf1432168431509a51f904)
d3-shape:
specifier: catalog:frontend
version: 3.2.0
@@ -1114,19 +1126,19 @@ importers:
devDependencies:
'@sveltejs/adapter-node':
specifier: catalog:build
- version: 5.5.7(@sveltejs/kit@2.70.3(@opentelemetry/api@1.9.1)(@sveltejs/vite-plugin-svelte@7.3.0(svelte@5.57.0(@typescript-eslint/types@8.67.0))(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0)))(svelte@5.57.0(@typescript-eslint/types@8.67.0))(typescript@6.0.3)(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0)))
+ version: 5.5.7(@sveltejs/kit@2.70.3(@opentelemetry/api@1.9.1)(@sveltejs/vite-plugin-svelte@7.3.0(svelte@5.57.0(@typescript-eslint/types@8.69.0))(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0)))(svelte@5.57.0(@typescript-eslint/types@8.69.0))(typescript@6.0.3)(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0)))
'@sveltejs/kit':
specifier: catalog:build
- version: 2.70.3(@opentelemetry/api@1.9.1)(@sveltejs/vite-plugin-svelte@7.3.0(svelte@5.57.0(@typescript-eslint/types@8.67.0))(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0)))(svelte@5.57.0(@typescript-eslint/types@8.67.0))(typescript@6.0.3)(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0))
+ version: 2.70.3(@opentelemetry/api@1.9.1)(@sveltejs/vite-plugin-svelte@7.3.0(svelte@5.57.0(@typescript-eslint/types@8.69.0))(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0)))(svelte@5.57.0(@typescript-eslint/types@8.69.0))(typescript@6.0.3)(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0))
'@sveltejs/vite-plugin-svelte':
specifier: catalog:frontend
- version: 7.3.0(svelte@5.57.0(@typescript-eslint/types@8.67.0))(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0))
+ version: 7.3.0(svelte@5.57.0(@typescript-eslint/types@8.69.0))(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0))
'@types/node':
specifier: catalog:types
version: 26.4.0
svelte:
specifier: catalog:frontend
- version: 5.57.0(@typescript-eslint/types@8.67.0)
+ version: 5.57.0(@typescript-eslint/types@8.69.0)
vite:
specifier: catalog:build
version: 8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0)
@@ -2380,10 +2392,10 @@ importers:
version: 1.2.2
'@storybook/svelte-vite':
specifier: catalog:storybook
- version: 10.5.10(@sveltejs/vite-plugin-svelte@7.3.0(svelte@5.57.0(@typescript-eslint/types@8.67.0))(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0)))(esbuild@0.28.2)(rollup@4.60.3)(storybook@10.5.10(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(svelte@5.57.0(@typescript-eslint/types@8.67.0))(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0))
+ version: 10.5.10(@sveltejs/vite-plugin-svelte@7.3.0(svelte@5.57.0(@typescript-eslint/types@8.69.0))(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0)))(esbuild@0.28.2)(rollup@4.60.3)(storybook@10.5.10(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(svelte@5.57.0(@typescript-eslint/types@8.69.0))(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0))
'@sveltejs/vite-plugin-svelte':
specifier: catalog:frontend
- version: 7.3.0(svelte@5.57.0(@typescript-eslint/types@8.67.0))(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0))
+ version: 7.3.0(svelte@5.57.0(@typescript-eslint/types@8.69.0))(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0))
'@types/node':
specifier: catalog:types
version: 26.4.0
@@ -2407,7 +2419,7 @@ importers:
version: 10.5.10(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)
svelte:
specifier: catalog:frontend
- version: 5.57.0(@typescript-eslint/types@8.67.0)
+ version: 5.57.0(@typescript-eslint/types@8.69.0)
tsdown:
specifier: catalog:build
version: 0.22.14(@volar/typescript@2.4.28(typescript@6.0.3))(oxc-resolver@11.24.2)(tsx@4.23.13)(typescript@6.0.3)
@@ -2502,7 +2514,7 @@ importers:
devDependencies:
'@antfu/eslint-config':
specifier: ^9.3.0
- version: 9.3.0(@typescript-eslint/typescript-estree@8.67.0(supports-color@10.2.2)(typescript@6.0.3))(@typescript-eslint/utils@8.67.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3))(@vue/compiler-sfc@3.5.42)(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3)(vitest@4.1.11(@opentelemetry/api@1.9.1)(@types/node@26.4.0)(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0)))
+ version: 9.3.0(@typescript-eslint/typescript-estree@8.69.0(supports-color@10.2.2)(typescript@6.0.3))(@typescript-eslint/utils@8.69.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3))(@vue/compiler-sfc@3.5.42)(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3)(vitest@4.1.11(@opentelemetry/api@1.9.1)(@types/node@26.4.0)(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0)))
'@playwright/test':
specifier: ^1.62.1
version: 1.62.1
@@ -2706,6 +2718,76 @@ packages:
svelte-eslint-parser:
optional: true
+ '@antfu/eslint-config@9.5.1':
+ resolution: {integrity: sha512-BoQGe5lY9spYmGqtUOC6hWohxob4SNn+7o5nHsOXoLn+9vJqNGqC/2/vRoXbcOa3dT4Rx/ZV/Qkr6uf72KTbxQ==}
+ hasBin: true
+ peerDependencies:
+ '@angular-eslint/eslint-plugin': ^21.1.0
+ '@angular-eslint/eslint-plugin-template': ^21.1.0
+ '@angular-eslint/template-parser': ^21.1.0
+ '@eslint-react/eslint-plugin': ^5.6.0
+ '@next/eslint-plugin-next': '>=15.0.0'
+ '@prettier/plugin-xml': ^3.4.1
+ '@unocss/eslint-plugin': '>=0.50.0'
+ astro-eslint-parser: '>=1.0.2'
+ eslint: ^9.10.0 || ^10.0.0
+ eslint-plugin-astro: '>=1.2.0'
+ eslint-plugin-erasable-syntax-only: ^0.7.1
+ eslint-plugin-format: '>=0.1.0'
+ eslint-plugin-jsx-a11y: '>=6.10.2'
+ eslint-plugin-react-refresh: ^0.5.0
+ eslint-plugin-slop: '>=0.1.1'
+ eslint-plugin-solid: ^0.17.0
+ eslint-plugin-sonarjs: '>=4.0.0'
+ eslint-plugin-svelte: '>=2.35.1'
+ eslint-plugin-vuejs-accessibility: ^2.4.1
+ prettier-plugin-astro: ^0.14.0
+ prettier-plugin-slidev: ^1.0.5
+ svelte-eslint-parser: '>=0.37.0'
+ peerDependenciesMeta:
+ '@angular-eslint/eslint-plugin':
+ optional: true
+ '@angular-eslint/eslint-plugin-template':
+ optional: true
+ '@angular-eslint/template-parser':
+ optional: true
+ '@eslint-react/eslint-plugin':
+ optional: true
+ '@next/eslint-plugin-next':
+ optional: true
+ '@prettier/plugin-xml':
+ optional: true
+ '@unocss/eslint-plugin':
+ optional: true
+ astro-eslint-parser:
+ optional: true
+ eslint-plugin-astro:
+ optional: true
+ eslint-plugin-erasable-syntax-only:
+ optional: true
+ eslint-plugin-format:
+ optional: true
+ eslint-plugin-jsx-a11y:
+ optional: true
+ eslint-plugin-react-refresh:
+ optional: true
+ eslint-plugin-slop:
+ optional: true
+ eslint-plugin-solid:
+ optional: true
+ eslint-plugin-sonarjs:
+ optional: true
+ eslint-plugin-svelte:
+ optional: true
+ eslint-plugin-vuejs-accessibility:
+ optional: true
+ prettier-plugin-astro:
+ optional: true
+ prettier-plugin-slidev:
+ optional: true
+ svelte-eslint-parser:
+ optional: true
+
'@antfu/install-pkg@1.1.0':
resolution: {integrity: sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==}
@@ -2956,6 +3038,17 @@ packages:
oxlint:
optional: true
+ '@e18e/eslint-plugin@0.8.0':
+ resolution: {integrity: sha512-js/TeM+XJyoJ2Zk4if5uTEchv3MEbqugc9gLgq8YdB6Dy+LvwGACpQiAwcul0r4LUl0TvhuzAKUeIUPtGp2cew==}
+ peerDependencies:
+ eslint: ^9.0.0 || ^10.0.0
+ oxlint: ^1.72.0
+ peerDependenciesMeta:
+ eslint:
+ optional: true
+ oxlint:
+ optional: true
+
'@emnapi/core@1.10.0':
resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==}
@@ -3003,6 +3096,10 @@ packages:
resolution: {integrity: sha512-WivZqV5jPTYDQJgIMp0hTsyQESKYNY6yCJr4b0l84tYtQntkAMkc6zARh2vlRQyeg4aYHPUkCUDpvr2IWAiGpQ==}
engines: {node: ^22.22.2 || >=24.15.0}
+ '@es-joy/jsdoccomment@0.95.1':
+ resolution: {integrity: sha512-LO/RI08Fo9bhXwB7Od9G+1j3eSNq63+ZS5CQO8YLXHbDg6kx6S/DhTeY0+Fc9uZrjK1zZSyTx8Sg5gv5DIoCnA==}
+ engines: {node: ^22.22.2 || >=24.15.0}
+
'@es-joy/resolve.exports@1.2.0':
resolution: {integrity: sha512-Q9hjxWI5xBM+qW2enxfe8wDKdFWMfd0Z29k5ZJnuBqD/CasY5Zryj09aCA6owbGATWz+39p5uIdaHXpopOcG8g==}
engines: {node: '>=10'}
@@ -3325,6 +3422,12 @@ packages:
peerDependencies:
eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0
+ '@eslint-community/eslint-utils@4.10.1':
+ resolution: {integrity: sha512-cuadcxVFE8sDK6iWJbs8Sn0av2Nrh2QSGQhVlBW9AaAHqHwjWsZHT8LJ4hFGPh7ASBV2deFdM7H/DPjulmh8rg==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ peerDependencies:
+ eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
+
'@eslint-community/eslint-utils@4.9.1':
resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@@ -3364,6 +3467,10 @@ packages:
resolution: {integrity: sha512-nxMparyhqVWQvadx9x8dIfubfIPOE+X2b2waua8fzdnM9vdp9rgVtwEZlG0TmCwEUz/d/f40fzvO/eqBwdxz0A==}
engines: {node: ^20.19.0 || ^22.13.0 || >=24}
+ '@eslint/css-tree@4.1.0':
+ resolution: {integrity: sha512-cg0ohyrAG3swyGqt8t1K/OK97DqBw/ftDvlvyY1fmEst5B40UOmsimwLENq74z2dyw5CDM+3zJIW+CV2nFNDdA==}
+ engines: {node: ^20.19.0 || ^22.13.0 || >=24}
+
'@eslint/markdown@8.0.3':
resolution: {integrity: sha512-rBTSSShrq7e4O+PWfeE4azH4/CWPNrC+VGxBXiW00o3vYVJnznsZiDayj3KC9JztIMVRZxZHn2nrDIUau/4j7A==}
engines: {node: ^20.19.0 || ^22.13.0 || >=24}
@@ -6571,6 +6678,14 @@ packages:
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
typescript: '>=4.8.4 <6.1.0'
+ '@typescript-eslint/eslint-plugin@8.69.0':
+ resolution: {integrity: sha512-t5jQTKPIgVW1PE6dR6H6Qz5gm8zjMlX5/2gRaOGd9eO6V7J+tQc6iWKukEe7dY8u9HyYasQ0yfF0/FSSTEO2gA==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ '@typescript-eslint/parser': ^8.69.0
+ eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
+ typescript: '>=4.8.4 <6.1.0'
+
'@typescript-eslint/parser@8.67.0':
resolution: {integrity: sha512-fUBfTuuEulWqX6V8+O3PtScV01tzYYRUDTAirHFKoRAt7nOzoGiPt0M/bB47wWNy0coOOcgEwAMUtBpykMxl6w==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@@ -6578,22 +6693,45 @@ packages:
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
typescript: '>=4.8.4 <6.1.0'
+ '@typescript-eslint/parser@8.69.0':
+ resolution: {integrity: sha512-l4b0DhWioGg6Gt2ebGlvfkFMOjRsauxtsnDRwUSRX1qHq3HdTfQHV8wW9zEXeciai6HfeaKOedQn2Zoofx3WBw==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
+ typescript: '>=4.8.4 <6.1.0'
+
'@typescript-eslint/project-service@8.67.0':
resolution: {integrity: sha512-cvE8c7ulYeXN9fYuszhCeCsbzyVEXuhrRCybnBre7TUmqb5nRmBfQAwCj0O3WJFDeyAZt4VYv51vMCC9LHSdYw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
typescript: '>=4.8.4 <6.1.0'
+ '@typescript-eslint/project-service@8.69.0':
+ resolution: {integrity: sha512-yi4obFrHMmnsesWehHbkg9zMA7Jt8cXT+mKM08G999pH1yT6nqgsHx7MYm0uY1wAj8CqiBXYRJ7WAT0QdQHQXg==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ typescript: '>=4.8.4 <6.1.0'
+
'@typescript-eslint/scope-manager@8.67.0':
resolution: {integrity: sha512-EgvsleTwS4E+WzzSvem8fAUubLwatMNF1B5hHSLQxcvs7q2dtRhGyujHwLJSYlG41niJ7GP24Aha2+0mb1b2kg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ '@typescript-eslint/scope-manager@8.69.0':
+ resolution: {integrity: sha512-ewfspqWvSxKSOaplqAUNbaSFO0eB6w1EtQ+esfYFRm3614Ty4uNtExkcbgd6nWsXphbqKyf9ZYdbZdv2xEoWEQ==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
'@typescript-eslint/tsconfig-utils@8.67.0':
resolution: {integrity: sha512-vV+LUSv5njUWsknE71fqKTlXUva+R76SaeORd6Zojcunk/6DvKFXONU3BrAs2H49mbygUXt6gbYunzwqNwlhdg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
typescript: '>=4.8.4 <6.1.0'
+ '@typescript-eslint/tsconfig-utils@8.69.0':
+ resolution: {integrity: sha512-xNqK7YTDZsLniQMV/4rpFR8Z5JlqeRvVjuG1YgF/mdPVH84HSD19L8CczMA0qg2RfwEV231GHH3VnToJDo4MfQ==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ typescript: '>=4.8.4 <6.1.0'
+
'@typescript-eslint/type-utils@8.67.0':
resolution: {integrity: sha512-aVWDXbRmdXO9siTfX4ditQI1T9+zVcNazT48EJCD0v40/9RIFoUgZ05CmGEq9H2gixRpjUn/iplwvlcvutJW/Q==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@@ -6601,16 +6739,33 @@ packages:
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
typescript: '>=4.8.4 <6.1.0'
+ '@typescript-eslint/type-utils@8.69.0':
+ resolution: {integrity: sha512-ZfoJAVg3JZndQEpEl9petVlxau3lRuElc4HRMuAlLCf8to04/iHz692RUSNmXKDjEuJmIL+KZ2/BsOcBc16dsA==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
+ typescript: '>=4.8.4 <6.1.0'
+
'@typescript-eslint/types@8.67.0':
resolution: {integrity: sha512-sBtgslww8nsMYUjhdPBiSyUqSzT8uR6g93A2QXnQC8+cGdjz0CyaOdqHDRJb1AtORbZCNUJBBeFA/tNR2uQmww==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ '@typescript-eslint/types@8.69.0':
+ resolution: {integrity: sha512-K3VrubUPhlo9VDBS6QdI8YB5j7ClpqLRdefcz6PFrhnwicehBweqQ9Evhl4l+FYz0HdDmMqIiSX0aldGRYtDCA==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
'@typescript-eslint/typescript-estree@8.67.0':
resolution: {integrity: sha512-EKQBCE9yNlRJYm7jdTW5AhDacDUmSwQb0FAJAmK2EKYrNXIsa2vxcSZx6PvJ/dEdI6lS+Y9W+EXckLj0iPFGcw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
typescript: '>=4.8.4 <6.1.0'
+ '@typescript-eslint/typescript-estree@8.69.0':
+ resolution: {integrity: sha512-AdFkgqck3Vudb/kWnxlyafU/4aBhHrbQ9locP2N4psXTy5mOBg0SHJumnLvx7r6g1gV4DKvUFwV2nJZBoqOD8w==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ typescript: '>=4.8.4 <6.1.0'
+
'@typescript-eslint/utils@8.67.0':
resolution: {integrity: sha512-U9D1FdwEWBwok3hxxSdhclMb0twvt9QnjIQ0VfQ1AiX2epnpSgv2ubVDsayOFyY8K6FX+AQ7E0FKWVG3iKsj1A==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@@ -6618,10 +6773,21 @@ packages:
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
typescript: '>=4.8.4 <6.1.0'
+ '@typescript-eslint/utils@8.69.0':
+ resolution: {integrity: sha512-tUbx60BBqQa31kXF5MCsOOLL5E/WzUuxIn7YpAvq+eaUlqvk8/NXnXMBNAdLCr0icjkzem7iUA5QqWHe/hJ1aw==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
+ typescript: '>=4.8.4 <6.1.0'
+
'@typescript-eslint/visitor-keys@8.67.0':
resolution: {integrity: sha512-fkv8dHRDqfGtTHuJeebdrQ7cX6Ad4WAS00rgHh9UGvMycF1mjBfsxry1XsLIFhWZ6Judlh6UdzK+TYlbpCXgnA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ '@typescript-eslint/visitor-keys@8.69.0':
+ resolution: {integrity: sha512-+rmdgPA+EXkNgKYvHvFfhrs35utXbwaC5PGpDquSXcoXQDKUA5UjV0LmTucG/4JXkM31BTu4TilHtrN8IVBe8w==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
'@typescript/typescript6@6.0.2':
resolution: {integrity: sha512-mbCddXd+jm7hfx7w2YU64/Av4/NqqeG3GoRZgxPcgoTxYjhrcfJRw9ULch71SS4G+Q3bOXFhRvPqjguN0Hyp5w==}
hasBin: true
@@ -7334,6 +7500,10 @@ packages:
resolution: {integrity: sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==}
engines: {node: '>=14'}
+ are-docs-informative@0.1.1:
+ resolution: {integrity: sha512-sqRsNQBwbKLRX0jV5Cu5uzmtflf892n4Vukz7T659ebL4pz3mpOqCMU7lxMoBTFwnp10E3YB5ZcyHM41W5bcDA==}
+ engines: {node: '>=18'}
+
argparse@1.0.10:
resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==}
@@ -7495,6 +7665,11 @@ packages:
engines: {node: '>=6.0.0'}
hasBin: true
+ baseline-browser-mapping@2.11.20:
+ resolution: {integrity: sha512-H0ulySigv6icDJ1F7SjtdCD6PrhTpdYCmP0CactWy1+ekh0AFd0o1Wn5T8b+hnTmdBx19u9yhL6wvCylXMY7zw==}
+ engines: {node: '>=6.0.0'}
+ hasBin: true
+
beautiful-mermaid@1.1.3:
resolution: {integrity: sha512-TItrtrAyHp1vwFfFVYauWGrquouk/6SS21Aq3RsxindSYZODcN4xYrPZD6BiZRU+o5mKJzDPz9MUSMvELdylyg==}
@@ -7530,6 +7705,11 @@ packages:
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
hasBin: true
+ browserslist@4.28.8:
+ resolution: {integrity: sha512-V2NpofLblG64mfOtSgDhOJESZEGogzDMBv/q+W6oc4LXWP/q75eOXoOaaOu1EOadB9U4Bwx/e0yzbvwKH8zalA==}
+ engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
+ hasBin: true
+
buffer-crc32@1.0.0:
resolution: {integrity: sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==}
engines: {node: '>=8.0.0'}
@@ -7540,6 +7720,10 @@ packages:
buffer@6.0.3:
resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==}
+ builtin-modules@3.3.0:
+ resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==}
+ engines: {node: '>=6'}
+
builtin-modules@5.2.0:
resolution: {integrity: sha512-02yxLeyxF4dNl6SlY6/5HfRSrSdZ/sCPoxy2kZNP5dZZX8LSAD9aE2gtJIUgWrsQTiMPl3mxESyrobSwvRGisQ==}
engines: {node: '>=18.20'}
@@ -7586,6 +7770,9 @@ packages:
caniuse-lite@1.0.30001806:
resolution: {integrity: sha512-72Cuvd95zbSYPKq6Fhg8eDJRlzgWDf7/mtoZv6Qe/DYNCEBdNxoA3+rZAU2ZhGCpZlns3EssFavaZomckT5Uuw==}
+ caniuse-lite@1.0.30001810:
+ resolution: {integrity: sha512-TITQPUkaz+aVk5GL6NhOdwk1aEaNTSDPsGFWrTuhKGtjTF70jL/Oht2W4c6rXUe5fu7Ie19VIahAXHIIiWWNeg==}
+
ccount@2.0.1:
resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==}
@@ -7731,6 +7918,10 @@ packages:
resolution: {integrity: sha512-0h+uSNtQGW3D98eQt3jJ8L06Fves8hncB4V/PKdw/Qb8Hnk19VaKuTr55UNRYiSoVa7WwrFls+rh3ux9agmkeQ==}
engines: {node: '>= 12.0.0'}
+ comment-parser@1.4.8:
+ resolution: {integrity: sha512-rKZTGo4fzKYna8UcL0isTg5wkBNla7bxTypLwZQXjIdi++IdP1OJ41rI5Mti3/jltkPujbu4i9LIARYA+zpotQ==}
+ engines: {node: '>= 12.0.0'}
+
commondir@1.0.1:
resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==}
@@ -7801,6 +7992,10 @@ packages:
core-js-compat@3.49.0:
resolution: {integrity: sha512-VQXt1jr9cBz03b331DFDCCP90b3fanciLkgiOoy8SBHy06gNf+vQ1A3WFLqG7I8TipYIKeYK9wxd0tUrvHcOZA==}
+ core-js-compat@3.50.0:
+ resolution: {integrity: sha512-XGpFGbMLHwSt74YLTKho7Ib242qi6O8MSX+sRokV4oz7iKXvQWGYZthjIhjRGMxjzVkAubBO512dKGYcefmX3Q==}
+ engines: {node: '>=6.4.0'}
+
core-util-is@1.0.3:
resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==}
@@ -8092,6 +8287,9 @@ packages:
electron-to-chromium@1.5.393:
resolution: {integrity: sha512-kiDJdIUawuEIcp9XoICKp1iTYDEbgguIPq526N1Q7jIQDeQ3CqoMx71025PI/7E48Ddtw2HuWsVjY7afEgNxmg==}
+ electron-to-chromium@1.5.420:
+ resolution: {integrity: sha512-2yD6XreGusOfNV+dUcvipJEXc3n/n7fgr7996aszTG+YY5E4mqM4tOq/3uhP129cazL9YHbVWSpc79ePotWtPA==}
+
elkjs@0.11.1:
resolution: {integrity: sha512-zxxR9k+rx5ktMwT/FwyLdPCrq7xN6e4VGGHH8hA01vVYKjTFik7nHOxBnAYtrgYUB1RpAiLvA1/U2YraWxyKKg==}
@@ -8258,6 +8456,11 @@ packages:
peerDependencies:
eslint: ^9.5.0 || ^10.0.0
+ eslint-config-flat-gitignore@2.4.0:
+ resolution: {integrity: sha512-JhYC+V7qEDiCDsbJcVP8fxNc62fk4+i91YLP/YvmVHlkaQ8Xo99olYN8MO5COdxl7onGlsrfZVONe5NYsZP1UA==}
+ peerDependencies:
+ eslint: ^9.5.0 || ^10.0.0
+
eslint-flat-config-utils@3.2.0:
resolution: {integrity: sha512-PHgo1X5uqIorJONLVD9BIaOSdoYFD3z/AeJljdqDPlWVRpeCYkDbK9k0AXoYVqqNJr6FEYIEr5Rm2TSktLQcHw==}
@@ -8308,12 +8511,24 @@ packages:
peerDependencies:
eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0
+ eslint-plugin-jsdoc@64.3.4:
+ resolution: {integrity: sha512-aZZp44/yc6UTuH6U+cp1IVTTImfP2gd4JTuc+zMoB76ZI746avwbAqbdTejlKDFIYl6gBBhx3FG+jTRPZjnSXw==}
+ engines: {node: ^22.22.2 || >=24.15.0}
+ peerDependencies:
+ eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0
+
eslint-plugin-jsonc@3.4.1:
resolution: {integrity: sha512-HHWkjAmVJ3QAffCkfo0XKl3CstLtgbIu5EGfFfVDLQT6vqPrxl4pFbUwFwY03nOlvyuDiiBixhHFrlbzn9u09Q==}
engines: {node: ^20.19.0 || ^22.13.0 || >=24}
peerDependencies:
eslint: '>=9.38.0'
+ eslint-plugin-jsonc@3.4.2:
+ resolution: {integrity: sha512-q5xzjCYFQuhFomTbctXzd3STfDJ8XduvaigjQmMEbP2gzSKrc58y3Fv6D775/cIK1/sRUn+4kpljiU2iW8k0zw==}
+ engines: {node: ^20.19.0 || ^22.13.0 || >=24}
+ peerDependencies:
+ eslint: '>=9.38.0'
+
eslint-plugin-n@18.2.2:
resolution: {integrity: sha512-gOO0lIqwEjZ750kv9/SptCWArUoAZXJoBr0vYWTO2dCBxctHUXlBIigiC8xuxxr/NKqgIT6Ehz1xRcilj8a5cA==}
engines: {node: ^20.19.0 || ^22.13.0 || >=24}
@@ -8327,6 +8542,19 @@ packages:
typescript:
optional: true
+ eslint-plugin-n@18.3.0:
+ resolution: {integrity: sha512-cPVguuDe6DrIPb/qUXHf8P89MaVTUmiYWwpt5gX5AILsvRIiZAxMFXcFR6QHYBksqKJpjfUBlL/RleCJUWcD7w==}
+ engines: {node: ^20.19.0 || ^22.13.0 || >=24}
+ peerDependencies:
+ eslint: '>=8.57.1'
+ ts-declaration-location: ^1.0.6
+ typescript: '>=5.0.0'
+ peerDependenciesMeta:
+ ts-declaration-location:
+ optional: true
+ typescript:
+ optional: true
+
eslint-plugin-no-only-tests@3.4.0:
resolution: {integrity: sha512-4S3/9Nb7A2tiMcpzEQE9bQSlpeOz6WJkgryBuou/SA8W2x2c8Zf4j0NvTKBjv6qNhF9T79tmkecm/0CHqV0UGg==}
engines: {node: '>=5.0.0'}
@@ -8342,12 +8570,33 @@ packages:
peerDependencies:
eslint: ^9.0.0 || ^10.0.0
+ eslint-plugin-pnpm@1.9.1:
+ resolution: {integrity: sha512-8++1Egww2cqc9Wylmt7P+xXNMQVCosAZ4m4W4Gc0V5lGea8HFByHTRvUI+ZvvpO8fLXGg2O4MQc90EhuI3mMdQ==}
+ peerDependencies:
+ eslint: ^9.0.0 || ^10.0.0
+
eslint-plugin-regexp@3.1.1:
resolution: {integrity: sha512-MxR5nqoQCtVWmJwia0D2+NlXX1xzdpkslsVOZLEYQ4PQWEaL65PCZXURxaBc3lPnkNFpNxzMIRmYVxdl8giXRA==}
engines: {node: ^20.19.0 || ^22.13.0 || >=24}
peerDependencies:
eslint: '>=9.38.0'
+ eslint-plugin-regexp@3.2.0:
+ resolution: {integrity: sha512-4yq47CnLxyfHFKJEo5kvNaiJ0aDtBxSJWk4M2LiamplUXdWxdlzDYqImb/ZVCp+2BqkQjBAmw4Xc07Q8SXVDZg==}
+ engines: {node: ^20.19.0 || ^22.13.0 || >=24}
+ peerDependencies:
+ eslint: '>=9.38.0'
+
+ eslint-plugin-slop@0.1.1:
+ resolution: {integrity: sha512-Zcp3WvGF1uC1599Sg0ZZr9kFa/9nGYEDBbw+ZePXD/tuS0MhiiHXv2u5jTtOk1Ou9yxCoG5t3LqFDAV4T7Z9FA==}
+ peerDependencies:
+ eslint: ^10.0.0
+
+ eslint-plugin-sonarjs@4.2.0:
+ resolution: {integrity: sha512-bqADfuNtTL7VK6RU29eoiFTtaaBKIpVPuX3bOl+rBpWSBa0zIBVZlqZNZQjfP6s4iXkAJokv5IsD8OsACkwApg==}
+ peerDependencies:
+ eslint: ^8.0.0 || ^9.0.0 || ^10.0.0
+
eslint-plugin-toml@1.5.0:
resolution: {integrity: sha512-qBjRywEkKxO2uYOjus//6GVF1r+Hg5QDkRO8RTY6XcaXgWfBU0DhwpFmJa2Ljf0Sz49r7DdZlpKwwHmJ4nmH1Q==}
engines: {node: ^20.19.0 || ^22.13.0 || >=24}
@@ -8360,6 +8609,12 @@ packages:
peerDependencies:
eslint: '>=10.4'
+ eslint-plugin-unicorn@74.0.0:
+ resolution: {integrity: sha512-AGnsGi2SxHg1HEAXxn9nSnZfyjvTWkxm8E8hpd/9tD6dLjBUdcD7+D6ZN64HmmCXTSXlrwVyUqe20Uyb2CaurA==}
+ engines: {node: '>=22'}
+ peerDependencies:
+ eslint: '>=10.4'
+
eslint-plugin-unused-imports@4.4.1:
resolution: {integrity: sha512-oZGYUz1X3sRMGUB+0cZyK2VcvRX5lm/vB56PgNNcU+7ficUCKm66oZWKUubXWnOuPjQ8PvmXtCViXBMONPe7tQ==}
peerDependencies:
@@ -8718,6 +8973,9 @@ packages:
resolution: {integrity: sha512-939eZS4gJ3htTHAldmyyuzlrD58P03fHG49v2JfFXbV6OhvZKRC9j2yAtdHw/zrp2zXHuv05zMIy40F0ge7spA==}
engines: {node: '>=18'}
+ functional-red-black-tree@1.0.1:
+ resolution: {integrity: sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==}
+
fuse.js@7.5.0:
resolution: {integrity: sha512-sQtrEfA+ez/3G0cCZecF70oqpCRttCexYUG4mUrtWL49ULUzUyxokt5kyqwtKzj1270RaKih+hcP3qLcumccow==}
engines: {node: '>=10'}
@@ -8802,6 +9060,10 @@ packages:
resolution: {integrity: sha512-V0kztuWST2k8A/VbxAY8+L+7+Rgo3fyA24IHRLrZp7HOzJjV0gHSaZUjK9lpP/IrBSNite2tZ1prhRkinRu1CA==}
engines: {node: '>=18'}
+ globals@17.12.0:
+ resolution: {integrity: sha512-cezEd/DTyyht9cvSSURyygXPfy04GtWO/5e6ZPvH7fCtjKz9PYOmuawphw1Ctd1f6C+5JypXfGD7ahNMXvevBA==}
+ engines: {node: '>=18'}
+
globby@16.2.0:
resolution: {integrity: sha512-QrJia2qDf5BB/V6HYlDTs0I0lBahyjLzpGQg3KT7FnCdTonAyPy2RtY802m2k4ALx6Dp752f82WsOczEVr3l6Q==}
engines: {node: '>=20'}
@@ -9183,6 +9445,10 @@ packages:
resolution: {integrity: sha512-1LJ/negRKJxH0+ulOsJYEpUgzIs1DAOz9QctuS4In2LW/Ro3l8C4ej5al+5FU2hBGEOAY3R3SCnP6x8226JMIw==}
engines: {node: ^22.22.2 || >=24.15.0}
+ jsdoc-type-pratt-parser@9.1.2:
+ resolution: {integrity: sha512-9EXymowgk1mb9RY1VxuwKc+AhaxfBk2CV0dWxgGM+l5RURTtiUoAx7MlKwcsiVcEXK5HEPa7FeH/tsRpqjEPRg==}
+ engines: {node: ^22.22.2 || >=24.15.0}
+
jsesc@3.1.0:
resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==}
engines: {node: '>=6'}
@@ -9218,12 +9484,20 @@ packages:
resolution: {integrity: sha512-75EA7EWZExL/j+MDKQrRbdzcRI2HOkRlmUw8fZJc1ioqFEOvBsq7Rt+A6yCxOt9w/TYNpkt52gC6nm/g5tFIng==}
engines: {node: ^20.19.0 || ^22.13.0 || >=24}
+ jsonc-eslint-parser@3.3.0:
+ resolution: {integrity: sha512-hYTGkHGNRZnXOFZ1urhINADoqDrGfpy53cjw+dxk84QE0pUDujQzeUeamNs6Mz44/TKD49z2x6/GVSu4ZrtA+Q==}
+ engines: {node: ^20.19.0 || ^22.13.0 || >=24}
+
jsonc-parser@3.3.1:
resolution: {integrity: sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==}
jstransformer@1.0.0:
resolution: {integrity: sha512-C9YK3Rf8q6VAPDCCU9fnqo3mAfOH6vUGnMcP4AQAYIEpWtfGLpwOTmZ+igtdK5y+VvI2n3CyYSzy4Qh34eq24A==}
+ jsx-ast-utils-x@0.1.0:
+ resolution: {integrity: sha512-eQQBjBnsVtGacsG9uJNB8qOr3yA8rga4wAaGG1qRcBzSIvfhERLrWxMAM1hp5fcS6Abo8M4+bUBTekYR0qTPQw==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
katex@0.16.45:
resolution: {integrity: sha512-pQpZbdBu7wCTmQUh7ufPmLr0pFoObnGUoL/yhtwJDgmmQpbkg/0HSVti25Fu4rmd1oCR6NGWe9vqTWuWv3GcNA==}
hasBin: true
@@ -9466,6 +9740,9 @@ packages:
lodash.isarguments@3.1.0:
resolution: {integrity: sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==}
+ lodash.merge@4.6.2:
+ resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
+
lodash@4.18.1:
resolution: {integrity: sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==}
@@ -9587,6 +9864,9 @@ packages:
mdn-data@2.28.1:
resolution: {integrity: sha512-U9w+PzSZ00Z5m9rZ5ARVFL5xOfuCHdKYi/1RRwDCJsboFgJDNT3zT6PIPD7mZQYaQLhsZM3GfDRgSMRHhSmVng==}
+ mdn-data@2.34.0:
+ resolution: {integrity: sha512-OgIlLv0NxJKVW4GTSAoEgpRGd4F2XCqGinK0MsMlBCCS/Zcm2/LsbercNWNA7PeMMcjl75NnI97eqyo7zkdxWA==}
+
mdurl@2.1.0:
resolution: {integrity: sha512-1+HBaOx0zi/dQWht8rNv9MYf9qqpqL/kxI0hXImU6Y547zM6Sni8BQibt7ifgMcYtQg41ao3Ivd6cnSM86inpg==}
@@ -9763,6 +10043,9 @@ packages:
module-replacements@3.0.0:
resolution: {integrity: sha512-tHIZqde+RlyNRobAIjfcH5UIgIrEbZbDGRL6J/x+HERX/g8O9mrm0p6knJbsTXmQtDvZ+eFP+xfOP3/9jHk6YA==}
+ module-replacements@3.3.0:
+ resolution: {integrity: sha512-AVZL23uePazQOZlb/QMGwxsUa1oWA62Cfe6ApPzgasUoF4cdCWAiRPVq4KkaQzXbIDAlpLhLG61Jx8Lju4wjTg==}
+
motion-dom@13.0.0:
resolution: {integrity: sha512-Xk+SJas70uMAUIApg+m3lZDShxI3LBFHq7mFGbBKoRXc2PVPDyAKmzN64Bbzt4CZdP/CItTiJxWtn4TA0v53Ng==}
@@ -9911,6 +10194,10 @@ packages:
resolution: {integrity: sha512-wRNIrw4DmVLKQlbgOMdkMx27Wrpzes2hh5Jtbi2bjPd+4wJstWIqP5A+lscnqbm0xxmT5Bpg8Lec5ItEBwx6BQ==}
engines: {node: '>=18'}
+ node-releases@2.0.54:
+ resolution: {integrity: sha512-YHs7BmmcsdAI5Ozuf8JZo6PT0mv2GIWC9vMfvUC3dp65M8hn7Ux8CPL+2oBI7juNuj9d0ndhTcznq2ODBps9cQ==}
+ engines: {node: '>=18'}
+
nopt@8.1.0:
resolution: {integrity: sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A==}
engines: {node: ^18.17.0 || >=20.5.0}
@@ -10324,6 +10611,9 @@ packages:
pnpm-workspace-yaml@1.7.0:
resolution: {integrity: sha512-cgjaozHkjWL4H8oKZydEWE4mg31XydK3/1cLKjHvwnFAXutp45yAlMKljpOdZEq4TtLuzYAMvy9j05wRm3aoPw==}
+ pnpm-workspace-yaml@1.9.1:
+ resolution: {integrity: sha512-Xj/T2X6DNAWbtk/9UQ0/TJRswltiHZevmcMjqoL7WrpJi67lu3qaslU4+I+zJ8wtwqmuvAE0KkB8rbv2ZdogBg==}
+
postcss-calc@10.1.1:
resolution: {integrity: sha512-NYEsLHh8DgG/PRH2+G9BTuUdtf9ViS+vdoQ0YA5OQdGsfN4ztiwtDWNtBl9EKeqNMFnIu8IKZ0cLxEQ5r5KVMw==}
engines: {node: ^18.12 || ^20.9 || >=22.0}
@@ -11874,6 +12164,12 @@ packages:
peerDependencies:
browserslist: '>= 4.21.0'
+ update-browserslist-db@1.3.2:
+ resolution: {integrity: sha512-UQ+MSxlhRm1bzjhU+DcuXfjFO1FzNtqhK5+9Yvlp90ItDLk5vT932A0rFu619nf7RVS+Y/VeaUW1jaRDqZ8VJw==}
+ hasBin: true
+ peerDependencies:
+ browserslist: '>= 4.21.0'
+
uqr@0.1.3:
resolution: {integrity: sha512-0rjE8iEJe4YmT9TOhwsZtqCMRLc5DXZUI2UEYUUg63ikBkqqE5EYWaI0etFe/5KUcmcYwLih2RND1kq+hrUJXA==}
@@ -12460,7 +12756,7 @@ snapshots:
reka-ui: 2.10.4(vue@3.5.42(typescript@6.0.3))
splitpanes: 4.1.2(vue@3.5.42(typescript@6.0.3))
- '@antfu/eslint-config@9.3.0(@typescript-eslint/typescript-estree@8.67.0(supports-color@10.2.2)(typescript@6.0.3))(@typescript-eslint/utils@8.67.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3))(@vue/compiler-sfc@3.5.42)(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3)(vitest@4.1.11(@opentelemetry/api@1.9.1)(@types/node@26.4.0)(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0)))':
+ '@antfu/eslint-config@9.3.0(@typescript-eslint/typescript-estree@8.69.0(supports-color@10.2.2)(typescript@6.0.3))(@typescript-eslint/utils@8.69.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3))(@vue/compiler-sfc@3.5.42)(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3)(vitest@4.1.11(@opentelemetry/api@1.9.1)(@types/node@26.4.0)(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0)))':
dependencies:
'@antfu/install-pkg': 2.0.1
'@clack/prompts': 1.7.0
@@ -12478,7 +12774,7 @@ snapshots:
eslint-flat-config-utils: 3.2.0
eslint-merge-processors: 2.0.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))
eslint-plugin-antfu: 3.2.3(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))
- eslint-plugin-command: 4.0.0(@typescript-eslint/typescript-estree@8.67.0(supports-color@10.2.2)(typescript@6.0.3))(@typescript-eslint/utils@8.67.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3))(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))
+ eslint-plugin-command: 4.0.0(@typescript-eslint/typescript-estree@8.69.0(supports-color@10.2.2)(typescript@6.0.3))(@typescript-eslint/utils@8.69.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3))(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))
eslint-plugin-import-lite: 0.6.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))
eslint-plugin-jsdoc: 63.3.3(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)
eslint-plugin-jsonc: 3.4.1(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))
@@ -12510,6 +12806,59 @@ snapshots:
- typescript
- vitest
+ '@antfu/eslint-config@9.5.1(@typescript-eslint/typescript-estree@8.69.0(supports-color@10.2.2)(typescript@6.0.3))(@typescript-eslint/utils@8.69.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3))(@vue/compiler-sfc@3.5.42)(eslint-plugin-slop@0.1.1(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2)))(eslint-plugin-sonarjs@4.2.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2)))(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3)(vitest@4.1.11(@opentelemetry/api@1.9.1)(@types/node@26.4.0)(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0)))':
+ dependencies:
+ '@antfu/install-pkg': 2.0.1
+ '@clack/prompts': 1.7.0
+ '@e18e/eslint-plugin': 0.8.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))
+ '@eslint-community/eslint-plugin-eslint-comments': 4.7.2(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))
+ '@eslint/markdown': 8.0.3(supports-color@10.2.2)
+ '@stylistic/eslint-plugin': 5.10.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))
+ '@typescript-eslint/eslint-plugin': 8.69.0(@typescript-eslint/parser@8.69.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3))(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3)
+ '@typescript-eslint/parser': 8.69.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3)
+ '@vitest/eslint-plugin': 1.6.27(@typescript-eslint/eslint-plugin@8.69.0(@typescript-eslint/parser@8.69.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3))(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3))(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3)(vitest@4.1.11(@opentelemetry/api@1.9.1)(@types/node@26.4.0)(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0)))
+ ansis: 4.3.1
+ cac: 7.0.0
+ eslint: 10.9.1(jiti@2.7.0)(supports-color@10.2.2)
+ eslint-config-flat-gitignore: 2.4.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))
+ eslint-flat-config-utils: 3.2.0
+ eslint-merge-processors: 2.0.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))
+ eslint-plugin-antfu: 3.2.3(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))
+ eslint-plugin-command: 4.0.0(@typescript-eslint/typescript-estree@8.69.0(supports-color@10.2.2)(typescript@6.0.3))(@typescript-eslint/utils@8.69.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3))(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))
+ eslint-plugin-import-lite: 0.6.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))
+ eslint-plugin-jsdoc: 64.3.4(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3)
+ eslint-plugin-jsonc: 3.4.2(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))
+ eslint-plugin-n: 18.3.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(typescript@6.0.3)
+ eslint-plugin-no-only-tests: 3.4.0
+ eslint-plugin-perfectionist: 5.10.1(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3)
+ eslint-plugin-pnpm: 1.9.1(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))
+ eslint-plugin-regexp: 3.2.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))
+ eslint-plugin-toml: 1.5.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)
+ eslint-plugin-unicorn: 74.0.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))
+ eslint-plugin-unused-imports: 4.4.1(@typescript-eslint/eslint-plugin@8.69.0(@typescript-eslint/parser@8.69.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3))(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3))(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))
+ eslint-plugin-vue: 10.10.0(@stylistic/eslint-plugin@5.10.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2)))(@typescript-eslint/parser@8.69.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3))(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(vue-eslint-parser@10.4.1(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2))
+ eslint-plugin-yml: 3.8.1(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))
+ eslint-processor-vue-blocks: 2.0.0(@vue/compiler-sfc@3.5.42)(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))
+ globals: 17.12.0
+ local-pkg: 1.2.1
+ parse-gitignore: 2.0.0
+ toml-eslint-parser: 1.0.3
+ vue-eslint-parser: 10.4.1(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)
+ yaml-eslint-parser: 2.1.0
+ optionalDependencies:
+ eslint-plugin-slop: 0.1.1(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))
+ eslint-plugin-sonarjs: 4.2.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))
+ transitivePeerDependencies:
+ - '@eslint/json'
+ - '@typescript-eslint/typescript-estree'
+ - '@typescript-eslint/utils'
+ - '@vue/compiler-sfc'
+ - oxlint
+ - supports-color
+ - ts-declaration-location
+ - typescript
+ - vitest
+
'@antfu/install-pkg@1.1.0':
dependencies:
package-manager-detector: 1.8.0
@@ -12859,6 +13208,14 @@ snapshots:
optionalDependencies:
eslint: 10.9.1(jiti@2.7.0)(supports-color@10.2.2)
+ '@e18e/eslint-plugin@0.8.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))':
+ dependencies:
+ empathic: 2.0.1
+ module-replacements: 3.3.0
+ semver: 7.8.5
+ optionalDependencies:
+ eslint: 10.9.1(jiti@2.7.0)(supports-color@10.2.2)
+
'@emnapi/core@1.10.0':
dependencies:
'@emnapi/wasi-threads': 1.2.1
@@ -12945,6 +13302,14 @@ snapshots:
esquery: 1.7.0
jsdoc-type-pratt-parser: 9.0.1
+ '@es-joy/jsdoccomment@0.95.1':
+ dependencies:
+ '@types/estree': 1.0.9
+ '@typescript-eslint/types': 8.67.0
+ comment-parser: 1.4.8
+ esquery: 1.7.0
+ jsdoc-type-pratt-parser: 9.1.2
+
'@es-joy/resolve.exports@1.2.0': {}
'@esbuild/aix-ppc64@0.27.7':
@@ -13109,6 +13474,11 @@ snapshots:
eslint: 10.9.1(jiti@2.7.0)(supports-color@10.2.2)
ignore: 7.0.6
+ '@eslint-community/eslint-utils@4.10.1(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))':
+ dependencies:
+ eslint: 10.9.1(jiti@2.7.0)(supports-color@10.2.2)
+ eslint-visitor-keys: 3.4.3
+
'@eslint-community/eslint-utils@4.9.1(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))':
dependencies:
eslint: 10.9.1(jiti@2.7.0)(supports-color@10.2.2)
@@ -13147,6 +13517,11 @@ snapshots:
mdn-data: 2.28.1
source-map-js: 1.2.1
+ '@eslint/css-tree@4.1.0':
+ dependencies:
+ mdn-data: 2.34.0
+ source-map-js: 1.2.1
+
'@eslint/markdown@8.0.3(supports-color@10.2.2)':
dependencies:
'@eslint/core': 1.2.1
@@ -15700,7 +16075,7 @@ snapshots:
dependencies:
'@shikijs/types': 4.4.3
- '@shikijs/magic-move@4.4.3(react@19.2.8)(shiki@4.4.3)(solid-js@1.9.15)(svelte@5.57.0(@typescript-eslint/types@8.67.0))(vue@3.5.42(typescript@6.0.3))':
+ '@shikijs/magic-move@4.4.3(react@19.2.8)(shiki@4.4.3)(solid-js@1.9.15)(svelte@5.57.0(@typescript-eslint/types@8.69.0))(vue@3.5.42(typescript@6.0.3))':
dependencies:
diff-match-patch-es: 2.0.1
ohash: 2.0.12
@@ -15708,7 +16083,7 @@ snapshots:
react: 19.2.8
shiki: 4.4.3
solid-js: 1.9.15
- svelte: 5.57.0(@typescript-eslint/types@8.67.0)
+ svelte: 5.57.0(@typescript-eslint/types@8.69.0)
vue: 3.5.42(typescript@6.0.3)
'@shikijs/primitive@4.4.3':
@@ -15851,15 +16226,15 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@storybook/svelte-vite@10.5.10(@sveltejs/vite-plugin-svelte@7.3.0(svelte@5.57.0(@typescript-eslint/types@8.67.0))(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0)))(esbuild@0.28.2)(rollup@4.60.3)(storybook@10.5.10(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(svelte@5.57.0(@typescript-eslint/types@8.67.0))(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0))':
+ '@storybook/svelte-vite@10.5.10(@sveltejs/vite-plugin-svelte@7.3.0(svelte@5.57.0(@typescript-eslint/types@8.69.0))(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0)))(esbuild@0.28.2)(rollup@4.60.3)(storybook@10.5.10(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(svelte@5.57.0(@typescript-eslint/types@8.69.0))(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0))':
dependencies:
'@storybook/builder-vite': 10.5.10(esbuild@0.28.2)(rollup@4.60.3)(storybook@10.5.10(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0))
- '@storybook/svelte': 10.5.10(storybook@10.5.10(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(svelte@5.57.0(@typescript-eslint/types@8.67.0))
- '@sveltejs/vite-plugin-svelte': 7.3.0(svelte@5.57.0(@typescript-eslint/types@8.67.0))(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0))
+ '@storybook/svelte': 10.5.10(storybook@10.5.10(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(svelte@5.57.0(@typescript-eslint/types@8.69.0))
+ '@sveltejs/vite-plugin-svelte': 7.3.0(svelte@5.57.0(@typescript-eslint/types@8.69.0))(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0))
magic-string: 0.30.21
storybook: 10.5.10(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)
- svelte: 5.57.0(@typescript-eslint/types@8.67.0)
- svelte2tsx: 0.7.57(svelte@5.57.0(@typescript-eslint/types@8.67.0))(typescript@5.9.3)
+ svelte: 5.57.0(@typescript-eslint/types@8.69.0)
+ svelte2tsx: 0.7.57(svelte@5.57.0(@typescript-eslint/types@8.69.0))(typescript@5.9.3)
typescript: 5.9.3
vite: 8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0)
transitivePeerDependencies:
@@ -15867,10 +16242,10 @@ snapshots:
- rollup
- webpack
- '@storybook/svelte@10.5.10(storybook@10.5.10(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(svelte@5.57.0(@typescript-eslint/types@8.67.0))':
+ '@storybook/svelte@10.5.10(storybook@10.5.10(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(svelte@5.57.0(@typescript-eslint/types@8.69.0))':
dependencies:
storybook: 10.5.10(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)
- svelte: 5.57.0(@typescript-eslint/types@8.67.0)
+ svelte: 5.57.0(@typescript-eslint/types@8.69.0)
ts-dedent: 2.2.0
type-fest: 5.6.0
@@ -15936,20 +16311,20 @@ snapshots:
dependencies:
acorn: 8.18.0
- '@sveltejs/adapter-node@5.5.7(@sveltejs/kit@2.70.3(@opentelemetry/api@1.9.1)(@sveltejs/vite-plugin-svelte@7.3.0(svelte@5.57.0(@typescript-eslint/types@8.67.0))(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0)))(svelte@5.57.0(@typescript-eslint/types@8.67.0))(typescript@6.0.3)(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0)))':
+ '@sveltejs/adapter-node@5.5.7(@sveltejs/kit@2.70.3(@opentelemetry/api@1.9.1)(@sveltejs/vite-plugin-svelte@7.3.0(svelte@5.57.0(@typescript-eslint/types@8.69.0))(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0)))(svelte@5.57.0(@typescript-eslint/types@8.69.0))(typescript@6.0.3)(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0)))':
dependencies:
'@rollup/plugin-commonjs': 29.0.2(rollup@4.60.3)
'@rollup/plugin-json': 6.1.0(rollup@4.60.3)
'@rollup/plugin-node-resolve': 16.0.3(rollup@4.60.3)
'@rollup/plugin-replace': 6.0.3(rollup@4.60.3)
- '@sveltejs/kit': 2.70.3(@opentelemetry/api@1.9.1)(@sveltejs/vite-plugin-svelte@7.3.0(svelte@5.57.0(@typescript-eslint/types@8.67.0))(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0)))(svelte@5.57.0(@typescript-eslint/types@8.67.0))(typescript@6.0.3)(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0))
+ '@sveltejs/kit': 2.70.3(@opentelemetry/api@1.9.1)(@sveltejs/vite-plugin-svelte@7.3.0(svelte@5.57.0(@typescript-eslint/types@8.69.0))(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0)))(svelte@5.57.0(@typescript-eslint/types@8.69.0))(typescript@6.0.3)(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0))
rollup: 4.60.3
- '@sveltejs/kit@2.70.3(@opentelemetry/api@1.9.1)(@sveltejs/vite-plugin-svelte@7.3.0(svelte@5.57.0(@typescript-eslint/types@8.67.0))(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0)))(svelte@5.57.0(@typescript-eslint/types@8.67.0))(typescript@6.0.3)(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0))':
+ '@sveltejs/kit@2.70.3(@opentelemetry/api@1.9.1)(@sveltejs/vite-plugin-svelte@7.3.0(svelte@5.57.0(@typescript-eslint/types@8.69.0))(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0)))(svelte@5.57.0(@typescript-eslint/types@8.69.0))(typescript@6.0.3)(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0))':
dependencies:
'@standard-schema/spec': 1.1.0
'@sveltejs/acorn-typescript': 1.0.10(acorn@8.18.0)
- '@sveltejs/vite-plugin-svelte': 7.3.0(svelte@5.57.0(@typescript-eslint/types@8.67.0))(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0))
+ '@sveltejs/vite-plugin-svelte': 7.3.0(svelte@5.57.0(@typescript-eslint/types@8.69.0))(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0))
'@types/cookie': 0.6.0
acorn: 8.18.0
cookie: 0.6.0
@@ -15960,18 +16335,18 @@ snapshots:
mrmime: 2.0.1
set-cookie-parser: 3.1.2
sirv: 3.0.2
- svelte: 5.57.0(@typescript-eslint/types@8.67.0)
+ svelte: 5.57.0(@typescript-eslint/types@8.69.0)
vite: 8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0)
optionalDependencies:
'@opentelemetry/api': 1.9.1
typescript: 6.0.3
- '@sveltejs/vite-plugin-svelte@7.3.0(svelte@5.57.0(@typescript-eslint/types@8.67.0))(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0))':
+ '@sveltejs/vite-plugin-svelte@7.3.0(svelte@5.57.0(@typescript-eslint/types@8.69.0))(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0))':
dependencies:
deepmerge: 4.3.1
magic-string: 1.2.3
obug: 2.1.4
- svelte: 5.57.0(@typescript-eslint/types@8.67.0)
+ svelte: 5.57.0(@typescript-eslint/types@8.69.0)
vite: 8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0)
vitefu: 1.1.3(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0))
@@ -16477,6 +16852,22 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ '@typescript-eslint/eslint-plugin@8.69.0(@typescript-eslint/parser@8.69.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3))(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3)':
+ dependencies:
+ '@eslint-community/regexpp': 4.12.2
+ '@typescript-eslint/parser': 8.69.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3)
+ '@typescript-eslint/scope-manager': 8.69.0
+ '@typescript-eslint/type-utils': 8.69.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3)
+ '@typescript-eslint/utils': 8.69.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3)
+ '@typescript-eslint/visitor-keys': 8.69.0
+ eslint: 10.9.1(jiti@2.7.0)(supports-color@10.2.2)
+ ignore: 7.0.6
+ natural-compare: 1.4.0
+ ts-api-utils: 2.5.0(typescript@6.0.3)
+ typescript: 6.0.3
+ transitivePeerDependencies:
+ - supports-color
+
'@typescript-eslint/parser@8.67.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3)':
dependencies:
'@typescript-eslint/scope-manager': 8.67.0
@@ -16489,6 +16880,18 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ '@typescript-eslint/parser@8.69.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3)':
+ dependencies:
+ '@typescript-eslint/scope-manager': 8.69.0
+ '@typescript-eslint/types': 8.69.0
+ '@typescript-eslint/typescript-estree': 8.69.0(supports-color@10.2.2)(typescript@6.0.3)
+ '@typescript-eslint/visitor-keys': 8.69.0
+ debug: 4.4.3(supports-color@10.2.2)
+ eslint: 10.9.1(jiti@2.7.0)(supports-color@10.2.2)
+ typescript: 6.0.3
+ transitivePeerDependencies:
+ - supports-color
+
'@typescript-eslint/project-service@8.67.0(supports-color@10.2.2)(typescript@6.0.3)':
dependencies:
'@typescript-eslint/tsconfig-utils': 8.67.0(typescript@6.0.3)
@@ -16498,15 +16901,33 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ '@typescript-eslint/project-service@8.69.0(supports-color@10.2.2)(typescript@6.0.3)':
+ dependencies:
+ '@typescript-eslint/tsconfig-utils': 8.69.0(typescript@6.0.3)
+ '@typescript-eslint/types': 8.69.0
+ debug: 4.4.3(supports-color@10.2.2)
+ typescript: 6.0.3
+ transitivePeerDependencies:
+ - supports-color
+
'@typescript-eslint/scope-manager@8.67.0':
dependencies:
'@typescript-eslint/types': 8.67.0
'@typescript-eslint/visitor-keys': 8.67.0
+ '@typescript-eslint/scope-manager@8.69.0':
+ dependencies:
+ '@typescript-eslint/types': 8.69.0
+ '@typescript-eslint/visitor-keys': 8.69.0
+
'@typescript-eslint/tsconfig-utils@8.67.0(typescript@6.0.3)':
dependencies:
typescript: 6.0.3
+ '@typescript-eslint/tsconfig-utils@8.69.0(typescript@6.0.3)':
+ dependencies:
+ typescript: 6.0.3
+
'@typescript-eslint/type-utils@8.67.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3)':
dependencies:
'@typescript-eslint/types': 8.67.0
@@ -16519,8 +16940,22 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ '@typescript-eslint/type-utils@8.69.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3)':
+ dependencies:
+ '@typescript-eslint/types': 8.69.0
+ '@typescript-eslint/typescript-estree': 8.69.0(supports-color@10.2.2)(typescript@6.0.3)
+ '@typescript-eslint/utils': 8.69.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3)
+ debug: 4.4.3(supports-color@10.2.2)
+ eslint: 10.9.1(jiti@2.7.0)(supports-color@10.2.2)
+ ts-api-utils: 2.5.0(typescript@6.0.3)
+ typescript: 6.0.3
+ transitivePeerDependencies:
+ - supports-color
+
'@typescript-eslint/types@8.67.0': {}
+ '@typescript-eslint/types@8.69.0': {}
+
'@typescript-eslint/typescript-estree@8.67.0(supports-color@10.2.2)(typescript@6.0.3)':
dependencies:
'@typescript-eslint/project-service': 8.67.0(supports-color@10.2.2)(typescript@6.0.3)
@@ -16536,6 +16971,21 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ '@typescript-eslint/typescript-estree@8.69.0(supports-color@10.2.2)(typescript@6.0.3)':
+ dependencies:
+ '@typescript-eslint/project-service': 8.69.0(supports-color@10.2.2)(typescript@6.0.3)
+ '@typescript-eslint/tsconfig-utils': 8.69.0(typescript@6.0.3)
+ '@typescript-eslint/types': 8.69.0
+ '@typescript-eslint/visitor-keys': 8.69.0
+ debug: 4.4.3(supports-color@10.2.2)
+ minimatch: 10.2.5
+ semver: 7.8.5
+ tinyglobby: 0.2.17
+ ts-api-utils: 2.5.0(typescript@6.0.3)
+ typescript: 6.0.3
+ transitivePeerDependencies:
+ - supports-color
+
'@typescript-eslint/utils@8.67.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3)':
dependencies:
'@eslint-community/eslint-utils': 4.9.1(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))
@@ -16547,11 +16997,27 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ '@typescript-eslint/utils@8.69.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3)':
+ dependencies:
+ '@eslint-community/eslint-utils': 4.9.1(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))
+ '@typescript-eslint/scope-manager': 8.69.0
+ '@typescript-eslint/types': 8.69.0
+ '@typescript-eslint/typescript-estree': 8.69.0(supports-color@10.2.2)(typescript@6.0.3)
+ eslint: 10.9.1(jiti@2.7.0)(supports-color@10.2.2)
+ typescript: 6.0.3
+ transitivePeerDependencies:
+ - supports-color
+
'@typescript-eslint/visitor-keys@8.67.0':
dependencies:
'@typescript-eslint/types': 8.67.0
eslint-visitor-keys: 5.0.1
+ '@typescript-eslint/visitor-keys@8.69.0':
+ dependencies:
+ '@typescript-eslint/types': 8.69.0
+ eslint-visitor-keys: 5.0.1
+
'@typescript/typescript6@6.0.2':
dependencies:
'@typescript/old': typescript@6.0.3
@@ -16786,13 +17252,13 @@ snapshots:
unplugin-utils: 0.3.2
vite: 8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0)
- '@vercel/analytics@2.0.1(5d2d6ffc3b89e9bceaf6c88cc98f5535)':
+ '@vercel/analytics@2.0.1(50265e90ff017898fc7602fbbd7753ba)':
optionalDependencies:
- '@sveltejs/kit': 2.70.3(@opentelemetry/api@1.9.1)(@sveltejs/vite-plugin-svelte@7.3.0(svelte@5.57.0(@typescript-eslint/types@8.67.0))(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0)))(svelte@5.57.0(@typescript-eslint/types@8.67.0))(typescript@6.0.3)(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0))
+ '@sveltejs/kit': 2.70.3(@opentelemetry/api@1.9.1)(@sveltejs/vite-plugin-svelte@7.3.0(svelte@5.57.0(@typescript-eslint/types@8.69.0))(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0)))(svelte@5.57.0(@typescript-eslint/types@8.69.0))(typescript@6.0.3)(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0))
next: 16.3.3(@babel/core@7.29.0(supports-color@10.2.2))(@opentelemetry/api@1.9.1)(@playwright/test@1.62.1)(@types/node@26.4.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)
nuxt: 4.5.2(@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.0(supports-color@10.2.2)))(@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.0(supports-color@10.2.2)))(@oxc-project/types@0.147.0)(@parcel/watcher@2.5.6)(@rspack/core@2.2.1(@swc/helpers@0.5.23))(@types/node@26.4.0)(@vercel/functions@3.9.5(ws@8.21.3))(@vitejs/devtools-kit@0.4.9(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0)))(@vue/compiler-sfc@3.5.42)(db0@0.3.4)(esbuild@0.28.2)(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(ioredis@5.10.1(supports-color@10.2.2))(lightningcss@1.33.0)(magicast@0.5.4)(optionator@0.9.4)(oxc-parser@0.143.0)(rolldown@1.2.6)(rollup-plugin-visualizer@7.0.1(rolldown@1.2.6)(rollup@4.60.3))(rollup@4.60.3)(srvx@0.11.22)(supports-color@10.2.2)(terser@5.47.1)(tsx@4.23.13)(typescript@6.0.3)(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0))(yaml@2.9.0)
react: 19.2.8
- svelte: 5.57.0(@typescript-eslint/types@8.67.0)
+ svelte: 5.57.0(@typescript-eslint/types@8.69.0)
vue: 3.5.42(typescript@6.0.3)
'@vercel/cli-config@0.2.4':
@@ -16856,13 +17322,13 @@ snapshots:
'@opentelemetry/sdk-metrics': 2.10.0(@opentelemetry/api@1.9.1)
'@opentelemetry/sdk-trace-base': 2.10.0(@opentelemetry/api@1.9.1)
- '@vercel/speed-insights@2.0.0(5d2d6ffc3b89e9bceaf6c88cc98f5535)':
+ '@vercel/speed-insights@2.0.0(50265e90ff017898fc7602fbbd7753ba)':
optionalDependencies:
- '@sveltejs/kit': 2.70.3(@opentelemetry/api@1.9.1)(@sveltejs/vite-plugin-svelte@7.3.0(svelte@5.57.0(@typescript-eslint/types@8.67.0))(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0)))(svelte@5.57.0(@typescript-eslint/types@8.67.0))(typescript@6.0.3)(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0))
+ '@sveltejs/kit': 2.70.3(@opentelemetry/api@1.9.1)(@sveltejs/vite-plugin-svelte@7.3.0(svelte@5.57.0(@typescript-eslint/types@8.69.0))(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0)))(svelte@5.57.0(@typescript-eslint/types@8.69.0))(typescript@6.0.3)(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0))
next: 16.3.3(@babel/core@7.29.0(supports-color@10.2.2))(@opentelemetry/api@1.9.1)(@playwright/test@1.62.1)(@types/node@26.4.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)
nuxt: 4.5.2(@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.0(supports-color@10.2.2)))(@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.0(supports-color@10.2.2)))(@oxc-project/types@0.147.0)(@parcel/watcher@2.5.6)(@rspack/core@2.2.1(@swc/helpers@0.5.23))(@types/node@26.4.0)(@vercel/functions@3.9.5(ws@8.21.3))(@vitejs/devtools-kit@0.4.9(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0)))(@vue/compiler-sfc@3.5.42)(db0@0.3.4)(esbuild@0.28.2)(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(ioredis@5.10.1(supports-color@10.2.2))(lightningcss@1.33.0)(magicast@0.5.4)(optionator@0.9.4)(oxc-parser@0.143.0)(rolldown@1.2.6)(rollup-plugin-visualizer@7.0.1(rolldown@1.2.6)(rollup@4.60.3))(rollup@4.60.3)(srvx@0.11.22)(supports-color@10.2.2)(terser@5.47.1)(tsx@4.23.13)(typescript@6.0.3)(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0))(yaml@2.9.0)
react: 19.2.8
- svelte: 5.57.0(@typescript-eslint/types@8.67.0)
+ svelte: 5.57.0(@typescript-eslint/types@8.69.0)
vue: 3.5.42(typescript@6.0.3)
'@vitejs/devtools-kit@0.4.9(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0))':
@@ -16918,6 +17384,18 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ '@vitest/eslint-plugin@1.6.27(@typescript-eslint/eslint-plugin@8.69.0(@typescript-eslint/parser@8.69.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3))(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3))(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3)(vitest@4.1.11(@opentelemetry/api@1.9.1)(@types/node@26.4.0)(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0)))':
+ dependencies:
+ '@typescript-eslint/scope-manager': 8.67.0
+ '@typescript-eslint/utils': 8.67.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3)
+ eslint: 10.9.1(jiti@2.7.0)(supports-color@10.2.2)
+ optionalDependencies:
+ '@typescript-eslint/eslint-plugin': 8.69.0(@typescript-eslint/parser@8.69.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3))(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3)
+ typescript: 6.0.3
+ vitest: 4.1.11(@opentelemetry/api@1.9.1)(@types/node@26.4.0)(vite@8.2.2(@types/node@26.4.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.13)(yaml@2.9.0))
+ transitivePeerDependencies:
+ - supports-color
+
'@vitest/expect@3.2.4':
dependencies:
'@types/chai': 5.2.3
@@ -17359,6 +17837,8 @@ snapshots:
are-docs-informative@0.0.2: {}
+ are-docs-informative@0.1.1: {}
+
argparse@1.0.10:
dependencies:
sprintf-js: 1.0.3
@@ -17490,6 +17970,8 @@ snapshots:
baseline-browser-mapping@2.10.43: {}
+ baseline-browser-mapping@2.11.20: {}
+
beautiful-mermaid@1.1.3:
dependencies:
elkjs: 0.11.1
@@ -17539,6 +18021,14 @@ snapshots:
node-releases: 2.0.51
update-browserslist-db: 1.2.3(browserslist@4.28.6)
+ browserslist@4.28.8:
+ dependencies:
+ baseline-browser-mapping: 2.11.20
+ caniuse-lite: 1.0.30001810
+ electron-to-chromium: 1.5.420
+ node-releases: 2.0.54
+ update-browserslist-db: 1.3.2(browserslist@4.28.8)
+
buffer-crc32@1.0.0: {}
buffer-from@1.1.2: {}
@@ -17548,6 +18038,8 @@ snapshots:
base64-js: 1.5.1
ieee754: 1.2.1
+ builtin-modules@3.3.0: {}
+
builtin-modules@5.2.0: {}
bumpp@12.2.2:
@@ -17606,6 +18098,8 @@ snapshots:
caniuse-lite@1.0.30001806: {}
+ caniuse-lite@1.0.30001810: {}
+
ccount@2.0.1: {}
chai@5.3.3:
@@ -17730,7 +18224,7 @@ snapshots:
- srvx
- uploadthing
- comark-docs@https://codeload.github.com/comarkdown/comark-docs/tar.gz/f97dc864b0aa702d54c600f868589b7a2c185b3a(patch_hash=5f1078be206123f957de74141ae02eaae510555cc7444404bffbfaae8d407e33)(16cf1b447d22766aa84945436e8d9e61):
+ comark-docs@https://codeload.github.com/comarkdown/comark-docs/tar.gz/f97dc864b0aa702d54c600f868589b7a2c185b3a(patch_hash=5f1078be206123f957de74141ae02eaae510555cc7444404bffbfaae8d407e33)(33a9239c8daf1432168431509a51f904):
dependencies:
'@ai-sdk/gateway': 4.0.69(zod@4.5.4)
'@ai-sdk/vue': 4.0.85(vue@3.5.42(typescript@6.0.3))(zod@4.5.4)
@@ -17747,11 +18241,11 @@ snapshots:
'@octokit/webhooks-methods': 6.0.0
'@opentelemetry/api': 1.9.1
'@resvg/resvg-js': 2.6.2
- '@vercel/analytics': 2.0.1(5d2d6ffc3b89e9bceaf6c88cc98f5535)
+ '@vercel/analytics': 2.0.1(50265e90ff017898fc7602fbbd7753ba)
'@vercel/functions': 3.9.5(ws@8.21.3)
'@vercel/global-config': 1.5.1(@opentelemetry/api@1.9.1)(next@16.3.3(@babel/core@7.29.0(supports-color@10.2.2))(@opentelemetry/api@1.9.1)(@playwright/test@1.62.1)(@types/node@26.4.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))
'@vercel/otel': 2.1.3(@opentelemetry/api-logs@0.221.0)(@opentelemetry/api@1.9.1)(@opentelemetry/instrumentation@0.221.0(@opentelemetry/api@1.9.1)(supports-color@10.2.2))(@opentelemetry/resources@2.10.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-logs@0.221.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-metrics@2.10.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.10.0(@opentelemetry/api@1.9.1))
- '@vercel/speed-insights': 2.0.0(5d2d6ffc3b89e9bceaf6c88cc98f5535)
+ '@vercel/speed-insights': 2.0.0(50265e90ff017898fc7602fbbd7753ba)
'@vueuse/core': 14.4.0(vue@3.5.42(typescript@6.0.3))
ai: 7.0.85(zod@4.5.4)
beautiful-mermaid: 1.1.3
@@ -17907,6 +18401,8 @@ snapshots:
comment-parser@1.4.7: {}
+ comment-parser@1.4.8: {}
+
commondir@1.0.1: {}
compatx@0.2.0: {}
@@ -17958,6 +18454,10 @@ snapshots:
dependencies:
browserslist: 4.28.6
+ core-js-compat@3.50.0:
+ dependencies:
+ browserslist: 4.28.8
+
core-util-is@1.0.3: {}
cors@2.8.6:
@@ -18212,6 +18712,8 @@ snapshots:
electron-to-chromium@1.5.393: {}
+ electron-to-chromium@1.5.420: {}
+
elkjs@0.11.1: {}
embla-carousel-auto-height@8.6.0(embla-carousel@8.6.0):
@@ -18375,6 +18877,11 @@ snapshots:
'@eslint/compat': 2.1.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))
eslint: 10.9.1(jiti@2.7.0)(supports-color@10.2.2)
+ eslint-config-flat-gitignore@2.4.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2)):
+ dependencies:
+ '@eslint/compat': 2.1.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))
+ eslint: 10.9.1(jiti@2.7.0)(supports-color@10.2.2)
+
eslint-flat-config-utils@3.2.0:
dependencies:
'@eslint/config-helpers': 0.5.5
@@ -18386,6 +18893,12 @@ snapshots:
esquery: 1.7.0
jsonc-eslint-parser: 3.1.0
+ eslint-json-compat-utils@0.2.3(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(jsonc-eslint-parser@3.3.0):
+ dependencies:
+ eslint: 10.9.1(jiti@2.7.0)(supports-color@10.2.2)
+ esquery: 1.7.0
+ jsonc-eslint-parser: 3.3.0
+
eslint-merge-processors@2.0.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2)):
dependencies:
eslint: 10.9.1(jiti@2.7.0)(supports-color@10.2.2)
@@ -18394,11 +18907,11 @@ snapshots:
dependencies:
eslint: 10.9.1(jiti@2.7.0)(supports-color@10.2.2)
- eslint-plugin-command@4.0.0(@typescript-eslint/typescript-estree@8.67.0(supports-color@10.2.2)(typescript@6.0.3))(@typescript-eslint/utils@8.67.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3))(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2)):
+ eslint-plugin-command@4.0.0(@typescript-eslint/typescript-estree@8.69.0(supports-color@10.2.2)(typescript@6.0.3))(@typescript-eslint/utils@8.69.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3))(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2)):
dependencies:
'@es-joy/jsdoccomment': 0.92.0
- '@typescript-eslint/typescript-estree': 8.67.0(supports-color@10.2.2)(typescript@6.0.3)
- '@typescript-eslint/utils': 8.67.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3)
+ '@typescript-eslint/typescript-estree': 8.69.0(supports-color@10.2.2)(typescript@6.0.3)
+ '@typescript-eslint/utils': 8.69.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3)
eslint: 10.9.1(jiti@2.7.0)(supports-color@10.2.2)
eslint-plugin-es-x@7.8.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2)):
@@ -18432,6 +18945,28 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ eslint-plugin-jsdoc@64.3.4(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3):
+ dependencies:
+ '@es-joy/jsdoccomment': 0.95.1
+ '@es-joy/resolve.exports': 1.2.0
+ '@typescript-eslint/utils': 8.69.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3)
+ are-docs-informative: 0.1.1
+ comment-parser: 1.4.8
+ debug: 4.4.3(supports-color@10.2.2)
+ escape-string-regexp: 5.0.0
+ eslint: 10.9.1(jiti@2.7.0)(supports-color@10.2.2)
+ espree: 11.2.0
+ esquery: 1.7.0
+ html-entities: 2.6.0
+ object-deep-merge: 2.0.1
+ parse-imports-exports: 0.2.4
+ semver: 7.8.5
+ spdx-expression-parse: 5.0.0
+ to-valid-identifier: 1.0.0
+ transitivePeerDependencies:
+ - supports-color
+ - typescript
+
eslint-plugin-jsonc@3.4.1(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2)):
dependencies:
'@eslint-community/eslint-utils': 4.9.1(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))
@@ -18447,6 +18982,21 @@ snapshots:
transitivePeerDependencies:
- '@eslint/json'
+ eslint-plugin-jsonc@3.4.2(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2)):
+ dependencies:
+ '@eslint-community/eslint-utils': 4.9.1(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))
+ '@eslint/core': 1.2.1
+ '@eslint/plugin-kit': 0.7.2
+ '@ota-meshi/ast-token-store': 0.3.0
+ diff-sequences: 29.6.3
+ eslint: 10.9.1(jiti@2.7.0)(supports-color@10.2.2)
+ eslint-json-compat-utils: 0.2.3(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(jsonc-eslint-parser@3.1.0)
+ jsonc-eslint-parser: 3.1.0
+ natural-compare: 1.4.0
+ synckit: 0.11.12
+ transitivePeerDependencies:
+ - '@eslint/json'
+
eslint-plugin-n@18.2.2(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(typescript@6.0.3):
dependencies:
'@eslint-community/eslint-utils': 4.9.1(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))
@@ -18461,6 +19011,20 @@ snapshots:
optionalDependencies:
typescript: 6.0.3
+ eslint-plugin-n@18.3.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(typescript@6.0.3):
+ dependencies:
+ '@eslint-community/eslint-utils': 4.9.1(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))
+ enhanced-resolve: 5.24.5
+ eslint: 10.9.1(jiti@2.7.0)(supports-color@10.2.2)
+ eslint-plugin-es-x: 7.8.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))
+ get-tsconfig: 4.14.3
+ globals: 15.15.0
+ globrex: 0.1.2
+ ignore: 5.3.2
+ semver: 7.8.5
+ optionalDependencies:
+ typescript: 6.0.3
+
eslint-plugin-no-only-tests@3.4.0: {}
eslint-plugin-perfectionist@5.10.1(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3):
@@ -18483,6 +19047,20 @@ snapshots:
yaml: 2.9.0
yaml-eslint-parser: 2.1.0
+ eslint-plugin-pnpm@1.9.1(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2)):
+ dependencies:
+ empathic: 2.0.1
+ eslint: 10.9.1(jiti@2.7.0)(supports-color@10.2.2)
+ eslint-json-compat-utils: 0.2.3(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(jsonc-eslint-parser@3.3.0)
+ jsonc-eslint-parser: 3.3.0
+ pathe: 2.0.3
+ pnpm-workspace-yaml: 1.9.1
+ tinyglobby: 0.2.17
+ yaml: 2.9.0
+ yaml-eslint-parser: 2.1.0
+ transitivePeerDependencies:
+ - '@eslint/json'
+
eslint-plugin-regexp@3.1.1(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2)):
dependencies:
'@eslint-community/eslint-utils': 4.9.1(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))
@@ -18494,6 +19072,39 @@ snapshots:
regexp-ast-analysis: 0.7.1
scslre: 0.3.0
+ eslint-plugin-regexp@3.2.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2)):
+ dependencies:
+ '@eslint-community/eslint-utils': 4.9.1(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))
+ '@eslint-community/regexpp': 4.12.2
+ comment-parser: 1.4.7
+ eslint: 10.9.1(jiti@2.7.0)(supports-color@10.2.2)
+ jsdoc-type-pratt-parser: 9.0.1
+ refa: 0.12.1
+ regexp-ast-analysis: 0.7.1
+ scslre: 0.3.0
+
+ eslint-plugin-slop@0.1.1(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2)):
+ dependencies:
+ diff: 9.0.0
+ eslint: 10.9.1(jiti@2.7.0)(supports-color@10.2.2)
+
+ eslint-plugin-sonarjs@4.2.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2)):
+ dependencies:
+ '@eslint-community/regexpp': 4.12.2
+ builtin-modules: 3.3.0
+ bytes: 3.1.2
+ eslint: 10.9.1(jiti@2.7.0)(supports-color@10.2.2)
+ functional-red-black-tree: 1.0.1
+ globals: 17.10.0
+ jsx-ast-utils-x: 0.1.0
+ lodash.merge: 4.6.2
+ minimatch: 10.2.5
+ scslre: 0.3.0
+ semver: 7.8.5
+ ts-api-utils: 2.5.0(typescript@6.0.3)
+ typescript: 6.0.3
+ yaml: 2.9.0
+
eslint-plugin-toml@1.5.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2):
dependencies:
'@eslint/core': 1.2.1
@@ -18529,12 +19140,42 @@ snapshots:
strip-indent: 4.1.1
yaml: 2.9.0
+ eslint-plugin-unicorn@74.0.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2)):
+ dependencies:
+ '@eslint-community/eslint-utils': 4.10.1(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))
+ '@eslint/css-tree': 4.1.0
+ browserslist: 4.28.8
+ change-case: 5.4.4
+ ci-info: 4.4.0
+ core-js-compat: 3.50.0
+ detect-indent: 7.0.2
+ entities: 8.0.0
+ eslint: 10.9.1(jiti@2.7.0)(supports-color@10.2.2)
+ find-up-simple: 1.0.1
+ globals: 17.12.0
+ indent-string: 5.0.0
+ is-builtin-module: 5.0.0
+ is-identifier: 1.1.0
+ pluralize: 8.0.0
+ quote-js-string: 0.1.0
+ regjsparser: 0.13.2
+ reserved-identifiers: 1.2.0
+ semver: 7.8.5
+ strip-indent: 4.1.1
+ yaml: 2.9.0
+
eslint-plugin-unused-imports@4.4.1(@typescript-eslint/eslint-plugin@8.67.0(@typescript-eslint/parser@8.67.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3))(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3))(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2)):
dependencies:
eslint: 10.9.1(jiti@2.7.0)(supports-color@10.2.2)
optionalDependencies:
'@typescript-eslint/eslint-plugin': 8.67.0(@typescript-eslint/parser@8.67.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3))(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3)
+ eslint-plugin-unused-imports@4.4.1(@typescript-eslint/eslint-plugin@8.69.0(@typescript-eslint/parser@8.69.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3))(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3))(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2)):
+ dependencies:
+ eslint: 10.9.1(jiti@2.7.0)(supports-color@10.2.2)
+ optionalDependencies:
+ '@typescript-eslint/eslint-plugin': 8.69.0(@typescript-eslint/parser@8.69.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3))(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3)
+
eslint-plugin-vue@10.10.0(@stylistic/eslint-plugin@5.10.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2)))(@typescript-eslint/parser@8.67.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3))(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(vue-eslint-parser@10.4.1(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)):
dependencies:
'@eslint-community/eslint-utils': 4.9.1(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))
@@ -18549,6 +19190,20 @@ snapshots:
'@stylistic/eslint-plugin': 5.10.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))
'@typescript-eslint/parser': 8.67.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3)
+ eslint-plugin-vue@10.10.0(@stylistic/eslint-plugin@5.10.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2)))(@typescript-eslint/parser@8.69.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3))(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(vue-eslint-parser@10.4.1(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)):
+ dependencies:
+ '@eslint-community/eslint-utils': 4.9.1(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))
+ eslint: 10.9.1(jiti@2.7.0)(supports-color@10.2.2)
+ natural-compare: 1.4.0
+ nth-check: 2.1.1
+ postcss-selector-parser: 7.1.4
+ semver: 7.8.5
+ vue-eslint-parser: 10.4.1(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)
+ xml-name-validator: 5.0.0
+ optionalDependencies:
+ '@stylistic/eslint-plugin': 5.10.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))
+ '@typescript-eslint/parser': 8.69.0(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3)
+
eslint-plugin-yml@3.8.1(eslint@10.9.1(jiti@2.7.0)(supports-color@10.2.2)):
dependencies:
'@eslint/core': 1.2.1
@@ -18637,11 +19292,11 @@ snapshots:
dependencies:
estraverse: 5.3.0
- esrap@2.2.13(@typescript-eslint/types@8.67.0):
+ esrap@2.2.13(@typescript-eslint/types@8.69.0):
dependencies:
'@jridgewell/sourcemap-codec': 1.5.5
optionalDependencies:
- '@typescript-eslint/types': 8.67.0
+ '@typescript-eslint/types': 8.69.0
esrecurse@4.3.0:
dependencies:
@@ -19000,6 +19655,8 @@ snapshots:
function-timeout@1.0.2: {}
+ functional-red-black-tree@1.0.1: {}
+
fuse.js@7.5.0: {}
fzf@0.5.2: {}
@@ -19081,6 +19738,8 @@ snapshots:
globals@17.10.0: {}
+ globals@17.12.0: {}
+
globby@16.2.0:
dependencies:
'@sindresorhus/merge-streams': 4.0.0
@@ -19457,6 +20116,10 @@ snapshots:
dependencies:
'@types/estree': 1.0.9
+ jsdoc-type-pratt-parser@9.1.2:
+ dependencies:
+ '@types/estree': 1.0.9
+
jsesc@3.1.0: {}
json-buffer@3.0.1: {}
@@ -19483,6 +20146,12 @@ snapshots:
eslint-visitor-keys: 5.0.1
semver: 7.8.5
+ jsonc-eslint-parser@3.3.0:
+ dependencies:
+ acorn: 8.18.0
+ eslint-visitor-keys: 5.0.1
+ verkit: 0.3.2
+
jsonc-parser@3.3.1: {}
jstransformer@1.0.0:
@@ -19490,6 +20159,8 @@ snapshots:
is-promise: 2.2.2
promise: 7.3.1
+ jsx-ast-utils-x@0.1.0: {}
+
katex@0.16.45:
dependencies:
commander: 8.3.0
@@ -19732,6 +20403,8 @@ snapshots:
lodash.isarguments@3.1.0: {}
+ lodash.merge@4.6.2: {}
+
lodash@4.18.1: {}
longest-streak@3.1.0: {}
@@ -19947,6 +20620,8 @@ snapshots:
mdn-data@2.28.1: {}
+ mdn-data@2.34.0: {}
+
mdurl@2.1.0: {}
media-typer@1.1.1: {}
@@ -20221,6 +20896,8 @@ snapshots:
module-replacements@3.0.0: {}
+ module-replacements@3.3.0: {}
+
motion-dom@13.0.0:
dependencies:
motion-utils: 13.0.0
@@ -20584,6 +21261,8 @@ snapshots:
node-releases@2.0.51: {}
+ node-releases@2.0.54: {}
+
nopt@8.1.0:
dependencies:
abbrev: 3.0.1
@@ -21474,6 +22153,10 @@ snapshots:
dependencies:
yaml: 2.9.0
+ pnpm-workspace-yaml@1.9.1:
+ dependencies:
+ yaml: 2.9.0
+
postcss-calc@10.1.1(postcss@8.5.26):
dependencies:
postcss: 8.5.26
@@ -22641,14 +23324,14 @@ snapshots:
supports-preserve-symlinks-flag@1.0.0: {}
- svelte2tsx@0.7.57(svelte@5.57.0(@typescript-eslint/types@8.67.0))(typescript@5.9.3):
+ svelte2tsx@0.7.57(svelte@5.57.0(@typescript-eslint/types@8.69.0))(typescript@5.9.3):
dependencies:
dedent-js: 1.0.1
scule: 1.3.0
- svelte: 5.57.0(@typescript-eslint/types@8.67.0)
+ svelte: 5.57.0(@typescript-eslint/types@8.69.0)
typescript: 5.9.3
- svelte@5.57.0(@typescript-eslint/types@8.67.0):
+ svelte@5.57.0(@typescript-eslint/types@8.69.0):
dependencies:
'@jridgewell/remapping': 2.3.5
'@jridgewell/sourcemap-codec': 1.5.5
@@ -22660,7 +23343,7 @@ snapshots:
clsx: 2.1.1
devalue: 5.9.0
esm-env: 1.2.2
- esrap: 2.2.13(@typescript-eslint/types@8.67.0)
+ esrap: 2.2.13(@typescript-eslint/types@8.69.0)
is-reference: 3.0.3
locate-character: 3.0.0
magic-string: 0.30.21
@@ -23261,6 +23944,12 @@ snapshots:
escalade: 3.2.0
picocolors: 1.1.1
+ update-browserslist-db@1.3.2(browserslist@4.28.8):
+ dependencies:
+ browserslist: 4.28.8
+ escalade: 3.2.0
+ picocolors: 1.1.1
+
uqr@0.1.3: {}
uri-js@4.4.1:
diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml
index 468cede59..6559ad338 100644
--- a/pnpm-workspace.yaml
+++ b/pnpm-workspace.yaml
@@ -1,33 +1,22 @@
+ignoreWorkspaceRootCheck: true
+catalogMode: prefer
+cleanupUnusedCatalogs: true
# The `comark-docs` layer (docs site theme, installed from GitHub) pins its
# `comark`/`comark-content`/`@comark/nuxt` deps to pkg.pr.new snapshot URLs,
# which pnpm 11 classifies as exotic subdependencies and blocks by default.
# There is no per-package allowlist for this setting.
blockExoticSubdeps: false
-allowBuilds:
- '@parcel/watcher': false
- esbuild: true
- sharp: false
- simple-git-hooks: true
- unrs-resolver: true
- vue-demi: true
-catalogMode: prefer
-cleanupUnusedCatalogs: true
-ignoreWorkspaceRootCheck: true
+
+minimumReleaseAgeExcludePrune: true
minimumReleaseAgeExclude:
- - nostics@1.1.4
- - '@antfu/design@0.3.0 || 0.3.2'
- - crossws@0.4.8
- iframe-pane@1.1.0
- tsdown@0.22.14
- - verkit@0.3.0
- structured-clone-es@2.0.1
- - '@devframes/hub-ui@0.9.4'
- - '@devframes/hub@0.9.4'
- - '@devframes/json-render@0.9.4'
- - '@devframes/vite@0.9.4'
-shamefullyHoist: true
-shellEmulator: true
-strictPeerDependencies: false
+ - '@antfu/eslint-config@9.5.1'
+ - eslint-plugin-pnpm@1.9.1
+ - eslint-plugin-slop@0.1.1
+ - pnpm-workspace-yaml@1.9.1
+
trustPolicy: no-downgrade
trustPolicyExclude:
- tinyexec@1.2.2
@@ -38,6 +27,15 @@ trustPolicyExclude:
- '@vercel/cli-config@0.2.3'
- '@vercel/cli-config@0.2.4'
- '@vercel/cli-exec@1.0.1'
+
+update:
+ ignoreDeps:
+ - typescript@7
+
+strictPeerDependencies: false
+shamefullyHoist: true
+shellEmulator: true
+
packages:
- packages/*
- plugins/*
@@ -82,11 +80,17 @@ overrides:
shell-quote: ^1.10.0
unhead: ^3.4.0
-update:
- ignoreDeps:
- - typescript@7
patchedDependencies:
comark-docs@0.0.1: patches/comark-docs@0.0.1.patch
+
+allowBuilds:
+ '@parcel/watcher': false
+ esbuild: true
+ sharp: false
+ simple-git-hooks: true
+ unrs-resolver: true
+ vue-demi: true
+
catalogs:
build:
'@nuxt/kit': ^4.5.2
@@ -210,9 +214,11 @@ catalogs:
tsnapi: ^1.4.0
vitest: ^4.1.11
tooling:
- '@antfu/eslint-config': ^9.3.0
+ '@antfu/eslint-config': ^9.5.1
bumpp: ^12.2.2
eslint: ^10.9.1
+ eslint-plugin-slop: ^0.1.1
+ eslint-plugin-sonarjs: ^4.2.0
knip: ^6.33.0
nano-staged: ^1.0.2
prompts: ^2.4.2
diff --git a/scripts/ci-retry.ts b/scripts/ci-retry.ts
index 6edc094db..601f50dcb 100644
--- a/scripts/ci-retry.ts
+++ b/scripts/ci-retry.ts
@@ -5,7 +5,7 @@ import process from 'node:process'
* Windows CI runners intermittently crash while spawning devframe's native
* build toolchain (rolldown, via tsdown/vite) with
* `STATUS_DLL_INIT_FAILED` (exit code -1073741502, surfaced by pnpm/turbo
- * as 3221225794) under `turbo run build`'s concurrency — an environment
+ * as 3221225794) under `turbo run build`'s concurrency, an environment
* fault unrelated to the code under test. `unit-test / test
* (windows-latest, *)` in the "CI" workflow has failed on this signature
* across many unrelated commits and packages.
@@ -38,7 +38,7 @@ async function main(): Promise {
const code = result.status ?? result.signal ?? 'unknown'
const isLastAttempt = attempt === attempts
- console.error(`\n[ci-retry] \`${command}\` failed (exit ${code}), attempt ${attempt}/${attempts}${isLastAttempt ? '' : ` — retrying in ${delayMs}ms`}\n`)
+ console.error(`\n[ci-retry] \`${command}\` failed (exit ${code}), attempt ${attempt}/${attempts}${isLastAttempt ? '' : `; retrying in ${delayMs}ms`}\n`)
if (isLastAttempt)
process.exit(typeof result.status === 'number' ? result.status : 1)
diff --git a/scripts/ecosystem-ci.ts b/scripts/ecosystem-ci.ts
index 02b3f0c1d..e13adf579 100644
--- a/scripts/ecosystem-ci.ts
+++ b/scripts/ecosystem-ci.ts
@@ -87,7 +87,7 @@ function prepareClone(ref: string): void {
if (existsSync(devtoolsDir))
rmSync(devtoolsDir, { recursive: true, force: true })
- // Use init + fetch instead of `clone --branch` so any ref works — tag,
+ // Use init + fetch instead of `clone --branch` so any ref works: tag,
// branch, or commit SHA. GitHub allows fetching reachable SHAs by default.
mkdirSync(devtoolsDir, { recursive: true })
run('git', ['init', '--quiet'], devtoolsDir)
diff --git a/scripts/play.ts b/scripts/play.ts
index adba6482a..d022ec7fe 100644
--- a/scripts/play.ts
+++ b/scripts/play.ts
@@ -15,7 +15,7 @@ import prompts from 'prompts'
const WORKSPACE_PATTERNS = ['examples/*', 'packages/*', 'plugins/*', 'storybook']
/**
- * Script names that make a workspace package runnable as a "play" — the
+ * Script names that make a workspace package runnable as a "play"; the
* first one present in a package's `scripts` wins.
*/
const RUN_SCRIPTS = ['dev', 'storybook', 'start']
@@ -64,7 +64,7 @@ async function main(): Promise {
.filter((play): play is Play => play !== undefined)
if (plays.length === 0) {
- console.error(`No playgrounds found — none of ${WORKSPACE_PATTERNS.join(', ')} has a package.json with a ${RUN_SCRIPTS.join('/')} script.`)
+ console.error(`No playgrounds found: none of ${WORKSPACE_PATTERNS.join(', ')} has a package.json with a ${RUN_SCRIPTS.join('/')} script.`)
process.exitCode = 1
return
}
diff --git a/scripts/smoke-bun.ts b/scripts/smoke-bun.ts
index 23e2943f5..89ac05035 100644
--- a/scripts/smoke-bun.ts
+++ b/scripts/smoke-bun.ts
@@ -1,12 +1,12 @@
/**
- * Bun smoke test for the Hono hub example — run locally with:
+ * Bun smoke test for the Hono hub example, run locally with:
*
* bun scripts/smoke-bun.ts
*
* Boots `examples/hub-hono-minimal/src/bun.ts` (Bun's fetch-upgrade wiring
* over the hub's context) and exercises four surfaces end to end: HTTP through
* the catch-all handler, the discovery documents, the embedded bootstrap, and
- * an RPC round-trip over a same-origin WebSocket upgrade — no side-car port
+ * an RPC round-trip over a same-origin WebSocket upgrade, with no side-car port
* anywhere.
*
* Prerequisites: `pnpm install && pnpm build` (the hub serves built dists).
@@ -23,7 +23,7 @@ const server = await startBunServer(0)
const origin = `http://localhost:${server.port}`
console.log(`serving on ${origin}`)
-// 1. Discovery through the fetch handler — the socket rides the app's own
+// 1. Discovery through the fetch handler: the socket rides the app's own
// origin, so the meta advertises a base-absolute path and no port.
const meta = await (await fetch(`${origin}/__devframes/__connection.json`)).json() as {
backend: string
diff --git a/scripts/sync-starter-version.ts b/scripts/sync-starter-version.ts
index 6f2e89769..8b5d13fba 100644
--- a/scripts/sync-starter-version.ts
+++ b/scripts/sync-starter-version.ts
@@ -8,7 +8,7 @@ const starterPkgPath = path.resolve(rootDir, 'starter/package.json')
/**
* Rewrites `starter/package.json`'s `devframe`/`@devframes/*` dependency
- * ranges to `^` — the starter is a self-contained, copy-paste-ready
+ * ranges to `^`, since the starter is a self-contained, copy-paste-ready
* template that pins real versions rather than `catalog:`/`workspace:*`, so
* a repo-wide bump has to touch it explicitly. Called from `bump.config.ts`'s
* `execute` hook so `bumpp -r` keeps it in lockstep automatically.
diff --git a/scripts/verify-typecheck-coverage.ts b/scripts/verify-typecheck-coverage.ts
index e7c2746eb..eebf59e61 100644
--- a/scripts/verify-typecheck-coverage.ts
+++ b/scripts/verify-typecheck-coverage.ts
@@ -12,7 +12,7 @@ import { fileURLToPath } from 'node:url'
* packages that **declare** it (`turbo.json`'s `typecheck` task fans out via
* `dependsOn: ["^typecheck"]`, but never invents the script). A workspace
* package with a `tsconfig.json` and no `typecheck` script is silently
- * skipped instead of failing loud — this script scans every workspace
+ * skipped instead of failing loud, so this script scans every workspace
* package for that gap and fails CI when it finds one that isn't a
* documented exception below.
*/
@@ -28,14 +28,14 @@ const WORKSPACE_PATTERNS = ['packages/*', 'plugins/*', 'examples/*', 'starter',
* Packages with a `tsconfig.json` that intentionally don't have a
* `typecheck` script yet. Each entry is a `pnpm typecheck` blind spot, so
* keep this list short and remove an entry the moment its package gets a
- * working script — the check below fails if an entry is stale (the package
+ * working script; the check below fails if an entry is stale (the package
* already has one).
*/
const EXCEPTIONS: Record = {
'plugins/inspect': 'tsconfig.json is the only one with composite:true, which makes tsc reject valid cross-package imports (TS6307); also has a couple of unrelated spa/composables type bugs. See plans/README.md "Execution notes" for plan 001.',
'examples/hub-next': 'packages/hub/src/node/host-terminals.ts types a child-process env as NodeJS.ProcessEnv, and Next.js\'s ambient types require a literal NODE_ENV on that interface once this app pulls hub into its program. See plans/README.md "Execution notes" for plan 001.',
- 'examples/hub-next-minimal': 'Same Next.js + hub NODE_ENV ambient conflict as examples/hub-next — the minimal Next host pulls hub into its program too.',
- 'docs': 'Nuxt app extending the comark-docs layer: tsconfig.json only holds project references into generated `.nuxt/tsconfig.*.json`, which exist only after `nuxt prepare` resolves the layer — type-checking it would drag a full Nuxt prepare into the Turbo graph.',
+ 'examples/hub-next-minimal': 'Same Next.js + hub NODE_ENV ambient conflict as examples/hub-next; the minimal Next host pulls hub into its program too.',
+ 'docs': 'Nuxt app extending the comark-docs layer: tsconfig.json only holds project references into generated `.nuxt/tsconfig.*.json`, which exist only after `nuxt prepare` resolves the layer, so type-checking it would drag a full Nuxt prepare into the Turbo graph.',
}
function expandPattern(pattern: string): string[] {
@@ -73,11 +73,11 @@ const staleExceptions = Object.keys(EXCEPTIONS).filter(dir => hasTypecheckScript
if (missing.length > 0) {
console.error('The following workspace packages have a tsconfig.json but no `typecheck` script:\n')
for (const dir of missing) console.error(` - ${dir}`)
- console.error('\nAdd `"typecheck": "tsc --noEmit"` to each package.json\'s scripts (see AGENTS.md), or — if it genuinely can\'t typecheck yet — add a documented exception to scripts/verify-typecheck-coverage.ts.')
+ console.error('\nAdd `"typecheck": "tsc --noEmit"` to each package.json\'s scripts (see AGENTS.md), or, if it genuinely can\'t typecheck yet, add a documented exception to scripts/verify-typecheck-coverage.ts.')
}
if (staleExceptions.length > 0) {
- console.error(`${missing.length > 0 ? '\n' : ''}The following exceptions in scripts/verify-typecheck-coverage.ts are stale — the package already has a \`typecheck\` script, so remove the entry:\n`)
+ console.error(`${missing.length > 0 ? '\n' : ''}The following exceptions in scripts/verify-typecheck-coverage.ts are stale; the package already has a \`typecheck\` script, so remove the entry:\n`)
for (const dir of staleExceptions) console.error(` - ${dir}`)
}
@@ -85,4 +85,4 @@ if (missing.length > 0 || staleExceptions.length > 0)
process.exit(1)
const covered = dirs.filter(dir => existsSync(join(rootDir, dir, 'tsconfig.json'))).length
-console.log(`typecheck coverage OK — ${covered - Object.keys(EXCEPTIONS).length}/${covered} eligible packages covered, ${Object.keys(EXCEPTIONS).length} documented exception(s).`)
+console.log(`typecheck coverage OK: ${covered - Object.keys(EXCEPTIONS).length}/${covered} eligible packages covered, ${Object.keys(EXCEPTIONS).length} documented exception(s).`)
diff --git a/services/git/src/git.ts b/services/git/src/git.ts
index 0b2f26223..67a1e6122 100644
--- a/services/git/src/git.ts
+++ b/services/git/src/git.ts
@@ -16,7 +16,7 @@ export interface GitRunResult {
}
/**
- * Run a git command in `cwd`. Rejects when git exits non-zero — callers that
+ * Run a git command in `cwd`. Rejects when git exits non-zero; callers that
* tolerate failure (e.g. "no upstream configured") should use {@link tryGit}.
*/
export async function runGit(cwd: string, args: string[]): Promise {
@@ -24,7 +24,7 @@ export async function runGit(cwd: string, args: string[]): Promise
cwd,
maxBuffer: MAX_BUFFER,
windowsHide: true,
- // Force plain, locale-independent output so parsers stay stable.
+ /** Force plain, locale-independent output so parsers stay stable. */
env: { ...process.env, GIT_PAGER: 'cat', GIT_OPTIONAL_LOCKS: '0', LC_ALL: 'C' },
})
return { stdout, stderr }
diff --git a/services/git/src/index.ts b/services/git/src/index.ts
index ec7f9fb29..47704291d 100644
--- a/services/git/src/index.ts
+++ b/services/git/src/index.ts
@@ -144,11 +144,11 @@ declare module 'devframe' {
}
/**
- * The git wire service — read/write git operations shared over RPC by every
+ * The git wire service: read/write git operations shared over RPC by every
* plugin on the host, generalizing the utilities that used to live inside the
* git plugin. The exec wrapper and output parsers stay internal; consumers get
* the typed {@link GitServiceApi} in-process (`ctx.services.get`) and the same
- * ops over `devframes:service:git:*` RPC. Write ops are always exposed —
+ * ops over `devframes:service:git:*` RPC. Write ops are always exposed;
* authorization is the host's connection-trust boundary. The service defines
* no `dump`/`snapshot`; a devframe bakes what it needs via `snapshotRpc`.
*/
@@ -158,7 +158,7 @@ export function createGitService(options?: GitServiceOptions): DevframeServiceDe
version: pkg.version,
scope: GIT_SERVICE_SCOPE,
options,
- // `cwd` deep-merges as a scalar (later installer wins) across declarers.
+ /** `cwd` deep-merges as a scalar (later installer wins) across declarers. */
setup(ctx, { options }) {
const ops = createGitOps(options?.cwd ?? ctx.cwd)
@@ -194,7 +194,7 @@ export function createGitService(options?: GitServiceOptions): DevframeServiceDe
jsonSerializable: true,
args: [s.object({ path: s.string(), ref: s.optional(s.string()) })],
returns: gitFileSchema,
- agent: { title: 'Git read file', description: 'Read the contents of a single file at a commit-ish (default HEAD) — the raw text of a versioned file without checking it out. found is false when no such file exists at the ref; binary blobs return with content omitted. Safe to call freely.' },
+ agent: { title: 'Git read file', description: 'Read the contents of a single file at a commit-ish (default HEAD): the raw text of a versioned file without checking it out. found is false when no such file exists at the ref; binary blobs return with content omitted. Safe to call freely.' },
handler: (args: ReadFileArgs): Promise => ops.readFile(args),
}))
ctx.rpc.register(defineRpcFunction({
@@ -203,7 +203,7 @@ export function createGitService(options?: GitServiceOptions): DevframeServiceDe
jsonSerializable: true,
args: [s.object({ path: s.optional(s.string()), staged: s.optional(s.boolean()) })],
returns: gitDiffSchema,
- agent: { title: 'Git diff', description: 'Unified diff of uncommitted changes — the working tree by default, the index with staged: true, one file with path. Safe to call freely.' },
+ agent: { title: 'Git diff', description: 'Unified diff of uncommitted changes: the working tree by default, the index with staged: true, one file with path. Safe to call freely.' },
handler: (args: DiffArgs = {}): Promise => ops.diff(args),
}))
ctx.rpc.register(defineRpcFunction({
@@ -221,7 +221,7 @@ export function createGitService(options?: GitServiceOptions): DevframeServiceDe
handler: (): Promise => ops.tags(),
}))
- // Write ops (always registered — authorization is the host's concern).
+ // Write ops (always registered; authorization is the host's concern).
ctx.rpc.register(defineRpcFunction({
name: 'stage',
type: 'action',
diff --git a/services/git/src/operations.ts b/services/git/src/operations.ts
index 18411d97e..a2a423d27 100644
--- a/services/git/src/operations.ts
+++ b/services/git/src/operations.ts
@@ -61,6 +61,52 @@ function mapCode(code: string): FileStatusCode {
}
}
+function applyBranchToken(status: GitStatus, token: string): void {
+ const [, key, ...rest] = token.split(' ')
+ const value = rest.join(' ')
+ switch (key) {
+ case 'branch.head':
+ status.detached = value === '(detached)'
+ status.branch = status.detached ? null : value
+ return
+ case 'branch.oid':
+ if (value !== '(initial)')
+ status.head = value.slice(0, 9)
+ return
+ case 'branch.upstream':
+ status.upstream = value
+ return
+ case 'branch.ab': {
+ const match = value.match(/\+(\d+)\s+-(\d+)/)
+ if (match) {
+ status.ahead = Number(match[1])
+ status.behind = Number(match[2])
+ }
+ }
+ }
+}
+
+/**
+ * Record a tracked change (`1 ` ordinary or `2 ` rename/copy) and return the
+ * token index consumed - a rename eats the following NUL token for its origin.
+ * Type 1 path begins at field 8; type 2 inserts the rename score at field 8,
+ * pushing the path to field 9 and the original to that extra token.
+ */
+function applyTrackedEntry(status: GitStatus, tokens: string[], index: number): number {
+ const fields = tokens[index].split(' ')
+ const [x, y] = fields[1]
+ const renamed = tokens[index].startsWith('2 ')
+ const path = fields.slice(renamed ? 9 : 8).join(' ')
+ const consumed = renamed ? index + 1 : index
+ const from = renamed ? tokens[consumed] : undefined
+
+ if (x !== '.')
+ status.staged.push(from ? { path, from, status: mapCode(x) } : { path, status: mapCode(x) })
+ if (y !== '.')
+ status.unstaged.push({ path, status: mapCode(y) })
+ return consumed
+}
+
/**
* Parse `git status --porcelain=v2 --branch -z` into a structured snapshot.
* Records are NUL-separated; rename/copy (type `2`) entries consume an extra
@@ -74,60 +120,13 @@ function parseStatus(root: string, raw: string): GitStatus {
const token = tokens[i]
if (!token)
continue
-
- if (token.startsWith('# ')) {
- const [, key, ...rest] = token.split(' ')
- const value = rest.join(' ')
- if (key === 'branch.head') {
- if (value === '(detached)') {
- status.detached = true
- status.branch = null
- }
- else {
- status.branch = value
- }
- }
- else if (key === 'branch.oid' && value !== '(initial)') {
- status.head = value.slice(0, 9)
- }
- else if (key === 'branch.upstream') {
- status.upstream = value
- }
- else if (key === 'branch.ab') {
- const match = value.match(/\+(\d+)\s+-(\d+)/)
- if (match) {
- status.ahead = Number(match[1])
- status.behind = Number(match[2])
- }
- }
- continue
- }
-
- if (token.startsWith('1 ') || token.startsWith('2 ')) {
- const renamed = token.startsWith('2 ')
- const fields = token.split(' ')
- const xy = fields[1]
- const x = xy[0]
- const y = xy[1]
- // Type 1 path begins at field 8; type 2 inserts the rename score at
- // field 8, pushing the path to field 9 and the original to a NUL token.
- const path = fields.slice(renamed ? 9 : 8).join(' ')
- const from = renamed ? tokens[++i] : undefined
-
- if (x !== '.')
- status.staged.push(from ? { path, from, status: mapCode(x) } : { path, status: mapCode(x) })
- if (y !== '.')
- status.unstaged.push({ path, status: mapCode(y) })
- continue
- }
-
- if (token.startsWith('u ')) {
- const path = token.split(' ').slice(10).join(' ')
- status.unstaged.push({ path, status: 'unmerged' } satisfies StatusFileEntry)
- continue
- }
-
- if (token.startsWith('? '))
+ if (token.startsWith('# '))
+ applyBranchToken(status, token)
+ else if (token.startsWith('1 ') || token.startsWith('2 '))
+ i = applyTrackedEntry(status, tokens, i)
+ else if (token.startsWith('u '))
+ status.unstaged.push({ path: token.split(' ').slice(10).join(' '), status: 'unmerged' } satisfies StatusFileEntry)
+ else if (token.startsWith('? '))
status.untracked.push(token.slice(2))
}
@@ -374,7 +373,7 @@ export function createGitOps(cwd: string): GitServiceApi {
return { isRepo: true, commits: [], limit, skip, hasMore: false }
command.push('--end-of-options', ref)
}
- // Pathspec after `--` — everything past it is treated as a path, never
+ // Pathspec after `--`: everything past it is treated as a path, never
// an option, so client paths need no dash guard here.
const paths = (args.paths ?? []).map(p => p.trim()).filter(Boolean)
if (paths.length > 0)
@@ -415,7 +414,7 @@ export function createGitOps(cwd: string): GitServiceApi {
catch {
return base
}
- // A NUL byte marks binary content — omit it rather than return garbage.
+ // A NUL byte marks binary content, so omit it rather than return garbage.
if (raw.includes('\0'))
return { ...base, found: true, binary: true }
const { text: content, truncated } = clipText(raw, FILE_CHAR_LIMIT)
@@ -489,8 +488,6 @@ export function createGitOps(cwd: string): GitServiceApi {
const parsed = Date.parse(isoDate)
return {
name,
- // Annotated tags dereference to their target commit; lightweight
- // tags point straight at it.
sha: targetSha || objectSha,
date: Number.isNaN(parsed) ? 0 : parsed,
subject: subject ?? '',
diff --git a/services/git/src/types.ts b/services/git/src/types.ts
index 768b396ed..ff8b45bdc 100644
--- a/services/git/src/types.ts
+++ b/services/git/src/types.ts
@@ -47,7 +47,7 @@ export interface Commit {
body: string
/** Ref names pointing at this commit (branches, tags, HEAD). */
refs: string[]
- /** Full parent hashes — drives the commit graph. */
+ /** Full parent hashes; drives the commit graph. */
parents: string[]
}
@@ -94,7 +94,7 @@ export interface Tag {
/** Short SHA of the commit the tag ultimately points to. */
sha: string
/**
- * Tag creation date as epoch milliseconds — the tag's own date for
+ * Tag creation date as epoch milliseconds: the tag's own date for
* annotated tags, the target commit's date for lightweight tags. `0` when
* the date can't be parsed.
*/
@@ -148,7 +148,7 @@ export interface GitDiff {
files: DiffFile[]
totalAdditions: number
totalDeletions: number
- /** Unified patch text — populated when `path` targets a single file. */
+ /** Unified patch text, populated when `path` targets a single file. */
patch: string | null
/** `true` when `patch` was clipped to the internal char limit. */
truncated: boolean
diff --git a/services/git/test/_repo.ts b/services/git/test/_repo.ts
index dd1fba216..a4950ecbe 100644
--- a/services/git/test/_repo.ts
+++ b/services/git/test/_repo.ts
@@ -17,7 +17,7 @@ const GIT_ENV = {
GIT_COMMITTER_EMAIL: 'test@example.com',
GIT_AUTHOR_DATE: '2020-01-01T00:00:00Z',
GIT_COMMITTER_DATE: '2020-01-01T00:00:00Z',
- // Ignore the developer's global/system config so commits are deterministic.
+ /** Ignore the developer's global/system config so commits are deterministic. */
GIT_CONFIG_GLOBAL: '/dev/null',
GIT_CONFIG_SYSTEM: '/dev/null',
}
@@ -63,7 +63,7 @@ export function createTempRepo(): TempRepo {
git(dir, ['branch', 'feature/x'])
// Tags: a lightweight tag on the initial commit, and an annotated tag (with
- // its own, later tagger date) on HEAD — exercises `creatordate`, which
+ // its own, later tagger date) on HEAD, exercising `creatordate`, which
// populates for annotated tags where `committerdate` would be empty.
git(dir, ['tag', 'v0.0.1', 'HEAD~1'])
gitAt(dir, ['tag', '-a', 'v1.0.0', '-m', 'release one'], '2021-06-01T00:00:00Z')
@@ -82,9 +82,9 @@ export function createTempRepo(): TempRepo {
/**
* Create a repo whose commits touch distinct paths, for path-scoped log:
- * 1. `feat: src a` — adds `src/a.ts`
- * 2. `docs: b` — adds `docs/b.md`
- * 3. `fix: src a` — modifies `src/a.ts`
+ * 1. `feat: src a` adds `src/a.ts`
+ * 2. `docs: b` adds `docs/b.md`
+ * 3. `fix: src a` modifies `src/a.ts`
*/
export function createPathRepo(): TempRepo {
const dir = mkdtempSync(join(tmpdir(), 'devframe-git-paths-'))
diff --git a/services/git/test/git.test.ts b/services/git/test/git.test.ts
index b56428021..4c2c0f294 100644
--- a/services/git/test/git.test.ts
+++ b/services/git/test/git.test.ts
@@ -112,7 +112,7 @@ describe('@devframes/service-git', () => {
expect(readme.ref).toBe('HEAD')
expect(readme.content).toBe('# Demo\n')
- // `a.txt` only exists from the second commit — absent at the initial one.
+ // `a.txt` only exists from the second commit, absent at the initial one.
const log = await git.log({})
const initHash = log.commits[1].hash
const atInit = await git.readFile({ path: 'a.txt', ref: initHash })
@@ -261,7 +261,7 @@ describe('@devframes/service-git', () => {
void ctx.services.install(createGitService())
await ctx.services.ready()
- // Auto-discovered from the RPC `agent` field — the hub's MCP surfaces this
+ // Auto-discovered from the RPC `agent` field; the hub's MCP surfaces this
// as `devframes_service_git_status` (the e2e asserts that name).
const tool = ctx.agent.getTool('devframes:service:git:status')
expect(tool?.title).toBe('Git status')
diff --git a/services/open/src/diagnostics.ts b/services/open/src/diagnostics.ts
index 447352d2f..6a73d690c 100644
--- a/services/open/src/diagnostics.ts
+++ b/services/open/src/diagnostics.ts
@@ -1,8 +1,10 @@
import { defineDiagnostics } from 'devframe/utils/nostics'
-// Uses the service's own `DS_OPEN_` prefix per the built-in convention,
-// keeping it collision-free with devframe core (`DF00xx`), the hub
-// (`DF8xxx`), and the plugins (`DP__`).
+/**
+ * Uses the service's own `DS_OPEN_` prefix per the built-in convention,
+ * keeping it collision-free with devframe core (`DF00xx`), the hub
+ * (`DF8xxx`), and the plugins (`DP__`).
+ */
export const diagnostics = defineDiagnostics({
docsBase: 'https://devfra.me/errors',
codes: {
diff --git a/services/open/src/index.ts b/services/open/src/index.ts
index 777aee819..c94cb03ca 100644
--- a/services/open/src/index.ts
+++ b/services/open/src/index.ts
@@ -29,14 +29,14 @@ export const OPEN_SERVICE_SCOPE = 'devframes:service:open'
export interface OpenServiceOptions {
/**
- * Preferred editor command — one of the `KNOWN_EDITORS` `launch-editor`
+ * Preferred editor command, one of the `KNOWN_EDITORS` `launch-editor`
* recognizes. Auto-detected (via `LAUNCH_EDITOR` and common defaults)
* when omitted. On merge, the later installer's choice wins.
*/
editor?: KnownEditor
/**
* Additional directories files may be opened from, on top of the
- * context's `workspaceRoot` — e.g. a plugin's managed storage dir that
+ * context's `workspaceRoot`, e.g. a plugin's managed storage dir that
* lives outside the workspace. Merged as a union across installers.
*/
roots?: string[]
@@ -44,7 +44,7 @@ export interface OpenServiceOptions {
export interface OpenInEditorInput {
/**
- * File to open — absolute, or relative to the service's `workspaceRoot`
+ * File to open, absolute or relative to the service's `workspaceRoot`
* (so a client with only a workspace-relative path, e.g. a message's file
* position, can call this directly without a server-side bridge).
*/
@@ -76,7 +76,7 @@ declare module 'devframe' {
}
/**
- * The open wire service — `open-in-editor` / `open-in-finder` RPC shared by
+ * The open wire service: `open-in-editor` / `open-in-finder` RPC shared by
* every plugin on the host, replacing per-plugin registrations of the
* (deprecated) `devframe/recipes/common-rpc-functions` recipes. Paths may be
* absolute or relative to the `workspaceRoot`; the service refuses paths
@@ -91,8 +91,10 @@ export function createOpenService(options?: OpenServiceOptions): DevframeService
version: pkg.version,
scope: OPEN_SERVICE_SCOPE,
options,
- // Option sets from multiple installers merge via devframe's default
- // deep-merge: `roots` union, `editor` last-wins.
+ /**
+ * Option sets from multiple installers merge via devframe's default
+ * deep-merge: `roots` union, `editor` last-wins.
+ */
setup(ctx, { options }) {
const allowedRoots = [ctx.workspaceRoot, ...(options?.roots ?? [])].map(r => resolve(r))
// Canonical forms of the same roots (symlinks in the root paths
diff --git a/services/shiki/src/index.ts b/services/shiki/src/index.ts
index bd2caa432..bca6c50b3 100644
--- a/services/shiki/src/index.ts
+++ b/services/shiki/src/index.ts
@@ -64,7 +64,7 @@ declare module 'devframe' {
}
}
-/** Tiny insertion-order LRU — enough to absorb re-renders of the same code. */
+/** Tiny insertion-order LRU, enough to absorb re-renders of the same code. */
class Lru {
private map = new Map()
constructor(private max: number) {}
@@ -91,7 +91,7 @@ const inputSchema = s.object({
})
/**
- * The Shiki wire service — server-side syntax highlighting shared by every
+ * The Shiki wire service: server-side syntax highlighting shared by every
* plugin on the host, so client bundles stop shipping their own grammars and
* themes. Shiki itself loads lazily on first use; results are LRU-cached per
* `(code, lang, themes)` and every RPC function is `cacheable` on the client
@@ -103,8 +103,10 @@ export function createShikiService(options?: ShikiServiceOptions): DevframeServi
version: pkg.version,
scope: SHIKI_SERVICE_SCOPE,
options,
- // Option sets from multiple installers merge via devframe's default
- // deep-merge: `langs` union, `themes` deep-merged (per-key last-wins).
+ /**
+ * Option sets from multiple installers merge via devframe's default
+ * deep-merge: `langs` union, `themes` deep-merged (per-key last-wins).
+ */
setup(ctx, { options }) {
const defaultThemes = options?.themes ?? SHIKI_DEFAULT_THEMES
@@ -154,7 +156,7 @@ export function createShikiService(options?: ShikiServiceOptions): DevframeServi
(await shiki()).codeToTokens(input.code, { lang, themes: { ...themes } })),
}
- // `s.object({})` is guard-only (extra keys survive) — a permissive
+ // `s.object({})` is guard-only (extra keys survive), a permissive
// envelope for the structured HAST / tokens payloads.
ctx.rpc.register(defineRpcFunction({
name: 'highlight',
diff --git a/storybook/README.md b/storybook/README.md
index 1cbbbc7f8..0f39833da 100644
--- a/storybook/README.md
+++ b/storybook/README.md
@@ -7,23 +7,23 @@ alongside the live terminals devframe running as a real mounted devframe.
The whole host-framework integration is one Vite plugin (`src/hub.ts`): one `initHub()` call mounts
the terminals devframe (via the `devframes` list) and, in its `configure(ctx)`
-step, registers a launcher dock (and a bound command) per built-in devframe's Storybook —
+step, registers a launcher dock (and a bound command) per built-in devframe's Storybook,
all behind the hub's connect middleware on a side-car RPC/WS server.
-Each Storybook dock is a `type: 'launcher'` tile with a **Start** button — the
+Each Storybook dock is a `type: 'launcher'` tile with a **Start** button, the
lazy trigger. The button binds a `ctx.commands` command (`storybook:launch:`),
so the client dispatches it over the serializable `hub:commands:execute` path.
Once launched, the tile swaps in place for the running Storybook's iframe, kept
mounted so its state survives tab switches. Where the iframe points depends on
the mode:
-- **dev** (`vite`) — the launch command spawns the devframe's `storybook dev`
+- **dev** (`vite`): the launch command spawns the devframe's `storybook dev`
through `ctx.terminals`, the hub's terminals subsystem, so each Storybook is a
read-only terminal session (open the **Terminals** dock to watch its output
stream live). As it boots, the tail of that output is patched onto the
launcher's `digest`; on ready the command returns the live dev-server URL the
client iframes (HMR).
-- **build** (`vite preview`) — the launch resolves immediately to the pre-built
+- **build** (`vite preview`): the launch resolves immediately to the pre-built
`storybook-static/` the hub serves on one origin.
## Run it
@@ -34,7 +34,7 @@ Build the devframe SPAs the hub mounts (terminals) once:
pnpm build
```
-### Dev — Storybooks spawned on demand
+### Dev: Storybooks spawned on demand
```sh
pnpm storybook
@@ -45,7 +45,7 @@ dev server boots on demand (subsequent opens are instant). The dev servers
listen on their own ports, so reaching them from a remote browser needs those
ports forwarded.
-### Preview — pre-built Storybooks on one origin
+### Preview: pre-built Storybooks on one origin
```sh
pnpm storybook:build # produces storybook-static/
diff --git a/storybook/src/client/main.ts b/storybook/src/client/main.ts
index bebcbd66d..ea3be6d11 100644
--- a/storybook/src/client/main.ts
+++ b/storybook/src/client/main.ts
@@ -31,7 +31,7 @@ interface DockRuntime {
error?: string
}
-// Every launched dock's iframe is parked here for its whole lifetime — switching
+// Every launched dock's iframe is parked here for its whole lifetime, so switching
// tabs only mounts/unmounts the pane over `#stage`, so background docks keep
// their state (Storybook's own routing, scroll, etc.) intact.
const panes = createIframePanes({ container: stageEl })
@@ -89,13 +89,42 @@ function launcherTile(entry: LauncherDock): string {
`
}
-function updateStage() {
+function syncPanes() {
for (const pane of panes.list()) {
if (pane.id === selectedId)
pane.mount(stageEl)
else
pane.unmount()
}
+}
+
+function errorTile(entry: Dock | undefined, rt: DockRuntime, title: string): string {
+ const detail = rt.error ? `
')
@@ -106,35 +135,19 @@ function updateStage() {
const rt = runtimeFor(selectedId)
const title = entry?.title ?? selectedId
- // A launched pane is mounted — hide the overlay and show the live iframe.
+ // A launched pane is mounted, so hide the overlay and show the live iframe.
if (rt.status === 'ready' && panes.has(selectedId)) {
overlayEl.style.display = 'none'
return
}
if (rt.status === 'error') {
- overlay(`
-
-
Failed to start ${title}
- ${rt.error ? `
${rt.error}
` : ''}
- ${entry && isLauncherDock(entry) ? `` : ''}`)
+ overlay(errorTile(entry, rt, title))
return
}
- // A launcher: idle shows its start tile; starting mirrors the live `digest`
- // (the tail of the `storybook dev` output the host streams onto the tile).
if (entry && isLauncherDock(entry)) {
- if (rt.status === 'starting') {
- const digest = entry.launcher.digest
- overlay(`
-
-
Starting ${title}…
- ${digest ? `
${digest}
` : ''}
- `)
- }
- else {
- overlay(launcherTile(entry))
- }
+ overlay(launcherStageTile(entry, rt, title))
return
}
@@ -211,7 +224,7 @@ async function main() {
selectedId = id
renderSidebar()
// Plain iframe docks open on select; launcher docks wait for their Start
- // button (the lazy trigger) — so opening a Storybook dock doesn't spawn it.
+ // button (the lazy trigger), so opening a Storybook dock doesn't spawn it.
if (isIframeDock(entry))
openIframe(entry)
updateStage()
@@ -237,7 +250,7 @@ async function main() {
}).join('')
}
- // Docks — read from `devframe:docks` shared state, keeping launcher (Storybook)
+ // Docks, read from `devframe:docks` shared state, keeping launcher (Storybook)
// and iframe (live plugin) entries.
const docksState = await rpc.sharedState.get('devframe:docks', { initialValue: [] })
const syncDocks = () => {
diff --git a/storybook/src/hub.ts b/storybook/src/hub.ts
index 3de681ebd..faa61d0c4 100644
--- a/storybook/src/hub.ts
+++ b/storybook/src/hub.ts
@@ -39,7 +39,7 @@ const STORYBOOKS: StorybookMeta[] = [
// regardless of the process cwd.
const repoRoot = fileURLToPath(new URL('../../', import.meta.url))
const require = createRequire(import.meta.url)
-// Storybook's CLI entry — run with `node` so we don't depend on PATH/.bin.
+// Storybook's CLI entry, run with `node` so we don't depend on PATH/.bin.
const storybookBin = join(dirname(require.resolve('storybook/package.json')), 'dist/bin/dispatcher.js')
const pluginDir = (id: string): string => join(repoRoot, 'plugins', id)
@@ -52,7 +52,7 @@ const launchCommandFor = (id: string): string => `storybook:launch:${id}`
// eslint-disable-next-line no-control-regex
const ANSI = /\u001B\[[0-9;]*[A-Z]/gi
-/** Last non-empty, ANSI-stripped line of a chunk — the launcher's `digest`. */
+/** Last non-empty, ANSI-stripped line of a chunk, the launcher's `digest`. */
function lastLine(chunk: string): string | undefined {
const lines = chunk.replace(ANSI, '').split(/\r?\n/).map(l => l.trim()).filter(Boolean)
return lines.at(-1)
@@ -73,7 +73,7 @@ export interface StorybookHubOptions {
/**
* A Vite plugin that turns this package's Vite dev/preview server into a
- * devframe hub whose docks are the built-in plugins' Storybooks — plus the live
+ * devframe hub whose docks are the built-in plugins' Storybooks, plus the live
* terminals plugin. It's the unified Storybook host, built as a devframe hub
* rather than via Storybook Composition.
*
@@ -111,7 +111,7 @@ export function storybookHub(options: StorybookHubOptions = {}): Plugin {
* Spawn (once) the `storybook dev` server for a plugin and resolve when it
* answers on its port. Concurrent callers await the same boot. The process
* is owned by the hub's terminals subsystem (`ctx.terminals`), so it shows
- * up as a read-only session — proper title + icon, output streamed live —
+ * up as a read-only session (proper title + icon, output streamed live)
* in the Terminals dock. `reportDigest` receives the tail of that output so
* the caller can surface boot progress on the launcher.
*/
@@ -133,7 +133,7 @@ export function storybookHub(options: StorybookHubOptions = {}): Plugin {
// terminals host; the public interface doesn't surface it yet.)
const stale = ctx.terminals.sessions.get(sessionId)
if (stale)
- (ctx.terminals as unknown as { remove?: (s: typeof stale) => void }).remove?.(stale)
+ (ctx.terminals as { remove?: (s: typeof stale) => void }).remove?.(stale)
const session = await ctx.terminals.startChildProcess(
{
@@ -189,8 +189,8 @@ export function storybookHub(options: StorybookHubOptions = {}): Plugin {
const cwd = viteConfig?.root ?? process.cwd()
- // In build mode, serve each pre-built Storybook on the Vite server itself
- // — outside the hub base, so a launcher iframe resolves it on this origin.
+ // In build mode, serve each pre-built Storybook on the Vite server itself,
+ // outside the hub base, so a launcher iframe resolves it on this origin.
if (mode === 'build') {
for (const meta of STORYBOOKS) {
if (existsSync(storybookStaticDir(meta.id)))
@@ -201,14 +201,18 @@ export function storybookHub(options: StorybookHubOptions = {}): Plugin {
hub = initHub({
base,
cwd,
- // Bind dual-stack (`::` accepts IPv6 + IPv4-mapped) so the side-car is
- // dialable via `::1`, `127.0.0.1`, and from outside the machine — the
- // default `localhost` bind resolves to `::1` only on some hosts, which
- // strands IPv4 clients and remote browsers.
+ /**
+ * Bind dual-stack (`::` accepts IPv6 + IPv4-mapped) so the side-car is
+ * dialable via `::1`, `127.0.0.1`, and from outside the machine; the
+ * default `localhost` bind resolves to `::1` only on some hosts, which
+ * strands IPv4 clients and remote browsers.
+ */
host: '::',
auth: false,
- // Prefer 9787 but fall back to a free port when taken; the client
- // discovers whatever was chosen via `__connection.json`.
+ /**
+ * Prefer 9787 but fall back to a free port when taken; the client
+ * discovers whatever was chosen via `__connection.json`.
+ */
ws: options.port != null ? { port: options.port } : { sidecar: true },
getStorageDir(scope) {
if (scope === 'workspace')
@@ -217,17 +221,19 @@ export function storybookHub(options: StorybookHubOptions = {}): Plugin {
return join(cwd, 'node_modules/.devframe-storybook')
return join(homedir(), '.devframe-storybook')
},
- // The live terminals plugin — a real integration docked alongside the
- // Storybooks, grouped separately so its "Terminals" reads apart from the
- // "Terminals" Storybook. It also mirrors the hub's `ctx.terminals`
- // sessions, so the spawned `storybook dev` processes appear inside it.
+ /**
+ * The live terminals plugin, a real integration docked alongside the
+ * Storybooks, grouped separately so its "Terminals" reads apart from the
+ * "Terminals" Storybook. It also mirrors the hub's `ctx.terminals`
+ * sessions, so the spawned `storybook dev` processes appear inside it.
+ */
devframes: [{ devframe: createTerminalsDevframe(), dock: { category: 'Plugins' } }],
configure(context) {
// Live launcher handles, so the launch command can patch each tile's
// status/digest/terminalSessionId as the process boots.
const launchers = new Map) => void }>()
- /** The full launcher payload for a tile (patched wholesale — `update` shallow-merges). */
+ /** The full launcher payload for a tile (patched wholesale, since `update` shallow-merges). */
const launcherState = (
meta: StorybookMeta,
patch: Partial,
@@ -280,7 +286,7 @@ export function storybookHub(options: StorybookHubOptions = {}): Plugin {
// One launcher dock per plugin Storybook, each bound to a command. A
// viewer dispatches the command over `hub:commands:execute` (the
- // serializable path — the handler is stripped when the entry crosses
+ // serializable path, since the handler is stripped when the entry crosses
// into shared state), and reads back the {@link EnsureStorybookResult}
// to iframe the result.
for (const meta of STORYBOOKS) {
@@ -318,12 +324,12 @@ export function storybookHub(options: StorybookHubOptions = {}): Plugin {
viteConfig = config
},
- // `vite` (dev): Storybooks are spawned on demand.
+ /** `vite` (dev): Storybooks are spawned on demand. */
async configureServer(server) {
await startHub(server, 'dev')
},
- // `vite preview` (after `vite build`): Storybooks are served static.
+ /** `vite preview` (after `vite build`): Storybooks are served static. */
async configurePreviewServer(server) {
await startHub(server, 'build')
},
diff --git a/storybook/uno.config.ts b/storybook/uno.config.ts
index eb8d7790f..de98e532b 100644
--- a/storybook/uno.config.ts
+++ b/storybook/uno.config.ts
@@ -1,10 +1,12 @@
import { mergeConfigs } from 'unocss'
import { designConfig } from '../design/uno.config'
-// The unified Storybook host is a devframe hub; its UI composes the shared
-// devframe base (see `design/uno.config.ts`). Pair with `@antfu/design/styles.css`
-// (imported in `src/client/main.ts`). `.ts` is opted into extraction since the
-// hub authors its class strings in vanilla `src/client/main.ts`.
+/**
+ * The unified Storybook host is a devframe hub; its UI composes the shared
+ * devframe base (see `design/uno.config.ts`). Pair with `@antfu/design/styles.css`
+ * (imported in `src/client/main.ts`). `.ts` is opted into extraction since the
+ * hub authors its class strings in vanilla `src/client/main.ts`.
+ */
export default mergeConfigs([
designConfig,
{
diff --git a/storybook/vite.config.ts b/storybook/vite.config.ts
index d5b1bc313..c88c23d93 100644
--- a/storybook/vite.config.ts
+++ b/storybook/vite.config.ts
@@ -5,8 +5,10 @@ import { storybookHub } from './src/hub'
export default defineConfig({
resolve: { alias },
- // Dev tooling reached from arbitrary hostnames (LAN IPs, tunnels, tailnets):
- // accept any Host header and fall back to the next free port when busy.
+ /**
+ * Dev tooling reached from arbitrary hostnames (LAN IPs, tunnels, tailnets):
+ * accept any Host header and fall back to the next free port when busy.
+ */
server: { allowedHosts: true, strictPort: false },
preview: { allowedHosts: true, strictPort: false },
plugins: [
diff --git a/tests/__snapshots__/tsnapi/@devframes/hub/node.snapshot.d.ts b/tests/__snapshots__/tsnapi/@devframes/hub/node.snapshot.d.ts
index 985f77c37..ee478ad7d 100644
--- a/tests/__snapshots__/tsnapi/@devframes/hub/node.snapshot.d.ts
+++ b/tests/__snapshots__/tsnapi/@devframes/hub/node.snapshot.d.ts
@@ -72,9 +72,11 @@ export declare class DevframeTerminalsHost implements DevframeTerminalsHost$1 {
private _channel?;
constructor(_: DevframeHubContext);
private getStreamingChannel;
+ private createStreamLifecycle;
register(_: DevframeTerminalSession): DevframeTerminalSession;
update(_: PartialWithoutId): void;
remove(_: DevframeTerminalSession): void;
+ private pumpStream;
private bindStream;
startChildProcess(_: DevframeChildProcessExecuteOptions, _: Omit): Promise;
startPtySession(_: DevframePtyExecuteOptions, _: Omit): Promise;
diff --git a/tests/__snapshots__/tsnapi/@devframes/json-render/node.snapshot.d.ts b/tests/__snapshots__/tsnapi/@devframes/json-render/node.snapshot.d.ts
index f61c13bfc..1e963b9c2 100644
--- a/tests/__snapshots__/tsnapi/@devframes/json-render/node.snapshot.d.ts
+++ b/tests/__snapshots__/tsnapi/@devframes/json-render/node.snapshot.d.ts
@@ -43,7 +43,7 @@ export declare const jsonRenderDiagnostics: Diagnostics<{
id: string;
reason: string;
}) => string;
- readonly fix: "Specs and state travel as strict JSON — remove functions, symbols, class instances, Map/Set, or circular references.";
+ readonly fix: "Specs and state travel as strict JSON, so remove functions, symbols, class instances, Map/Set, or circular references.";
};
readonly DF0073: {
readonly why: (p: {
diff --git a/tests/__snapshots__/tsnapi/@devframes/plugin-code-server/node.snapshot.d.ts b/tests/__snapshots__/tsnapi/@devframes/plugin-code-server/node.snapshot.d.ts
index 238e08aee..e0de0f463 100644
--- a/tests/__snapshots__/tsnapi/@devframes/plugin-code-server/node.snapshot.d.ts
+++ b/tests/__snapshots__/tsnapi/@devframes/plugin-code-server/node.snapshot.d.ts
@@ -60,6 +60,17 @@ export declare class CodeServerSupervisor {
detect(): Promise;
status(): CodeServerStatusResult;
start(_?: CodeServerStartRequest): Promise;
+ private tryAdopt;
+ private resolveInitialPort;
+ private buildLaunchEnv;
+ private consumeOutput;
+ private latchPort;
+ private latchLogin;
+ private latchReadyUrl;
+ private handleChildError;
+ private handleChildExit;
+ private finalizeLocalStart;
+ private handleStartFailure;
stop(): CodeServerStatusResult;
dispose(): void;
get resolvedBackend(): CodeServerBackend;
@@ -72,6 +83,8 @@ export declare class CodeServerSupervisor {
private resolveHubTerminals;
private reflectHub;
private launchProcess;
+ private launchViaHub;
+ private launchDirect;
private appendLog;
private lastLog;
private publish;
diff --git a/tests/__snapshots__/tsnapi/@devframes/plugin-code-server/node.snapshot.js b/tests/__snapshots__/tsnapi/@devframes/plugin-code-server/node.snapshot.js
index bfecc56b8..a73082f63 100644
--- a/tests/__snapshots__/tsnapi/@devframes/plugin-code-server/node.snapshot.js
+++ b/tests/__snapshots__/tsnapi/@devframes/plugin-code-server/node.snapshot.js
@@ -36,6 +36,17 @@ export class CodeServerSupervisor {
async detect() {}
status() {}
async start(_) {}
+ async tryAdopt(_) {}
+ async resolveInitialPort(_) {}
+ buildLaunchEnv(_) {}
+ consumeOutput(_, _, _) {}
+ latchPort(_, _) {}
+ latchLogin(_, _, _) {}
+ latchReadyUrl(_, _, _) {}
+ handleChildError(_, _, _) {}
+ handleChildExit(_, _, _) {}
+ async finalizeLocalStart(_, _) {}
+ handleStartFailure(_, _, _, _) {}
stop() {}
dispose() {}
get resolvedBackend() {}
@@ -48,6 +59,8 @@ export class CodeServerSupervisor {
resolveHubTerminals() {}
reflectHub(_) {}
async launchProcess(_, _, _) {}
+ async launchViaHub(_, _, _, _) {}
+ launchDirect(_, _, _) {}
appendLog(_) {}
lastLog() {}
publish() {}
diff --git a/tests/__snapshots__/tsnapi/devframe/internal.snapshot.d.ts b/tests/__snapshots__/tsnapi/devframe/internal.snapshot.d.ts
index 1915953ec..ee600f14e 100644
--- a/tests/__snapshots__/tsnapi/devframe/internal.snapshot.d.ts
+++ b/tests/__snapshots__/tsnapi/devframe/internal.snapshot.d.ts
@@ -127,7 +127,7 @@ export declare const diagnostics: import("nostics").Diagnostics<{
channel: string;
id: string;
}) => string;
- readonly fix: "Track the producer lifecycle — guard writes with the `stream.signal.aborted` flag.";
+ readonly fix: "Track the producer lifecycle by guarding writes with the `stream.signal.aborted` flag.";
};
readonly DF0032: {
readonly why: (p: {
@@ -159,7 +159,7 @@ export declare const diagnostics: import("nostics").Diagnostics<{
readonly why: (p: {
name: string;
}) => string;
- readonly fix: "Complete the auth handshake (or connect with a static/pre-shared token) before calling a trusted method. Untrusted callers may only call `anonymous:`-prefixed methods — see `isAnonymousRpcMethod`.";
+ readonly fix: "Complete the auth handshake (or connect with a static/pre-shared token) before calling a trusted method. Untrusted callers may only call `anonymous:`-prefixed methods; see `isAnonymousRpcMethod`.";
};
readonly DF0037: {
readonly why: (p: {
@@ -208,7 +208,7 @@ export declare const diagnostics: import("nostics").Diagnostics<{
readonly why: (p: {
port: number;
}) => string;
- readonly fix: "Call devframe_connect_list-instances for the current instance list — the instance may have stopped or changed port.";
+ readonly fix: "Call devframe_connect_list-instances for the current instance list; the instance may have stopped or changed port.";
};
readonly DF0051: {
readonly why: (p: {
@@ -228,7 +228,7 @@ export declare const diagnostics: import("nostics").Diagnostics<{
readonly why: (p: {
id: string;
}) => string;
- readonly fix: "Await `instance.ready` (or any request through `instance.handler`) before reading `connectionMeta()` — the WebSocket binding it describes is only known once initialization completes.";
+ readonly fix: "Await `instance.ready` (or any request through `instance.handler`) before reading `connectionMeta()`; the WebSocket binding it describes is only known once initialization completes.";
};
readonly DF0055: {
readonly why: (p: {
@@ -244,7 +244,7 @@ export declare const diagnostics: import("nostics").Diagnostics<{
};
readonly DF0057: {
readonly why: () => string;
- readonly fix: "Clients connect over the SSE endpoint instead — no upgrade wiring is needed. Remove `ws: false` if the instance should serve a WebSocket after all.";
+ readonly fix: "Clients connect over the SSE endpoint instead, so no upgrade wiring is needed. Remove `ws: false` if the instance should serve a WebSocket after all.";
};
readonly DF0058: {
readonly why: (p: {
@@ -275,7 +275,7 @@ export declare const diagnostics: import("nostics").Diagnostics<{
required: string;
installed: string;
}) => string;
- readonly fix: "Align the installed assets package with the version its node package declares — they are published in lockstep.";
+ readonly fix: "Align the installed assets package with the version its node package declares; they are published in lockstep.";
};
readonly DF0062: {
readonly why: (p: {
@@ -305,7 +305,7 @@ export declare const diagnostics: import("nostics").Diagnostics<{
field: "package" | "version";
value: string;
}) => string;
- readonly fix: "A remote-assets `package` must be a valid npm package name and `version` an exact semver version (e.g. `1.2.3`) — they are interpolated into CDN URLs and the cache path.";
+ readonly fix: "A remote-assets `package` must be a valid npm package name and `version` an exact semver version (e.g. `1.2.3`); they are interpolated into CDN URLs and the cache path.";
};
readonly DF0066: {
readonly why: (p: {
@@ -341,7 +341,7 @@ export declare const diagnostics: import("nostics").Diagnostics<{
package: string;
reason: string;
}) => string;
- readonly fix: "A service package's default export must be a factory returning a `DevframeServiceDefinition` — an object with `package`, `version`, `scope`, and a `setup` function.";
+ readonly fix: "A service package's default export must be a factory returning a `DevframeServiceDefinition`, an object with `package`, `version`, `scope`, and a `setup` function.";
};
readonly DF0072: {
readonly why: (p: {
diff --git a/tests/e2e/_support/serve-static.mjs b/tests/e2e/_support/serve-static.mjs
index b39a70a08..030869655 100644
--- a/tests/e2e/_support/serve-static.mjs
+++ b/tests/e2e/_support/serve-static.mjs
@@ -52,7 +52,7 @@ function send(res, status, body, headers = {}) {
const server = createServer((req, res) => {
const found = resolveAsset(req.url ?? '/')
- // SPA fallback — unknown routes (no file extension match) serve index.html
+ // SPA fallback: unknown routes (no file extension match) serve index.html
// so client-side routing works under the static dump.
const file = found ?? resolveAsset('/index.html')
if (!file) {
diff --git a/tests/e2e/devframe-connect.spec.ts b/tests/e2e/devframe-connect.spec.ts
index f4a60c468..8663c6fab 100644
--- a/tests/e2e/devframe-connect.spec.ts
+++ b/tests/e2e/devframe-connect.spec.ts
@@ -19,7 +19,7 @@ test.describe('devframe connect (files-inspector)', () => {
)
expect(instance).toBeDefined()
// The probe may adopt an explicit address family for a `localhost`
- // origin — accept either spelling.
+ // origin, so accept either spelling.
expect(instance.mcp.url).toMatch(/^http:\/\/(?:localhost|127\.0\.0\.1):9876\/__devframe-files-inspector\/__mcp$/)
const toolNames = instance.mcp.tools.map((t: any) => t.name)
expect(toolNames).toContain('devframe_state_read')
diff --git a/tests/e2e/next-devframe-hub-dev.spec.ts b/tests/e2e/next-devframe-hub-dev.spec.ts
index 6c83a81c0..95a88f880 100644
--- a/tests/e2e/next-devframe-hub-dev.spec.ts
+++ b/tests/e2e/next-devframe-hub-dev.spec.ts
@@ -21,7 +21,7 @@ test.describe('devframe connect (next-devframe-hub)', () => {
}
}, { timeout: 150_000, intervals: [1000] }).toBe(200)
- // The meta advertises the in-process MCP endpoint — same origin as the
+ // The meta advertises the in-process MCP endpoint: same origin as the
// Next app, no side-car port (the `/_next/mcp` shape).
const meta = await (await fetch(`${ORIGIN}/__devframes/__connection.json`)).json() as {
mcp?: { path: string, port?: number }
@@ -29,13 +29,13 @@ test.describe('devframe connect (next-devframe-hub)', () => {
expect(meta.mcp).toEqual({ path: '__mcp' })
await withConnectClient(REGISTRY, async (client) => {
- // Index: the hub registered itself (explicitly — it runs in-process,
+ // Index: the hub registered itself (explicitly, since it runs in-process,
// not via createDevServer) with the Next server's own origin.
const index = parseToolText(await client.callTool({ name: 'devframe_connect_list-instances', arguments: {} }))
const hub = index.instances.find((entry: any) => entry.id === 'example:next-devframe-hub')
expect(hub).toBeDefined()
// The probe may adopt an explicit address family for the recorded
- // `localhost` origin — accept either spelling.
+ // `localhost` origin, so accept either spelling.
expect(hub.mcp.url).toMatch(/^http:\/\/(?:localhost|127\.0\.0\.1):9878\/__devframes\/__mcp$/)
// The hub's agent surface flows through: the agent-flagged hub command,
diff --git a/tests/e2e/next-runtime-snapshot-dev.spec.ts b/tests/e2e/next-runtime-snapshot-dev.spec.ts
index a9eb11168..43f2e2d87 100644
--- a/tests/e2e/next-runtime-snapshot-dev.spec.ts
+++ b/tests/e2e/next-runtime-snapshot-dev.spec.ts
@@ -23,7 +23,7 @@ test.describe('next-runtime-snapshot (dev)', () => {
expect(initialRss).toMatch(/\d+(?:\.\d+)?\s*MB/)
await memCard.locator('button:has-text("Refresh")').click()
- // After refresh the uptime row should still render — the call resolved.
+ // After refresh the uptime row should still render, since the call resolved.
await expect(memCard.locator('span.color-muted').first()).toHaveText('uptime')
})
diff --git a/tests/e2e/next-runtime-snapshot-static.spec.ts b/tests/e2e/next-runtime-snapshot-static.spec.ts
index ed04460c9..6357c8b9d 100644
--- a/tests/e2e/next-runtime-snapshot-static.spec.ts
+++ b/tests/e2e/next-runtime-snapshot-static.spec.ts
@@ -5,7 +5,7 @@ const BASE = 'http://127.0.0.1:9889/'
// Static dumps only carry pre-computed `static` (and `query{snapshot:true}`)
// RPC results. The example's `system` function is `static` so it bakes
// into the dump; `memory` and `env` are live `query`s with no `snapshot`,
-// so they don't render anything in static mode — the cards stay in their
+// so they don't render anything in static mode; the cards stay in their
// "Loading…" placeholder.
test.describe('next-runtime-snapshot (static build)', () => {
diff --git a/tests/e2e/streaming-chat-dev.spec.ts b/tests/e2e/streaming-chat-dev.spec.ts
index 9c795d734..4fefde06f 100644
--- a/tests/e2e/streaming-chat-dev.spec.ts
+++ b/tests/e2e/streaming-chat-dev.spec.ts
@@ -3,7 +3,7 @@ import { expect, test } from '@playwright/test'
const BASE = 'http://localhost:9897/__devframe-streaming-chat/'
// Shared server-side history means parallel browsers see each other's
-// messages — pin the suite to serial so each test starts from a clean
+// messages, so pin the suite to serial so each test starts from a clean
// `clear()` and exits with its stream settled.
test.describe.configure({ mode: 'serial' })
diff --git a/tests/e2e/streaming-chat-static.spec.ts b/tests/e2e/streaming-chat-static.spec.ts
index cae72be16..6e0bc2152 100644
--- a/tests/e2e/streaming-chat-static.spec.ts
+++ b/tests/e2e/streaming-chat-static.spec.ts
@@ -4,7 +4,7 @@ const BASE = 'http://127.0.0.1:9898/'
// Static dumps only carry pre-computed `static` / `query{snapshot:true}`
// RPC results. streaming-chat's `send` and `clear` are `action` functions
-// so they never run from a static build — these specs cover what *does*
+// so they never run from a static build; these specs cover what *does*
// render: the demo-prompts list (static RPC) and the connection meta.
test.describe('streaming-chat (static build)', () => {
diff --git a/tests/helpers/serve-test-context.ts b/tests/helpers/serve-test-context.ts
index 4411ff09e..931bde5d3 100644
--- a/tests/helpers/serve-test-context.ts
+++ b/tests/helpers/serve-test-context.ts
@@ -9,7 +9,7 @@ import { getInternalContext } from 'devframe/node/hub-internals'
import { attachWsRpcTransport } from 'devframe/rpc/transports/ws-server'
import { H3 as H3App, toNodeHandler } from 'h3'
-/** Loopback / wildcard binds aren't dialable as-is — advertise `localhost`. */
+/** Loopback / wildcard binds aren't dialable as-is, so advertise `localhost`. */
function formatHostForUrl(host: string): string {
const dialable = ['0.0.0.0', '127.0.0.1', '::', ''].includes(host) ? 'localhost' : host
return isIP(dialable) === 6 ? `[${dialable}]` : dialable
@@ -32,7 +32,7 @@ export interface ServeTestContextOptions {
/**
* Stand up a real HTTP + WebSocket RPC server for a hand-built devframe
- * context — the in-process test counterpart to the binding `initDevframe` /
+ * context, the in-process test counterpart to the binding `initDevframe` /
* `initHub` perform internally. Test harnesses that need a live origin,
* direct `ctx` access, an injected fake host, or a custom `cwd` build their
* context by hand and serve it through this helper; production code reaches
@@ -43,9 +43,6 @@ export async function serveTestContext(options: ServeTestContextOptions): Promis
const bindHost = options.host ?? 'localhost'
const app = options.app ?? new H3App()
const httpServer = createServer(toNodeHandler(app))
- const rpcHost = context.rpc as unknown as {
- definitions: Map
- }
const { rpcGroup, onConnected, onDisconnected } = createContextRpcServer({
context,
@@ -80,7 +77,7 @@ export async function serveTestContext(options: ServeTestContextOptions): Promis
function connectionMeta(): ConnectionMeta {
const jsonSerializableMethods: string[] = []
- for (const def of rpcHost.definitions.values()) {
+ for (const def of context.rpc.definitions.values()) {
if (def.jsonSerializable === true)
jsonSerializableMethods.push(def.name)
}
diff --git a/tests/optional-mcp-bundles.test.ts b/tests/optional-mcp-bundles.test.ts
index e2a9c1ce5..37b21458b 100644
--- a/tests/optional-mcp-bundles.test.ts
+++ b/tests/optional-mcp-bundles.test.ts
@@ -92,7 +92,7 @@ describe('optional MCP peers in consumer bundles', () => {
}))
// A 2025-era `initialize` is served statelessly through the SDK's
- // default legacy path — answered per request with no `Mcp-Session-Id`.
+ // default legacy path, answered per request with no `Mcp-Session-Id`.
expect(response.status).toBe(200)
expect(response.headers.get('mcp-session-id')).toBeNull()
await response.body?.cancel()