diff --git a/plans/vite-devtools-integration/00-compat-foundation.md b/plans/vite-devtools-integration/00-compat-foundation.md deleted file mode 100644 index 6955f08047..0000000000 --- a/plans/vite-devtools-integration/00-compat-foundation.md +++ /dev/null @@ -1,209 +0,0 @@ -# Plan 00 — Compatibility & deprecation foundation - -**Status:** ready to execute · **Risk:** medium · **Depends on:** nothing · -**Foundation for:** plans 01, 02, 03 build on the surfaces this plan creates. -**Outcome:** Nuxt DevTools keeps its existing public API working, **exposes the -devframe-native API alongside it** (connect-safe), and gains a **nostics-driven -soft-deprecation** system so migrations are minimal and self-discoverable. This -is the base layer for the long-term move to devframe-native APIs. - -> Self-contained: read this whole file. Shared API facts are repeated here. - -## Why this exists - -We're cutting a **new major** of Nuxt DevTools on top of Vite DevTools 0.4 / -devframe 0.6 (migration already merged, nuxt/devtools#1010). Breaking changes -are acceptable, but the migration for module authors/users must be **minimal** -and **self-discoverable**. Strategy: - -1. **Keep** the existing Nuxt DevTools API working. -2. **Expose** the devframe-native API (docks/terminals/messages/commands/ - diagnostics) so authors can start using it directly. -3. **Soft-deprecate** the Nuxt API where a devframe equivalent exists, via a - backward-compatible **shim** + a **nostics** deprecation diagnostic (code + - fix + doc link). Hard-break only where a faithful shim is infeasible. -4. Long term: gradually retire the shimmed Nuxt APIs (next major). - -Plans 01 (messages), 02 (terminals), 03 (dock groups) each *apply* this -foundation to their specific APIs. This plan builds the **mechanism** + policy + -a couple of pilot deprecations. - -## Context you need - -### The devframe-native context (target surface) - -`nuxt.devtools.devtoolsKit` is a `ViteDevToolsNodeContext` (= devframe -`DevframeNodeContext`) exposing `docks`, `terminals`, `messages`, `commands`, -and **`diagnostics`** (a `DevframeDiagnosticsHost`). It is assigned in -`packages/devtools/src/server-rpc/index.ts` (`connectDevToolsKit(ctx)`), and is -**`undefined` until the Vite DevTools plugin connects** — typed -`devtoolsKit: DevToolsNodeContext | undefined` in -`packages/devtools-kit/src/_types/server-ctx.ts`. `server-rpc/index.ts` already -demonstrates the **pre-connect queue** pattern (`pendingBroadcasts`, flushed in -`connectDevToolsKit`). - -### The current Nuxt DevTools public API surface (what modules use) - -- **Server context** `nuxt.devtools` (`NuxtDevtoolsServerContext`, - `packages/devtools-kit/src/_types/server-ctx.ts`): `rpc` (`rpc.broadcast`, - `rpc.functions`), `extendServerRpc(name, fns)`, `refresh(event)`, - `openInEditorHooks`, `devtoolsKit`. -- **`@nuxt/devtools-kit` root exports** (`packages/devtools-kit/src/index.ts`): - `addCustomTab`, `refreshCustomTabs`, `startSubprocess`, `extendServerRpc`, - `onDevToolsInitialized`. -- **Client kit subpaths**: `@nuxt/devtools-kit/iframe-client` - (`onDevtoolsClientConnected`, `useDevtoolsClient`), `@nuxt/devtools-kit/host-client` - (`onDevtoolsHostClientConnected`, `useDevtoolsHostClient`). `NuxtDevtoolsClient` - (`_types/client-api.ts`) with `rpc`, `extendClientRpc`, `renderMarkdown`, - `renderCodeHighlight`, `colorMode`. -- **Nuxt hooks** (`packages/devtools-kit/src/_types/hooks.ts`): `devtools:before`, - `devtools:initialized`, `devtools:customTabs`, `devtools:customTabs:refresh`, - `devtools:terminal:register|write|remove|exit`, runtime `devtools:terminal:data`. -- **Custom tabs**: `ModuleCustomTab` (`_types/custom-tabs.ts`) with iframe/launch/ - vnode views; `ModuleOptions.customTabs`. -- **Subprocess**: `startSubprocess(execaOptions, tabOptions, nuxt?)` - (`src/index.ts`), returns `{ getProcess (deprecated), getResult, terminate, - restart, clear }`. - -### nostics (diagnostics library) — the deprecation engine - -`nostics@1.1.4` (dep of devframe & devtools-kit). Two ways to use it: - -- **Standalone catalog** (works pre-connect, prints to terminal): - ```ts - import { createConsoleReporter, defineDiagnostics } from 'nostics' - const diagnostics = defineDiagnostics({ - docsBase: (code) => `https://devtools.nuxt.com/e/${String(code).toLowerCase()}`, // confirm canonical URL - reporters: [createConsoleReporter()], // default method: 'warn' - codes: { - NDT_DEP_0001: { - why: (p) => `\`${p.api}\` is deprecated.`, - fix: (p) => `Use \`${p.replacement}\` instead.`, - }, - }, - }) - diagnostics.NDT_DEP_0001({ api: 'x', replacement: 'y' }) // warns, returns a throwable Diagnostic - throw diagnostics.NDT_DEP_0001({ api: 'x', replacement: 'y' }) // hard-break variant (error path) - diagnostics.NDT_DEP_0001({ ... }, { method: 'error' }) // per-call severity override - ``` - - Definition shape: `{ why: string|((p)=>string), fix?: string|((p)=>string), docs?: string|false }`. **No `level`** field — severity is chosen per call via the reporter `method`. -- **Register into the DevTools host** (so deprecations also surface *inside* - DevTools) after connect, via `nuxt.devtools.devtoolsKit.diagnostics`: - ```ts - const cat = ctx.diagnostics.defineDiagnostics({ docsBase, codes }) // host supplies its ANSI reporter - ctx.diagnostics.register(cat) - // later: throw ctx.diagnostics.logger.NDT_DEP_0001({...}) / cat.NDT_DEP_0001({...}) - ``` - `DevframeDiagnosticsHost` = `{ logger, register(defs), defineDiagnostics(opts) }`. - -Existing ad-hoc deprecation warnings to fold into this: the `startSubprocess` -`getProcess()` `console.warn` (`packages/devtools-kit/src/index.ts` ~line 126) -and the `logger.warn` in `packages/devtools/src/server-rpc/index.ts` (the -`disableAuthorization` notice, ~lines 165‑168), and the `disableAuthorization` -warning in `module-main.ts`. - -## Decisions (locked) - -1. **Expose devframe-native API as first-class connect-safe hosts** on - `nuxt.devtools`: `nuxt.devtools.docks`, `.terminals`, `.messages`, - `.commands`, `.diagnostics` — proxies that resolve to `devtoolsKit.*` once - connected and **queue pre-connect calls** (mirroring `pendingBroadcasts`). - Keep the raw `devtoolsKit` as an escape hatch. -2. **Self-discoverable deprecations** via a Nuxt nostics catalog - (`defineDiagnostics` with `createConsoleReporter()` + `docsBase` → Nuxt docs), - **also registered into the DevTools host diagnostics after connect** so they - appear in DevTools too. Warn-only by default; each code carries `why` + `fix` - + doc link. -3. **Shim-first** compatibility: every existing API keeps working this major via - shims forwarding to devframe; deprecations are warn-only; removal deferred to - the next major. **Hard-break only where a faithful shim is infeasible** — - those emit an **error-level** diagnostic naming the exact replacement. - -## Implementation - -### Step 1 — connect-safe devframe host accessors on `nuxt.devtools` - -In `packages/devtools/src/server-rpc/index.ts` (`setupRPC`) — where the context -and `pendingBroadcasts` queue already live: - -- Add `docks`, `terminals`, `messages`, `commands`, `diagnostics` to the - `NuxtDevtoolsServerContext` (extend the type in - `packages/devtools-kit/src/_types/server-ctx.ts`). -- Implement each as a small proxy/wrapper: when `devtoolsKitCtx` is set, forward - to `devtoolsKitCtx.`; when not, either (a) buffer mutating calls - (register/add/start…) into a queue flushed in `connectDevToolsKit`, or (b) - return a thenable/guarded stub. Prefer buffering for the register/add/start - methods and reads returning empty until connected. -- Keep `devtoolsKit` getter as the raw escape hatch. -- Document these as the **forward path** in `docs/`. - -### Step 2 — the Nuxt deprecation diagnostics catalog - -- Add a module, e.g. `packages/devtools-kit/src/diagnostics.ts` (exported so both - the kit and the app can emit), that builds the standalone catalog with - `defineDiagnostics({ docsBase, reporters:[createConsoleReporter()], codes })`. - Reserve a code range/prefix: `NDT_DEP_xxxx` for deprecations (and maybe - `NDT_xxxx` for other diagnostics later). -- Provide a tiny `deprecate(code, params, opts?)` helper wrapping the handle call - (default warn; `opts.method:'error'` for hard-breaks). -- After connect (in `connectDevToolsKit`), also `ctx.diagnostics.register(cat)` - (or re-define via `ctx.diagnostics.defineDiagnostics` and register) so codes - are known to DevTools and post-connect emissions surface in the DevTools - diagnostics UI. Guard for `diagnostics` host availability. -- Confirm the canonical docs URL scheme with maintainers (e.g. - `https://devtools.nuxt.com/e/` or a migration guide anchor); wire it into - `docsBase`. - -### Step 3 — shim pattern + deprecation classification map - -Establish the pattern (used by plans 01/02/03): keep the old API; internally -forward to the devframe host; emit the deprecation diagnostic once per unique -call site (dedupe by code+key to avoid noise). Ship this **classification map** -(implemented incrementally by the owning plans): - -| Nuxt API | devframe-native path | Policy | Owner | -|---|---|---|---| -| `devtoolsUiShowNotification` | `messages` host (`add`/`info`/…) | shim + deprecate | Plan 01 | -| `startSubprocess`, `devtools:terminal:*` hooks | `terminals` host (`register`/`startChildProcess`/`startPtySession`) | shim + deprecate | Plan 02 | -| `startSubprocess().getProcess()` | `getResult()` | already deprecated → move to nostics code | Plan 00 (pilot) | -| `addCustomTab` / `devtools:customTabs` / `ModuleCustomTab` | stays (Nuxt-native); gains `dock:true` → `docks` | **keep** (extend, not deprecate) | Plan 03 | -| `extendServerRpc`, `rpc.broadcast`, `rpc.functions` | `ctx.rpc` (`register`/`defineRpcFunction`/`broadcast`) | keep + expose; low-urgency soft-deprecate later | Plan 00 exposes; future | -| client `extendClientRpc`, `useDevtoolsClient`, `onDevtoolsClientConnected` | devframe client RPC | keep + shim | future | -| `onDevToolsInitialized`, `devtools:before/initialized` | Nuxt lifecycle | **keep** (no devframe equivalent) | — | -| `disableAuthorization` option | handled by Vite DevTools auth | already warned → move to nostics code (**breaking**, error-level) | Plan 00 (pilot) | - -### Step 4 — pilot deprecations (prove the mechanism) - -- Replace the `getProcess()` `console.warn` (`devtools-kit/src/index.ts`) with a - `NDT_DEP_xxxx` warn diagnostic. -- Replace the `disableAuthorization` `logger.warn` (`server-rpc/index.ts` / - `module-main.ts`) with a diagnostic (error-level — it no longer does anything). -- These validate both reporting paths (pre-connect console + post-connect host). - -## Acceptance criteria - -- `nuxt.devtools.terminals` / `.messages` / `.docks` / `.commands` / - `.diagnostics` are usable from a module's setup (calls made before the kit - connects are queued and applied after connect; no crashes when `devtoolsKit` - is still undefined). -- Using a deprecated API prints a terminal warning with a **code**, a **fix**, - and a **doc link**, and the same deprecation is visible inside DevTools' - diagnostics after connect. -- The two pilot deprecations fire correctly (getProcess → warn; disableAuthorization → error). -- `pnpm lint && pnpm build && pnpm typecheck` pass. -- No existing module integration breaks solely due to this plan (shims in place; - plans 01/02/03 attach their specific shims). - -## Risks / gotchas - -- **Connect timing.** The hosts are undefined pre-connect; buffer mutating calls - and flush on `connectDevToolsKit` (reuse the `pendingBroadcasts` pattern). -- **Diagnostic noise.** Dedupe deprecation emissions (once per code+key) so a - hot path doesn't spam the console. -- **Docs URL.** `docsBase` must point at real pages or the "see:" link is dead — - confirm the scheme and create stubs/redirects before shipping. -- **Prod stripping.** nostics supports `defineProdDiagnostics` + a strip plugin; - DevTools is dev-only so this is optional, but keep `why`/`fix` out of any - shipped runtime if size matters. -- **Don't over-deprecate.** Custom tabs and the Nuxt lifecycle hooks have no - clean devframe equivalent yet — keep them; only deprecate where the map says so. diff --git a/plans/vite-devtools-integration/01-messages-unification.md b/plans/vite-devtools-integration/01-messages-unification.md index 40bc7ab26a..b3c0aa0d2b 100644 --- a/plans/vite-devtools-integration/01-messages-unification.md +++ b/plans/vite-devtools-integration/01-messages-unification.md @@ -1,6 +1,7 @@ # Plan 01 — Unify notifications on the devframe Messages system -**Status:** ready to execute · **Risk:** low · **Depends on:** nothing +**Status:** ready to execute · **Risk:** low · **Depends on:** the landed +compat/deprecation foundation (nuxt/devtools#1021, #1023 — see the folder README) **Outcome:** one notification system across Nuxt DevTools — ephemeral toasts and persistent, leveled notifications both flow through devframe's Messages subsystem, surfaced by Vite DevTools' built-in **Messages** dock and its toast @@ -10,15 +11,24 @@ to a thin adapter). > Self-contained: read this whole file; you don't need other plans. Shared API > facts are repeated here. -## Relationship to Plan 00 (foundation) - -If Plan 00 (compat foundation) has landed, prefer its **connect-safe** -`nuxt.devtools.messages` host over reaching into `nuxt.devtools.devtoolsKit.messages` -directly (it queues pre-connect calls for you), and emit the toast -soft-deprecation through Plan 00's **nostics** catalog (a `NDT_DEP_xxxx` code -with `fix` + doc link) rather than an ad-hoc `console.warn`. If Plan 00 is not -yet in place, use `devtoolsKit.messages` guarded for the undefined-until-connect -window (queue + flush like `server-rpc/index.ts`'s `pendingBroadcasts`). +## Relationship to the landed foundation + +The compat/deprecation foundation has **already shipped** (nuxt/devtools#1021 +server-side, #1023 client-side). Build on it — do not rebuild it: + +- **Reach `ctx.messages` via the ready hooks**, which hand you the *already + connected* context — there is no pre-connect window to guard and **no queue to + manage**: + - Server: `onDevtoolsReady((ctx) => ctx.messages.…)` from `@nuxt/devtools-kit` + (raw escape hatch: `nuxt.devtools.devtoolsKit?.messages`). + - Client: `onDevtoolsReady((kit) => …)` from `@nuxt/devtools-kit/iframe-client`, + or `client.devtools.devtoolsKit` — the connected `DevToolsRpcClient`, so you + can call the messages RPC without importing `@vitejs/devtools-kit/client`. +- **Emit the toast soft-deprecation through the nostics catalog** + (`deprecate(nuxt, code, params)` from `packages/devtools-kit/src/diagnostics.ts`) + with the **next free** `NDT_DEP_xxxx` code (don't reuse `0002`) rather than an + ad-hoc `console.warn`; add the code to `diagnosticCodes` and give it a + migration-guide anchor. ## Context you need @@ -51,10 +61,12 @@ today. ### devframe Messages API (target) **Node side** — `ctx.messages` (a `DevframeMessagesHost`) where `ctx` is the -`ViteDevToolsNodeContext` available in `module-main.ts`'s -`devtools.setup(ctx)` and stored as `devtoolsKit` on the Nuxt server context -(see `packages/devtools/src/server-rpc/index.ts` → `connectDevToolsKit`, and the -`devtoolsKit` field typed in `packages/devtools-kit/src/_types/server-ctx.ts`): +connected `ViteDevToolsNodeContext` handed to you by +`onDevtoolsReady((ctx) => …)` (from `@nuxt/devtools-kit`). It is also stored as +`devtoolsKit` on the Nuxt server context (see +`packages/devtools/src/server-rpc/index.ts` → `connectDevToolsKit`, which fires +the `devtools:ready` hook, and the `devtoolsKit` field typed in +`packages/devtools-kit/src/_types/server-ctx.ts`): ```ts ctx.messages.add({ message, level, description?, notify?, autoDismiss?, autoDelete?, labels?, category?, filePosition?, stacktrace? }) @@ -68,18 +80,22 @@ Key entry fields: - `autoDismiss`: toast auto-hides. - `autoDelete`: entry is not kept in the persistent list (toast-only). -**Client side** — the Nuxt DevTools client already holds a devframe RPC client -(`packages/devtools/client/composables/rpc.ts` → `rpcClient` / -`getDevToolsRpcClient()`, and the `rpc` proxy that does `client.call(method, …)`). -Messages can be added from the client by calling the messages RPC method -(`devframes-plugin-messages:add`) — the client is trusted and the method is -registered by the plugin. Confirm the exact method name at build time by -inspecting `node_modules/.pnpm/@devframes+plugin-messages@0.6.0*/…/dist/rpc` +**Client side** — since nuxt/devtools#1023 the client exposes the connected +devframe client directly: `client.devtools.devtoolsKit` is the connected +`DevToolsRpcClient`, and `onDevtoolsReady((kit) => …)` from +`@nuxt/devtools-kit/iframe-client` hands you that same `kit`. Use it to add +messages from the client (`kit.client.call('', …)`) rather than +hand-rolling `getDevToolsRpcClient()`. + +Confirm the exact messages RPC method at build time by inspecting +`node_modules/.pnpm/@devframes+plugin-messages@0.6.0*/…/dist/rpc` (`devframes-plugin-messages:list|add|update|remove|clear`). There is also a core kit surface (`devtoolskit:internal:messages:*` / `hub:messages:*`) visible in the connection meta; prefer the plugin method, and fall back to whichever one actually drives the core toast if the plugin one does not (verify with a manual -`rpc.call(...)` in the running playground). +`kit.client.call(...)` in the running playground). The legacy +`packages/devtools/client/composables/rpc.ts` proxy still exists but +`extendClientRpc` is now deprecated in favour of `onDevtoolsReady`. ## Decisions (locked) @@ -99,10 +115,11 @@ actually drives the core toast if the plugin one does not (verify with a manual - In the server RPC layer (`packages/devtools/src/server-rpc/`), add a small module (e.g. `messages.ts`) wired in `server-rpc/index.ts` alongside the other `setup*RPC` calls. It should: - - Expose a helper `notify(input)` that calls `ctx.devtoolsKit?.messages.add(…)` - (guard for `devtoolsKit` being `undefined` before the kit connects — queue - and flush on connect, mirroring how `server-rpc/index.ts` already queues - `pendingBroadcasts` until `connectDevToolsKit` runs). + - Expose a helper `notify(input)` that adds to `ctx.messages`. Get the + connected context from `onDevtoolsReady((ctx) => …)` (capture `ctx.messages` + once ready); no manual queue/flush is needed because the ready hook only + fires post-connect. Buffer any `notify(...)` calls made before `ready` and + replay them in the `onDevtoolsReady` callback if early emission matters. - Register a Nuxt hook **`devtools:notify`** (add it to the hooks type in `packages/devtools-kit/src/_types/hooks.ts`) so modules can push: `nuxt.callHook('devtools:notify', { message, level?, description?, … })`. @@ -131,16 +148,20 @@ intentional, leveled message. - Reimplement `devtoolsUiShowNotification` (in `packages/devtools-ui-kit/src/composables/notification.ts`) so that, instead of - driving the local `NNotification` component, it emits a devframe message via - the client RPC with `notify:true, autoDismiss:true, autoDelete:true` and a - `level` derived from intent (default `info`; allow callers to pass one). + driving the local `NNotification` component, it emits a devframe message with + `notify:true, autoDismiss:true, autoDelete:true` and a `level` derived from + intent (default `info`; allow callers to pass one). Emit the toast + soft-deprecation for `devtoolsUiShowNotification` via `deprecate(...)` (next + free `NDT_DEP_xxxx`) if you keep it as a thin adapter. - The UI kit must not hard-depend on the devtools client RPC. Keep the `devtoolsUiProvideNotificationFn` seam: the **client** provides the concrete - implementation (which calls the devframe RPC) at startup; the UI kit stays a - thin proxy. So: keep `notification.ts` as the proxy, and register the - devframe-backed implementation from the Nuxt DevTools client (e.g. in - `packages/devtools/client/plugins/` or `app.vue` setup) via - `devtoolsUiProvideNotificationFn`. + implementation at startup; the UI kit stays a thin proxy. Register the + devframe-backed implementation from the Nuxt DevTools client via + `devtoolsUiProvideNotificationFn`, using the client-side + `onDevtoolsReady((kit) => …)` (from `@nuxt/devtools-kit/iframe-client`) / + `client.devtools.devtoolsKit` from #1023 to obtain the connected client and + call the messages RPC (e.g. in `packages/devtools/client/plugins/` or + `app.vue` setup). - Map the existing callers' options (`message`, `icon`, `duration`, `position`) onto message fields where they have an equivalent; `position`/`duration` become no-ops or best-effort (the chrome toast owns placement/timing). Audit each @@ -177,9 +198,10 @@ intentional, leveled message. ## Risks / gotchas - **Which RPC method drives the core toast.** Verify empirically in the running - playground (`rpc.call('devframes-plugin-messages:add', …)` vs the - `devtoolskit:internal:messages:*` / `hub:messages:*` methods). Whichever makes - a floating toast appear is the one to use for the ephemeral tier. + playground (`kit.client.call('devframes-plugin-messages:add', …)` vs the + `devtoolskit:internal:messages:*` / `hub:messages:*` methods, with `kit` from + the client `onDevtoolsReady`). Whichever makes a floating toast appear is the + one to use for the ephemeral tier. - **Toast location.** The chrome toast renders in the Vite DevTools host layer, not inside the (possibly promoted, separate) Nuxt iframe where the action happened. This is expected under "unify"; confirm it renders above the panel. diff --git a/plans/vite-devtools-integration/02-terminals-reuse.md b/plans/vite-devtools-integration/02-terminals-reuse.md index a10cc4c255..8832ca33b0 100644 --- a/plans/vite-devtools-integration/02-terminals-reuse.md +++ b/plans/vite-devtools-integration/02-terminals-reuse.md @@ -1,6 +1,7 @@ # Plan 02 — Reuse the built-in devframe Terminals dock -**Status:** ready to execute · **Risk:** medium · **Depends on:** nothing +**Status:** ready to execute · **Risk:** medium · **Depends on:** the landed +compat/deprecation foundation (nuxt/devtools#1021 — see the folder README) **Outcome:** Nuxt DevTools stops shipping its own `@xterm` terminal UI + RPC and instead surfaces terminal sessions through devframe's `ctx.terminals`, so they render in Vite DevTools' built-in **Terminals** dock. Existing modules that use @@ -9,16 +10,31 @@ opt-in interactive **PTY** path is added. > Self-contained: read this whole file; shared API facts are repeated here. -## Relationship to Plan 00 (foundation) +## What already landed (don't redo) -If Plan 00 (compat foundation) has landed, prefer its **connect-safe** -`nuxt.devtools.terminals` host over `nuxt.devtools.devtoolsKit.terminals` -(it queues pre-connect `register`/`start…` calls), and emit the -`devtools:terminal:register` / `startSubprocess` soft-deprecations through Plan -00's **nostics** catalog (`NDT_DEP_xxxx` with `fix` + doc link). The -`getProcess()`→`getResult()` deprecation is already a Plan 00 pilot. If Plan 00 -is not yet in place, use `devtoolsKit.terminals` guarded for the -undefined-until-connect window (queue + flush like `pendingBroadcasts`). +nuxt/devtools#1021 already ships the **deprecation warnings** for this area: + +- `startSubprocess` → `NDT_DEP_0004` (points at + `onDevtoolsReady((ctx) => ctx.terminals.startChildProcess(...))`). +- `startSubprocess().getProcess()` → `getResult()` = `NDT_DEP_0001`. + +But the **shim still routes through the old system** — `startSubprocess` (in +`packages/devtools-kit/src/index.ts`) still fires the `devtools:terminal:*` +hooks, which `packages/devtools/src/server-rpc/terminals.ts` still services with +its own `@xterm`-backed Map + RPC. So the warnings exist, but the underlying +implementation is unchanged. **This plan's job is to swap that implementation to +`ctx.terminals`** while keeping the hooks/deprecations working. Reuse the +existing `NDT_DEP_0004`/`0001` codes; if you add a `devtools:terminal:register` +deprecation, use the **next free** `NDT_DEP_xxxx` (don't reuse `0002`). + +## Relationship to the landed foundation + +Reach `ctx.terminals` via `onDevtoolsReady((ctx) => …)` from +`@nuxt/devtools-kit`, which hands you the *already connected* context — **no +pre-connect window to guard and no queue to manage**. Raw escape hatch: +`nuxt.devtools.devtoolsKit?.terminals`. Emit any new soft-deprecations through +the nostics catalog (`deprecate(...)` in +`packages/devtools-kit/src/diagnostics.ts`). ## Context you need @@ -75,10 +91,11 @@ DevTools; DevTools is a passive viewer" (output-only; no stdin, no resize). ### devframe Terminals API (target) `ctx.terminals` is a `DevframeTerminalsHost` on the `ViteDevToolsNodeContext` -available in `packages/devtools/src/module-main.ts`'s `devtools.setup(ctx)` and -stored as `devtoolsKit` on the Nuxt server context -(`packages/devtools/src/server-rpc/index.ts` → `connectDevToolsKit`; -`packages/devtools-kit/src/_types/server-ctx.ts` `devtoolsKit` field): +handed to you by `onDevtoolsReady((ctx) => …)` (from `@nuxt/devtools-kit`). It is +also stored as `devtoolsKit` on the Nuxt server context +(`packages/devtools/src/server-rpc/index.ts` → `connectDevToolsKit`, which fires +`devtools:ready`; `packages/devtools-kit/src/_types/server-ctx.ts` `devtoolsKit` +field): ```ts interface DevframeTerminalsHost { @@ -119,17 +136,20 @@ Rewrite `packages/devtools/src/server-rpc/terminals.ts` (or replace it with a `terminals-bridge` integration) so that instead of maintaining its own map + RPC it: +- Capture `ctx.terminals` from `onDevtoolsReady((ctx) => …)`. Terminals may be + registered before the kit connects (module setup runs early); since the ready + hook only fires post-connect, buffer any early `register`/`write`/`exit` events + in your own `Map` and replay them into `ctx.terminals` inside the + `onDevtoolsReady` callback. (No `pendingBroadcasts`-style plumbing needed — the + ready hook removes the undefined-until-connect race.) - On `devtools:terminal:register`: create a `ReadableStream` (keep its controller in a `Map`), build a `DevframeTerminalSession` `{ id, title: terminal.name, status: 'running', icon?, stream }`, and call - `devtoolsKit.terminals.register(session)`. Guard for `devtoolsKit` being - `undefined` before the kit connects — queue registrations and flush them in - `connectDevToolsKit` (mirror the existing `pendingBroadcasts` pattern in - `server-rpc/index.ts`). + `ctx.terminals.register(session)`. - On `devtools:terminal:write`: `controller.enqueue(data)` for that id (and keep a rolling buffer if the session's initial `buffer` needs seeding). - On `devtools:terminal:exit`: `controller.close()`, set the session `status` to - `'stopped'`/`'error'` and `devtoolsKit.terminals.update(session)`. + `'stopped'`/`'error'` and `ctx.terminals.update(session)`. - On `devtools:terminal:remove` + `runTerminalAction` semantics: map `restart`/`terminate`/`remove`/`clear` onto the module-provided `onActionRestart`/`onActionTerminate` callbacks (still owned by the module) and @@ -158,8 +178,9 @@ module-facing contracts don't change. ### Step 3 — add an opt-in PTY path - Add a server helper (e.g. on the Nuxt server context / a new - `devtools:terminal:spawn` hook option `{ interactive: true }`) that calls - `devtoolsKit.terminals.startPtySession({ command, args, cwd, env, cols, rows }, { id, title })`. + `devtools:terminal:spawn` hook option `{ interactive: true }`) that, from + within `onDevtoolsReady`, calls + `ctx.terminals.startPtySession({ command, args, cwd, env, cols, rows }, { id, title })`. Interactive sessions get stdin `write` + `resize` handled entirely by the built-in Terminals dock UI (no Nuxt client code needed). - Note PTY uses `zigpty` native bindings with graceful pipe fallback @@ -201,8 +222,9 @@ module-facing contracts don't change. their lifecycle/`onActionRestart`/`onActionTerminate` semantics. - **Don't drop exit-driven cleanup.** `client-rpc.ts` prunes installing-modules / analyze-build state on `devtools:terminal:exit`. Preserve an exit signal path. -- **Timing before kit connect.** Terminals may register before - `connectDevToolsKit` runs; queue + flush (mirror `pendingBroadcasts`). +- **Timing before kit connect.** Terminals may register before the kit connects; + buffer early events in your own `Map` and replay them inside the + `onDevtoolsReady` callback (the ready hook only fires post-connect). - **Read-only session controls.** Registered read-only sessions have no `write`/`resize`; make sure the dock UI doesn't imply interactivity for them (rely on the session's `interactive` flag being falsy). diff --git a/plans/vite-devtools-integration/03-dock-groups-presentation.md b/plans/vite-devtools-integration/03-dock-groups-presentation.md index 1934d79828..9b46499309 100644 --- a/plans/vite-devtools-integration/03-dock-groups-presentation.md +++ b/plans/vite-devtools-integration/03-dock-groups-presentation.md @@ -1,7 +1,8 @@ # Plan 03 — "Nuxt" dock group + promote-tab-to-dock capability **Status:** ready to execute · **Risk:** high (UX/architecture) · -**Depends on:** benefits from plans 01 & 02 landing first (not a hard dep) +**Depends on:** the landed compat/deprecation foundation (nuxt/devtools#1021 — +see the folder README); benefits from plans 01 & 02 landing first (not a hard dep) **Outcome:** Nuxt DevTools presents as a **"Nuxt" dock group** in the Vite DevTools dock bar. The full client stays reachable as the group's hub member, and a curated set of tools is **promoted** to sibling dock buttons under the @@ -10,31 +11,47 @@ group. Promotion is a general, opt-in capability any tab can request. > Self-contained: read this whole file; shared API facts are repeated here. > This is the largest/most opinionated plan — do it after 01 & 02 if possible. -## Relationship to Plan 00 (foundation) - -If Plan 00 (compat foundation) has landed, register the group + promoted entries -through its **connect-safe** `nuxt.devtools.docks` host (queues pre-connect -`register` calls) rather than reaching into `devtoolsKit.docks` directly. The -`dock:true` promotion flag is an **additive extension** of the existing custom -tabs API (`ModuleCustomTab`) — it is **not** a deprecation (per the Plan 00 -classification map, custom tabs stay Nuxt-native). If Plan 00 is not yet in -place, use `devtoolsKit.docks` guarded for the undefined-until-connect window. +## Relationship to the landed foundation + +The foundation shipped in nuxt/devtools#1021. Register the group + promoted +entries on `ctx.docks`: + +- Nuxt DevTools' **own** group/hub registration lives in + `packages/devtools/src/module-main.ts`'s `devtools.setup(ctx)` callback, right + next to the existing `ctx.docks.register({ id: 'nuxt:devtools', … })` (which + today registers a single iframe with `defaultOrder: -2000`). +- For **module authors** promoting their own tabs, use + `onDevtoolsReady((ctx) => ctx.docks.register(...))` — the *already connected* + context, so **no pre-connect queue** is needed. Raw escape hatch: + `nuxt.devtools.devtoolsKit?.docks`. + +**Tension to resolve, not ignore.** `addCustomTab` / `refreshCustomTabs` are now +**soft-deprecated** (`NDT_DEP_0005` / `NDT_DEP_0006`, shipped in #1021) pointing +authors at `ctx.docks.register`. `ctx.docks` is therefore the **long-term path**. +This plan still adds a `dock:true` **convenience flag** on the existing custom-tab +API (so authors get a dock button without rewriting onto docks yet), but treat it +as a bridge: the custom-tabs API persists mainly because docks does **not yet** +cover `vnode` views or tab categories. Do not present `dock:true` as the +permanent, recommended API — call out that `ctx.docks.register` is the direction +of travel. If you add any new deprecation here, use the **next free** +`NDT_DEP_xxxx` code (don't reuse `0002`). ## Context you need Nuxt DevTools v4 renders inside **Vite DevTools** `@vitejs/devtools@0.4` on **devframe 0.6**. Today it registers exactly **one** dock entry: -`packages/devtools/src/module-main.ts` (~lines 92‑98), inside the plugin -`devtools.setup(ctx)` callback (`ctx` is a `ViteDevToolsNodeContext`): +`packages/devtools/src/module-main.ts`, inside the plugin `devtools.setup(ctx)` +callback (`ctx` is a `ViteDevToolsNodeContext`): ```ts ctx.docks.register({ id: 'nuxt:devtools', type: 'iframe', - icon: 'https://nuxt.com/assets/design-kit/icon-green.svg', + icon: '/__nuxt_devtools__/client/nuxt.svg', title: 'Nuxt DevTools', url: '/__nuxt_devtools__/client/', + defaultOrder: -2000, }) ``` @@ -114,14 +131,14 @@ ctx.docks.register({ id: 'nuxt', type: 'group', title: 'Nuxt', - icon: 'https://nuxt.com/assets/design-kit/icon-green.svg', + icon: '/__nuxt_devtools__/client/nuxt.svg', defaultOrder: -900, // sits near the framework tools; tune vs ~viteplus (-1000) defaultChildId: 'nuxt:devtools', }) ctx.docks.register({ id: 'nuxt:devtools', type: 'iframe', - icon: '…', + icon: '/__nuxt_devtools__/client/nuxt.svg', title: 'Nuxt DevTools', url: '/__nuxt_devtools__/client/', groupId: 'nuxt', @@ -162,8 +179,9 @@ ctx.docks.register({ - Custom tabs arrive/refresh dynamically (`devtools:customTabs:refresh`) — keep the promoted dock entries in sync (register on add, update on change; use the `ctx.docks.register(...)` return `{ update }` handle, and re-evaluate on - refresh). Guard for `devtoolsKit` not yet connected (queue + flush, mirroring - `server-rpc/index.ts` `pendingBroadcasts`). + refresh). Do this from `onDevtoolsReady((ctx) => …)` so `ctx.docks` is + already connected; buffer tabs collected before `ready` and register them in + the callback (no `pendingBroadcasts`-style queue needed). - Ship the curated default: mark **Components, Server Routes, Pages** with `dock: true` in their `definePageMeta`. @@ -213,8 +231,8 @@ ctx.docks.register({ a promoted one. Review/adjust that logic (it currently binds by dock entry id `nuxt:devtools`, which is correct — verify it still resolves to the hub). - **Dynamic custom tabs.** Promoted dock entries must track the async - `devtools:customTabs` lifecycle (add/update/remove + refresh) and the - pre-connect queue. + `devtools:customTabs` lifecycle (add/update/remove + refresh); register them + from `onDevtoolsReady` and buffer any collected before the hook fires. - **"Relocating" UX surprise.** Tools vanish from the SideNav; make sure they're discoverable via the dock group and the command palette. Consider a one-time note/changelog for users. diff --git a/plans/vite-devtools-integration/04-ecosystem-playgrounds.md b/plans/vite-devtools-integration/04-ecosystem-playgrounds.md deleted file mode 100644 index e90909b00f..0000000000 --- a/plans/vite-devtools-integration/04-ecosystem-playgrounds.md +++ /dev/null @@ -1,130 +0,0 @@ -# Plan 04 — Ecosystem dogfooding playgrounds - -**Status:** ready to execute · **Risk:** low · **Depends on:** nothing (but most -useful once plans 00–03 are in progress, to verify real integrations). -**Outcome:** a `playgrounds-ecosystem/` folder with one playground per popular -Nuxt module that ships a Nuxt DevTools integration, wired to the **local** -`@nuxt/devtools`, for verification + dogfooding — plus a short per-module -**compatibility/migration report** that later seeds an issue/PR to that module. - -> Self-contained: read this whole file. - -## Why - -Popular modules register Nuxt DevTools tabs/RPC (custom iframe tabs, RPC -functions, launch views, etc.). As we (a) migrate to Vite DevTools 0.4 / -devframe 0.6, (b) add the compat foundation (Plan 00), and (c) reshape the dock -(Plan 03), we need to see real integrations render and behave. These playgrounds -are the dogfooding surface and the basis for helping the ecosystem migrate. - -## Modules to cover (initial set) - -Create one playground per module: - -- `nuxt-og-image` / `@nuxtjs/seo` — OG Image playground tab (iframe + interactive) -- `@nuxt/scripts` — Scripts DevTools tab (first-party) -- `@nuxt/content` — Content DevTools tab (collections/DB viewer) -- `@nuxtjs/tailwindcss` — the classic "Tailwind Viewer" iframe custom tab -- `@nuxthub/core` — Hub viewers (DB/KV/Blob), heavier RPC-driven integration -- `@nuxt/fonts` — Fonts module DevTools surface -- `@nuxt/image` — Image module DevTools surface - -(Chosen because each exercises a real DevTools integration; `@nuxtjs/tailwindcss` -and `nuxt-og-image` are canonical iframe-tab integrations, `@nuxthub/core` is a -rich RPC one.) - -## Decisions (locked) - -1. **One playground per module** under `playgrounds-ecosystem//`. -2. Each links the **local** `@nuxt/devtools` (workspace) so it tests the new - version — reuse the existing playground convention - (`const devtoolsModule = process.env.NUXT_DEVTOOLS_LOCAL ? '../../local' : '@nuxt/devtools'`); - note the relative path is `'../../local'` from `playgrounds-ecosystem//` - — verify/point it at the repo's `local` devtools entry used by `playgrounds/*`. -3. **Opt-in install / out of main CI.** These are NOT part of the default - `pnpm install` or the main CI e2e — they pull heavy third-party deps and - would bloat install + flake CI. Keep the dep graph isolated so a normal repo - install is unaffected. -4. **Per-module compatibility report** (a markdown doc) capturing what works / - breaks / needs migration; later seeds an upstream issue/PR. - -## Implementation - -### Step 1 — isolate the workspace so the main install stays lean - -- Do **not** add `playgrounds-ecosystem/**` to the default `packages:` globs in - `pnpm-workspace.yaml` (which currently lists `packages/**` and `playgrounds/**`). - Options, pick one: - - **Separate opt-in workspace file / script** that installs the ecosystem set - on demand (e.g. a `pnpm -C playgrounds-ecosystem/ install` per - playground, each with its own lockfile), or - - a dedicated `pnpm-workspace.ecosystem.yaml` + an npm script - (`pnpm run ecosystem:install`) that a contributor runs explicitly. -- Each playground links the local devtools. Confirm how `playgrounds/*` resolve - `'../../local'` (the repo exposes a `local` Nuxt module entry for the built - `@nuxt/devtools`); replicate that resolution from the deeper - `playgrounds-ecosystem//` path (likely `'../../local'` still resolves - to `/local` — verify the depth). - -### Step 2 — scaffold each playground - -For each module, a minimal Nuxt app: - -- `playgrounds-ecosystem//package.json` — `nuxt`, the target module (pin - a known-good version), and a `dev`/`build` script. Bind dev to `0.0.0.0` for - remote preview (`nuxi dev --host 0.0.0.0`). -- `nuxt.config.ts` — `modules: [devtoolsModule, '']`, plus the minimal - module config needed to activate its DevTools integration (e.g. tailwind needs - a config; content needs a `content/` dir; og-image needs a route with OG tags; - nuxthub needs its bindings/config). -- Just enough app content to make the integration light up (a page, a component, - sample content, etc.). - -### Step 3 — a per-module compatibility report - -- `playgrounds-ecosystem//COMPAT.md` (or a shared - `playgrounds-ecosystem/REPORTS.md`) recording, per module: - - Does the module's DevTools tab/entry appear? (in the hub SideNav and/or, if - the module opts into `dock:true` from Plan 03, as a dock button) - - Does its RPC / iframe view load without console errors under Vite DevTools - 0.4 / devframe 0.6? - - Any use of deprecated Nuxt DevTools APIs (surfaced by the Plan 00 nostics - deprecation diagnostics) — capture the codes shown. - - Verdict: works as-is / works via shim (with deprecation) / broken + required - migration steps. -- These reports are the raw material for upstream issues/PRs to each module. - -### Step 4 — a dogfooding runbook - -- `playgrounds-ecosystem/README.md`: how to install (opt-in), run a single - playground against the local devtools, and where to record findings. Include - the `agent-browser`/manual steps to open Vite DevTools and exercise each - integration. - -## Acceptance criteria - -- `playgrounds-ecosystem//` exists for each of the 7 modules, each - runnable with the local `@nuxt/devtools` and its DevTools integration visibly - active. -- A normal `pnpm install` at the repo root is **unaffected** (ecosystem deps are - opt-in, not pulled by default; main CI unchanged). -- Each playground has a compatibility report with a clear verdict. -- Running any one playground surfaces (via Plan 00 diagnostics) whether the - module uses deprecated APIs. - -## Risks / gotchas - -- **Dependency bloat / lockfile churn.** Keep ecosystem deps out of the default - workspace + lockfile; isolate per playground so the core repo install stays - lean and reproducible. -- **Module config specifics.** Some integrations only activate with real config - (tailwind config, content dir, nuxthub bindings, og-image routes) — scaffold - the minimum to trigger each DevTools surface. -- **Version drift.** Pin each module to a known version in its playground; note - the version in the report so upstream fixes can be tracked. -- **Local-devtools resolution.** Verify the `'../../local'` link resolves from - the extra directory depth; adjust the relative path if - `playgrounds-ecosystem//` is one level deeper than `playgrounds//`. -- **Not a CI gate (yet).** These are manual dogfooding surfaces; if we later want - automated smoke coverage, add a separate optional workflow (kept off the - critical path). diff --git a/plans/vite-devtools-integration/README.md b/plans/vite-devtools-integration/README.md index 78f09e33a9..48bdcb3599 100644 --- a/plans/vite-devtools-integration/README.md +++ b/plans/vite-devtools-integration/README.md @@ -13,12 +13,18 @@ official `@devframes/plugin-terminals` / `@devframes/plugin-messages` / `@devframes/plugin-inspect` built-ins). The migration to those versions has already landed on `main` (nuxt/devtools#1010). +The **compatibility & deprecation foundation** these plans were originally going +to build has **also already landed** — nuxt/devtools#1021 (server-side) and +nuxt/devtools#1023 (client-side). See ["Landed foundation"](#landed-foundation) +below; that section is now the shared ground these plans stand on (there is no +longer a separate "plan 00" — it shipped). + Today Nuxt DevTools: - Registers **one** `type:'iframe'` dock entry (`nuxt:devtools`) that loads the whole client (`/__nuxt_devtools__/client/`), with ~25 tabs behind an internal `SideNav`. Registration lives in `packages/devtools/src/module-main.ts` - (~lines 92‑98), inside a Vite DevTools plugin `devtools.setup(ctx)` callback. + (inside a Vite DevTools plugin `devtools.setup(ctx)` callback, ~lines 95‑112). - Ships its **own** terminals system (`@xterm` UI, `server-rpc/terminals.ts`, `devtools:terminal:*` Nuxt hooks, output-only child processes). - Ships its **own** ephemeral toast (`devtoolsUiShowNotification` in @@ -32,53 +38,126 @@ We're cutting a **new major**. Breaking changes are acceptable, but migration for module authors/users must be **minimal and self-discoverable**, with a gradual long-term move to devframe-native APIs. Concretely: -1. **Keep** the existing Nuxt DevTools API working. -2. **Expose** the devframe-native API alongside it (connect-safe hosts on - `nuxt.devtools`). +1. **Keep** the existing Nuxt DevTools API working (via shims). +2. **Expose** the devframe-native API — done: modules reach the connected + `ViteDevToolsNodeContext` through the `devtools:ready` hook / `onDevtoolsReady` + (server) and `onDevtoolsReady` from `@nuxt/devtools-kit/iframe-client` + + `client.devtools.devtoolsKit` (client). 3. **Soft-deprecate** the Nuxt API where a devframe equivalent exists — via a backward-compatible **shim** + a **nostics** deprecation diagnostic (code + - fix + doc link). **Hard-break only where a faithful shim is infeasible.** + fix + doc link). This mechanism has shipped (see below). 4. Build the feature work (Messages / Terminals / Dock groups) **on top of** that foundation. -5. **Dogfood** against real ecosystem modules and produce migration reports. + +## Landed foundation + +The foundation these plans depend on is **already implemented** — do **not** +rebuild it. Build the feature plans on top of it. + +### Reaching the connected context + +**Server side** — `onDevtoolsReady((ctx) => …)` (from `@nuxt/devtools-kit`, +backed by the `devtools:ready` Nuxt hook) runs once the Vite DevTools kit has +connected and hands you the connected `ViteDevToolsNodeContext`, exposing +`ctx.docks`, `ctx.terminals`, `ctx.messages`, `ctx.commands`, `ctx.rpc`, and +`ctx.diagnostics`: + +```ts +import { onDevtoolsReady } from '@nuxt/devtools-kit' + +onDevtoolsReady((ctx) => { + ctx.docks.register({ id: 'my-module', type: 'iframe', title: 'My Module', url: '/…' }) +}) +``` + +This is the **recommended entry point** — the kit is guaranteed available, so +there is **no pre-connect timing problem and no queue to manage**. (Earlier +drafts proposed "connect-safe host accessors" on `nuxt.devtools` with an internal +queue; those were **not** built and the ready hook supersedes them.) The raw +`nuxt.devtools.devtoolsKit` (`ViteDevToolsNodeContext | undefined` until connect) +remains the escape hatch. Wiring lives in +`packages/devtools/src/server-rpc/index.ts` (`connectDevToolsKit` fires +`devtools:ready`). + +**Client side** (nuxt/devtools#1023) — `onDevtoolsReady((kit) => …)` from +`@nuxt/devtools-kit/iframe-client` mirrors the server hook and hands back the +connected `DevToolsRpcClient`. `client.devtools.devtoolsKit` is that same +connected client (mirror of `nuxt.devtools.devtoolsKit`), giving full +devframe-native client access (register client RPC, call server functions, +shared state, streaming) with **no** `@vitejs/devtools-kit/client` import: + +```ts +import { onDevtoolsReady } from '@nuxt/devtools-kit/iframe-client' + +onDevtoolsReady((kit) => { + kit.client.register({ name: 'my-module:on-update', type: 'event', handler }) +}) +``` + +### nostics deprecation system (shipped) + +`packages/devtools-kit/src/diagnostics.ts` implements the deprecation engine: + +- A `diagnosticCodes` catalog + `consoleDiagnostics` standalone reporter (prints + to the terminal pre-connect), and `registerHostDiagnostics(ctx)` which also + registers the codes into the DevTools **diagnostics host** post-connect so they + surface inside DevTools. +- `deprecate(nuxt, code, params, { key?, method? })` — emits once per + `code:key` (deduped), routing to the host catalog when connected and the + console catalog otherwise. `method: 'error'` for hard breaks; default `'warn'`. +- `docsBase` resolves to a per-code migration-guide anchor: + `https://devtools.nuxt.com/module/migration-v4#`. + +**Codes already allocated** (extend by appending to `diagnosticCodes`; give each +new code a migration-guide anchor): + +| Code | Deprecated API | Replacement | +|---|---|---| +| `NDT_DEP_0001` | `startSubprocess().getProcess()` | `getResult()` | +| `NDT_DEP_0002` | *retired* (`disableAuthorization` is now a supported option) | — | +| `NDT_DEP_0003` | `extendServerRpc` | `onDevtoolsReady((ctx) => ctx.rpc.register(defineRpcFunction(...)))` | +| `NDT_DEP_0004` | `startSubprocess` | `onDevtoolsReady((ctx) => ctx.terminals.startChildProcess(...))` | +| `NDT_DEP_0005` | `addCustomTab` | `onDevtoolsReady((ctx) => ctx.docks.register(...))` | +| `NDT_DEP_0006` | `refreshCustomTabs` | update via the `ctx.docks.register(...)` handle | +| `NDT_DEP_0007` | direct `nuxt.devtools.rpc` (`broadcast`/`functions`) | the connected `ctx.rpc` from `onDevtoolsReady` | +| `extendClientRpc` (client) | deprecated in #1023 | `onDevtoolsReady((kit) => kit.client.register(...))` | + +These shims **already ship** — `addCustomTab` / `refreshCustomTabs` / +`startSubprocess` / `extendServerRpc` all still work and merely warn. New +deprecations added by the plans below use `deprecate(...)` with the **next free** +`NDT_DEP_xxxx` code (don't reuse `0002`). + +> **Note — `disableAuthorization`.** An earlier draft wanted to hard-break this +> option with an error-level diagnostic. That was reversed: it is now a +> **supported first-class option** (`ModuleOptions.disableAuthorization`, +> mapped to Vite's `devtools.clientAuth = false`; default `isSandboxed`). Do +> **not** deprecate it. ## Workstreams | # | Plan | Scope | Risk | Depends on | |---|------|-------|------|------------| -| 00 | [`00-compat-foundation.md`](./00-compat-foundation.md) | Expose devframe-native API as connect-safe hosts on `nuxt.devtools`; add nostics-driven soft-deprecation (catalog + host registration); establish the shim-first policy + deprecation map. | Medium | none | -| 01 | [`01-messages-unification.md`](./01-messages-unification.md) | Route all notifications through the devframe Messages system (`messages` host + built-in Messages dock); retire the bespoke toast. | Low | 00 | -| 02 | [`02-terminals-reuse.md`](./02-terminals-reuse.md) | Retire Nuxt's `@xterm` terminals; surface sessions in the built-in Terminals dock via the `terminals` host; keep a compat shim for the `devtools:terminal:register` hook. | Medium | 00 | -| 03 | [`03-dock-groups-presentation.md`](./03-dock-groups-presentation.md) | Introduce a **"Nuxt" dock group** and a general **promote‑tab‑to‑dock** capability; relocate a curated set of tools onto the dock bar. | High (UX) | 00 | -| 04 | [`04-ecosystem-playgrounds.md`](./04-ecosystem-playgrounds.md) | `playgrounds-ecosystem/` per popular module (og-image/SEO, scripts, content, tailwindcss, nuxthub, fonts, image) linked to local devtools; opt-in install; per-module compat report. | Low | cross-cutting (verifies 00–03) | +| 01 | [`01-messages-unification.md`](./01-messages-unification.md) | Route all notifications through the devframe Messages system (`ctx.messages` + built-in Messages dock); retire the bespoke toast. | Low | landed foundation | +| 02 | [`02-terminals-reuse.md`](./02-terminals-reuse.md) | Retire Nuxt's `@xterm` terminals; surface sessions in the built-in Terminals dock via `ctx.terminals`; keep a compat shim for the `devtools:terminal:register` hook. | Medium | landed foundation | +| 03 | [`03-dock-groups-presentation.md`](./03-dock-groups-presentation.md) | Introduce a **"Nuxt" dock group** and a general **promote‑tab‑to‑dock** capability; relocate a curated set of tools onto the dock bar. | High (UX) | landed foundation | + +Recommended order: **01 → 02 → 03**. Each is technically buildable/reviewable as +a **separate PR** on top of the landed foundation (#1021/#1023). -Recommended order: **00 → 01 → 02 → 03**, with **04** running alongside as the -dogfooding/verification surface. Each is technically buildable/reviewable as a -**separate PR** (00 first, since 01/02/03 use the surfaces it creates). +> **Ecosystem dogfooding** (the former "plan 04") is being handled separately in +> nuxt/devtools#1022 (`playgrounds-ecosystem/`), so it no longer lives here. Use +> those playgrounds to verify plans 01–03 against real module integrations and to +> capture per-module compatibility reports. ## Shared facts every plan relies on **Versions** (already in `pnpm-workspace.yaml` catalogs): `@vitejs/devtools` `^0.4.0`, `@vitejs/devtools-kit` `^0.4.0`, `vite-plugin-inspect` `^12.0.2`, `vue` `^3.5.39`; transitively `devframe`/`@devframes/hub`/`@devframes/plugin-*` -`0.6.0`. - -**Where Nuxt gets the Vite DevTools node context (`ctx`)** — a -`ViteDevToolsNodeContext`, which exposes `ctx.docks`, `ctx.terminals`, -`ctx.messages`, `ctx.commands`, `ctx.rpc`: - -- In `packages/devtools/src/module-main.ts`, inside - `defineViteDevToolsPlugin({ name: 'nuxt:devtools', devtools: { setup(ctx) { … } } })`. - That callback also calls `connectDevToolsKit?.(ctx)`. -- `connectDevToolsKit` is defined in `packages/devtools/src/server-rpc/index.ts` - (`setupRPC`), which stores the ctx as `devtoolsKitCtx` and exposes it on the - Nuxt server context as `ctx.devtoolsKit` (typed in - `packages/devtools-kit/src/_types/server-ctx.ts` as `DevToolsNodeContext | undefined`). - So server-side integrations receive `{ devtoolsKit }` and can call - `devtoolsKit.terminals.*` / `devtoolsKit.messages.*`. +`0.6.0`; `nostics` `1.1.4`. **devframe host APIs (node side)** — from `@devframes/hub` (re-exported by -`@vitejs/devtools-kit`): +`@vitejs/devtools-kit`), reached via `ctx` from `onDevtoolsReady`: ```ts // ctx.terminals: DevframeTerminalsHost @@ -143,25 +222,36 @@ iframe. (This is the same mechanism as the "Connecting…" fix in North star: pursue **all** of — discoverability/UX parity, maintenance reduction, behavioral consistency, and capability upgrade. -Foundation (plan 00): -- **Expose devframe-native API** as first-class **connect-safe** hosts on - `nuxt.devtools` (`docks`/`terminals`/`messages`/`commands`/`diagnostics`), - queuing pre-connect calls; keep raw `devtoolsKit` as an escape hatch. -- **Self-discoverable deprecations** via a Nuxt **nostics** catalog - (`defineDiagnostics` + `createConsoleReporter()` + `docsBase` → Nuxt docs), - **also registered into the DevTools host diagnostics** so they surface inside - DevTools. Warn-only by default; every code carries `why` + `fix` + doc link. -- **Shim-first**: keep every existing API working this major via shims; - deprecations are warnings; removal deferred to the next major. **Hard-break - only where a faithful shim is infeasible** (error-level diagnostic naming the - replacement). - -Ecosystem (plan 04): -- **One playground per module** under `playgrounds-ecosystem/`, linked to the - **local** `@nuxt/devtools`; initial set: og-image/SEO, scripts, content, - tailwindcss, nuxthub, fonts, image. -- **Opt-in install / out of main CI** (avoid dep bloat + flake). -- **Per-module compatibility report** that later seeds an upstream issue/PR. +Foundation (landed in #1021/#1023 — for reference, not to rebuild): +- **Devframe-native API exposed** via the server + client `onDevtoolsReady` + hooks and `nuxt.devtools.devtoolsKit` / `client.devtools.devtoolsKit`. The + connect-safe-accessor idea was dropped in favour of the ready hooks (kit + guaranteed present, no queue). +- **Self-discoverable deprecations** via the Nuxt **nostics** catalog + (`deprecate()` → console pre-connect + DevTools diagnostics host post-connect; + every code carries `why` + `fix` + a migration-guide doc link). +- **Shim-first**: existing APIs keep working this major via shims; deprecations + are warnings; removal deferred to the next major. + +Messages (plan 01): +- **Unify everything into the devframe Messages system** (one notification + system). The client toast is re-implemented to push into it. +- **Tiered by intent**: ephemeral client feedback → `notify + autoDismiss + + autoDelete` (toast-only, no history); server-originated → persisted + leveled. +- **Public notify API** (a `devtools:notify` Nuxt hook and/or + `useNuxtDevTools().notify()`) forwarded to `ctx.messages`, plus a curated set + of built-in sources (build/module errors & warnings, server-task results). + +Terminals (plan 02): +- **Full replacement + compat shim**: retire the `@xterm` UI + `server-rpc/terminals` + + terminals tab; route sessions through `ctx.terminals` (built-in Terminals + dock); keep the `devtools:terminal:register` hook as a shim forwarding to + `ctx.terminals`. +- Capability: **preserve output-only** for existing module terminals (map to + read-only registered sessions), **add opt-in PTY** for new interactive use. +- Note: the `startSubprocess` (`NDT_DEP_0004`) and `getProcess()` (`NDT_DEP_0001`) + deprecation warnings already ship, but the shim still routes through the old + `devtools:terminal:*` hooks — this plan swaps the underlying implementation. Presentation (plan 03): - **Curated hybrid "Nuxt" dock group**: the hub iframe stays the primary member; @@ -176,23 +266,10 @@ Presentation (plan 03): lives only as a dock button; the SideNav shrinks to non-promoted + Vue tools. - Vue-bridge tools (Pinia, Render Tree) stay in the hub only. - Default promoted set: **Components, Server Routes, Pages**. - -Terminals (plan 02): -- **Full replacement + compat shim**: retire the `@xterm` UI + `server-rpc/terminals` - + terminals tab; route sessions through `ctx.terminals` (built-in Terminals - dock); keep the `devtools:terminal:register` hook as a shim forwarding to - `ctx.terminals`. -- Capability: **preserve output-only** for existing module terminals (map to - read-only registered sessions), **add opt-in PTY** for new interactive use. - -Messages (plan 01): -- **Unify everything into the devframe Messages system** (one notification - system). The client toast is re-implemented to push into it. -- **Tiered by intent**: ephemeral client feedback → `notify + autoDismiss + - autoDelete` (toast-only, no history); server-originated → persisted + leveled. -- **Public notify API** (a `devtools:notify` Nuxt hook and/or - `useNuxtDevTools().notify()`) forwarded to `ctx.messages`, plus a curated set - of built-in sources (build/module errors & warnings, server-task results). +- Tension to keep in mind: `addCustomTab` is now soft-deprecated (`NDT_DEP_0005`) + toward `ctx.docks.register`. Plan 03 still adds a `dock:true` convenience flag + on the custom-tab API, but docks is the long-term path (docks doesn't yet cover + `vnode` views or tab categories, which is why custom tabs still exist). ## Working agreement