Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions devframe/docs/.vitepress/sidebar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ export default function devframeSidebar(prefix = ''): DefaultTheme.SidebarItem[]
{ text: 'Dock System', link: `${prefix}/guide/dock-system` },
{ text: 'Commands', link: `${prefix}/guide/commands` },
{ text: 'When Clauses', link: `${prefix}/guide/when-clauses` },
{ text: 'Logs & Notifications', link: `${prefix}/guide/logs` },
{ text: 'Messages & Notifications', link: `${prefix}/guide/messages` },
{ text: 'Structured Diagnostics', link: `${prefix}/guide/diagnostics` },
{ text: 'Terminals', link: `${prefix}/guide/terminals` },
{ text: 'Client', link: `${prefix}/guide/client` },
{ text: 'Standalone CLI', link: `${prefix}/guide/standalone-cli` },
Expand All @@ -25,7 +26,7 @@ export default function devframeSidebar(prefix = ''): DefaultTheme.SidebarItem[]
text: 'Error Reference',
link: `${prefix}/errors/`,
collapsed: true,
items: Array.from({ length: 17 }, (_, i) => {
items: Array.from({ length: 18 }, (_, i) => {
const code = `DF${String(i + 1).padStart(4, '0')}`
return { text: code, link: `${prefix}/errors/${code}` }
}),
Expand Down
52 changes: 52 additions & 0 deletions devframe/docs/errors/DF0018.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
---
outline: deep
---

# DF0018: `ctx.logs` Deprecated

> Package: `devframe`

## Message

> `` `ctx.logs` is deprecated and will be removed in a future release. Use `ctx.messages` instead. ``

## Cause

The user-facing message subsystem has been renamed from `logs` to `messages` to disambiguate it from the structured diagnostics surface (`ctx.diagnostics`, powered by [`logs-sdk`](https://github.com/vercel-labs/logs-sdk)).

`ctx.logs` continues to work as an alias of `ctx.messages` for one release cycle, but emits this warning the first time it is accessed in a given process.

## Example

Code that triggers it:

```ts
ctx.logs.add({ message: 'something happened', level: 'info' })
```

## Fix

Replace `ctx.logs` with `ctx.messages`:

```ts
ctx.messages.add({ message: 'something happened', level: 'info' })
```

The runtime behavior is identical — the same host instance backs both fields.

The associated type names have been renamed too (with deprecated aliases kept for one release):

| Old | New |
|-----|-----|
| `DevToolsLogsHost` | `DevToolsMessagesHost` |
| `DevToolsLogsClient` | `DevToolsMessagesClient` |
| `DevToolsLogEntry` | `DevToolsMessageEntry` |
| `DevToolsLogEntryInput` | `DevToolsMessageEntryInput` |
| `DevToolsLogHandle` | `DevToolsMessageHandle` |
| `DevToolsLogLevel` | `DevToolsMessageLevel` |

The event names emitted by the host have changed from `log:added` / `log:updated` / `log:removed` / `log:cleared` to `message:added` / `message:updated` / `message:removed` / `message:cleared`.

## Source

`packages/devframe/src/node/context.ts`
1 change: 1 addition & 0 deletions devframe/docs/errors/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,4 @@ Emitted by `devframe` — framework-neutral host / shared-state / auth surface.
| [DF0015](./DF0015) | error | Agent Tool Already Registered | — |
| [DF0016](./DF0016) | error | Agent Resource Already Registered | — |
| [DF0017](./DF0017) | error | MCP Server Start Failure | — |
| [DF0018](./DF0018) | warn | `ctx.logs` Deprecated | — |
6 changes: 4 additions & 2 deletions devframe/docs/guide/devtool-definition.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ interface DevToolsNodeContext {
docks: DevToolsDockHost // dock entries
views: DevToolsViewHost // static file hosting
terminals: DevToolsTerminalHost
logs: DevToolsLogsHost
messages: DevToolsMessagesHost
diagnostics: DevToolsDiagnosticsHost
commands: DevToolsCommandsHost
agent: DevToolsAgentHost // experimental

Expand All @@ -92,7 +93,8 @@ Each host has a dedicated page:
- [Shared State](./shared-state) — `ctx.rpc.sharedState`
- [Dock System](./dock-system) — `ctx.docks`, `ctx.views`
- [Commands](./commands) — `ctx.commands`
- [Logs](./logs) — `ctx.logs`
- [Messages](./messages) — `ctx.messages`
- [Diagnostics](./diagnostics) — `ctx.diagnostics`
- [Terminals](./terminals) — `ctx.terminals`
- [Agent-Native](./agent-native) — `ctx.agent`

Expand Down
162 changes: 162 additions & 0 deletions devframe/docs/guide/diagnostics.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
---
outline: deep
---

# Structured Diagnostics

`ctx.diagnostics` is a thin layer over [`logs-sdk`](https://github.com/vercel-labs/logs-sdk) that lets integrations register their own coded errors and warnings into a shared logger — without taking a direct dependency on `logs-sdk`.

Use it for *author-defined coded diagnostics* (errors, warnings, deprecations) that have a stable code, a documentation URL, and a structured payload. For free-form runtime output that should appear in the DevTools UI, use [`ctx.messages`](./messages) instead.

| Surface | Purpose | Example |
|---------|---------|---------|
| `ctx.diagnostics` | Coded errors and warnings emitted from node-side plugin code | `MYP0001: Plugin foo not configured` |
| [`ctx.messages`](./messages) | Free-form, user-facing notifications shown in the Messages panel | `'Audit complete — 3 issues found'` |

## Shape

```ts
interface DevToolsDiagnosticsHost {
/** Combined logs-sdk Logger across all registered diagnostics. */
readonly logger: Logger

/** Register additional diagnostic definitions. */
register: (definitions: DiagnosticsResult) => void

/** Re-export of logs-sdk's `defineDiagnostics`. */
defineDiagnostics: typeof defineDiagnostics

/** Re-export of logs-sdk's `createLogger`. */
createLogger: typeof createLogger
}
```

The host ships pre-seeded with devframe's own `DF*` codes, plus the host package's codes (`DTK*` for `@vitejs/devtools`, etc.). Call `register()` to add your own.

## Register Your Own Codes

```ts
export function MyPlugin(): PluginWithDevTools {
return {
name: 'my-plugin',
devtools: {
setup(ctx) {
const myDiagnostics = ctx.diagnostics.defineDiagnostics({
docsBase: 'https://example.com/errors',
codes: {
MYP0001: {
message: (p: { name: string }) => `Plugin "${p.name}" is not configured`,
hint: 'Add the plugin to your `vite.config.ts` and pass an options object.',
},
MYP0002: {
message: 'Cache directory missing — running cold.',
level: 'warn',
},
},
})

ctx.diagnostics.register(myDiagnostics)

// Now you can emit codes through the shared logger:
ctx.diagnostics.logger.MYP0002().log()
},
},
}
}
```

## Code Conventions

Use a **4-letter prefix + 4-digit number** for your codes (e.g. `MYP0001`). Pick a prefix that's specific to your plugin or tool — short enough to type, distinctive enough not to collide with other integrations.

Prefixes already in use in this monorepo:

| Prefix | Owner |
|--------|-------|
| `DF` | `devframe` |
| `DTK` | `@vitejs/devtools` (Vite-specific) |
| `RDDT` | `@vitejs/devtools-rolldown` |
| `VDT` | `@vitejs/devtools-vite` (reserved) |

Each definition supports a `message` (string or function), an optional `hint`, an optional `level` (`'error'` / `'warn'` / `'suggestion'` / `'deprecation'` — defaults to `'error'`), and a `docsBase` for generating documentation URLs. See [`logs-sdk`](https://github.com/vercel-labs/logs-sdk) for the full schema.

## Emit a Diagnostic

Each registered code becomes a callable factory on `ctx.diagnostics.logger`. The factory returns an object with `.throw()`, `.warn()`, `.error()`, `.log()`, and `.format()`.

```ts
// Throw — control flow stops here
throw ctx.diagnostics.logger.MYP0001({ name: 'foo' }).throw()

// Log without throwing
ctx.diagnostics.logger.MYP0002().log()

// Override level per call
ctx.diagnostics.logger.MYP0002().warn()

// Attach a `cause`
ctx.diagnostics.logger.MYP0001({ name: 'foo' }, { cause: error }).log()
```

`.throw()` is also typed `never` — TypeScript will treat the line after it as unreachable, so prefix it with `throw` for control-flow narrowing:

```ts
throw ctx.diagnostics.logger.MYP0001({ name }).throw()
```

## Typed Logger Reference

`ctx.diagnostics.logger` is loosely typed (it covers an unbounded set of registered codes). If you want full type narrowing — e.g. autocompletion for your plugin's specific codes — keep your own typed reference returned from `createLogger`:

```ts
const myDiagnostics = ctx.diagnostics.defineDiagnostics({
docsBase: 'https://example.com/errors',
codes: {
MYP0001: { message: (p: { name: string }) => `…${p.name}` },
},
})

// Register so the shared logger can also see it
ctx.diagnostics.register(myDiagnostics)

// Keep a typed reference for your own emit sites
const logger = ctx.diagnostics.createLogger({ diagnostics: [myDiagnostics] })
logger.MYP0001({ name: 'foo' }).warn()
```

Both loggers share the formatter and reporter defaults set by the host (ANSI console output).

## Updating the Combined Logger

`ctx.diagnostics.logger` is a *getter* — it always returns the freshest combined logger, rebuilt each time `register()` is called. Don't cache it:

```ts
// ❌ Stale after a later register() call
const log = ctx.diagnostics.logger
log.MYP0001({ name: 'foo' }).log()

// ✅ Always fresh
ctx.diagnostics.logger.MYP0001({ name: 'foo' }).log()
```

If you want a stable reference, use `ctx.diagnostics.createLogger({ diagnostics: [myDiagnostics] })` — that one stays bound to *your* definitions.

## Document Your Codes

Pair each code with a documentation page. devframe and the published Vite DevTools packages follow this layout:

```
docs/errors/
index.md # Table of all codes
MYP0001.md # One page per code
MYP0002.md
```

Each page covers the message, cause, example, and fix — see any [DF code page](https://devtools.vite.dev/devframe/errors/) for the canonical template. Set `docsBase` on `defineDiagnostics({...})` so the URL is auto-attached to every emitted diagnostic.

## When to Use What

- **`ctx.diagnostics`** — Coded conditions you want users (or other tools) to be able to look up: misconfiguration, deprecations, validation failures, internal invariants. Always have a docs page. Often `.throw()`.
- **`ctx.messages`** — User-facing activity surfaces in the DevTools UI: progress indicators, audit results, "URL copied" toasts. No code, no docs URL — just a message and a level.

The two systems are intentionally separate: diagnostics are for tool authors and CI; messages are for the human in front of the DevTools panel.
48 changes: 25 additions & 23 deletions devframe/docs/guide/logs.md → devframe/docs/guide/messages.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@
outline: deep
---

# Logs & Notifications
# Messages & Notifications

`ctx.logs` is a structured log store with live updates, toasts, and positional hints that link a log entry back to a DOM element or source file. Use it to surface a11y findings, lint errors, runtime failures, or short-lived notifications like "URL copied".
`ctx.messages` is a structured message store with live updates, toasts, and positional hints that link a message entry back to a DOM element or source file. Use it to surface a11y findings, lint errors, runtime failures, or short-lived notifications like "URL copied".

The same API works from the server and the browser: each call is a Promise, but most callers fire-and-forget.

> **Note:** Previously named `ctx.logs`. The old field still works as a deprecated alias for one release cycle — see [DF0018](/errors/DF0018) for migration details.

## Entry Fields

| Field | Type | Required | Description |
Expand All @@ -31,7 +33,7 @@ The same API works from the server and the browser: each call is a Promise, but
## Fire-and-Forget

```ts
ctx.logs.add({
ctx.messages.add({
message: 'Plugin initialized',
level: 'info',
})
Expand All @@ -42,7 +44,7 @@ ctx.logs.add({
`await` the call to get a handle for live updates:

```ts
const handle = await ctx.logs.add({
const handle = await ctx.messages.add({
id: 'my-devtool:build',
message: 'Building…',
level: 'info',
Expand All @@ -63,27 +65,27 @@ Re-adding with the same `id` updates the existing entry — use this to replace

## Toasts

Set `notify: true` to also render the log as a toast:
Set `notify: true` to also render the message as a toast:

```ts
ctx.logs.add({
ctx.messages.add({
message: 'URL copied to clipboard',
level: 'success',
notify: true,
autoDismiss: 3000,
})
```

`autoDismiss` controls how long the toast stays on screen; the log entry persists in the panel until explicitly removed or `autoDelete` fires.
`autoDismiss` controls how long the toast stays on screen; the message entry persists in the panel until explicitly removed or `autoDelete` fires.

## Positional Hints

### File Position

Linking a log to a source file makes it clickable — clicking opens the file in the user's editor:
Linking a message to a source file makes it clickable — clicking opens the file in the user's editor:

```ts
ctx.logs.add({
ctx.messages.add({
message: 'Unused import',
level: 'warn',
category: 'lint',
Expand All @@ -93,11 +95,11 @@ ctx.logs.add({

### Element Position

DOM anchors are rendered as a highlight overlay when the user hovers the log entry:
DOM anchors are rendered as a highlight overlay when the user hovers the message entry:

```ts
// Typically from a browser-side audit:
ctx.logs.add({
ctx.messages.add({
message: 'Button missing accessible name',
level: 'warn',
category: 'a11y',
Expand All @@ -115,7 +117,7 @@ ctx.logs.add({

```ts
async function rebuild(ctx) {
const handle = await ctx.logs.add({
const handle = await ctx.messages.add({
id: 'my-devtool:rebuild',
message: 'Rebuilding…',
level: 'info',
Expand All @@ -141,7 +143,7 @@ async function rebuild(ctx) {
### Category filter

```ts
ctx.logs.events.on('log:added', (entry) => {
ctx.messages.events.on('message:added', (entry) => {
if (entry.category === 'a11y') {
console.log('a11y finding:', entry.message)
}
Expand All @@ -151,26 +153,26 @@ ctx.logs.events.on('log:added', (entry) => {
## Removing Entries

```ts
await ctx.logs.remove('my-devtool:build')
await ctx.logs.clear() // all entries
await ctx.messages.remove('my-devtool:build')
await ctx.messages.clear() // all entries
```

## Events

The host emits events for anyone who wants to observe the log stream:
The host emits events for anyone who wants to observe the message stream:

```ts
ctx.logs.events.on('log:added', (entry) => { /* … */ })
ctx.logs.events.on('log:updated', (entry) => { /* … */ })
ctx.logs.events.on('log:removed', (id) => { /* … */ })
ctx.logs.events.on('log:cleared', () => { /* … */ })
ctx.messages.events.on('message:added', (entry) => { /* … */ })
ctx.messages.events.on('message:updated', (entry) => { /* … */ })
ctx.messages.events.on('message:removed', (id) => { /* … */ })
ctx.messages.events.on('message:cleared', () => { /* … */ })
```

Use this to bridge logs into external tools — e.g. mirror them into a structured log file or forward certain categories to your own reporter.
Use this to bridge messages into external tools — e.g. mirror them into a structured log file or forward certain categories to your own reporter.

## Server vs Browser

Both sides share the same API. Browser-side calls go through the RPC client (`rpc.logs` or — more idiomatically — the exported `DevToolsLogsClient` interface). Entries carry a `from` field so the UI can distinguish server-originated logs from browser-originated ones.
Both sides share the same API. Browser-side calls go through the RPC client (— more idiomatically — the exported `DevToolsMessagesClient` interface). Entries carry a `from` field so the UI can distinguish server-originated messages from browser-originated ones.

> [!NOTE]
> The separate, Node-side [structured diagnostics system](https://github.com/vercel-labs/logs-sdk) used for DevFrame's own warnings / errors (`DF`-prefixed codes) is distinct from `ctx.logs`. Diagnostics are author-defined coded errors with documentation URLs; `ctx.logs` is free-form plugin output shown in the Logs panel.
> The separate, Node-side structured diagnostics system used for DevFrame's own warnings / errors (`DF`-prefixed codes) is distinct from `ctx.messages`. See the [Diagnostics guide](./diagnostics) for `ctx.diagnostics`, the host-level wrapper around [`logs-sdk`](https://github.com/vercel-labs/logs-sdk).
Loading
Loading