devframe 0.1.20 → 0.1.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/README.md +41 -18
  2. package/dist/{_shared-S-Ujqz_L.mjs → _shared-DcJX9-Az.mjs} +4 -4
  3. package/dist/adapters/build.d.mts +7 -7
  4. package/dist/adapters/build.mjs +15 -14
  5. package/dist/adapters/cli.d.mts +2 -2
  6. package/dist/adapters/cli.mjs +5 -5
  7. package/dist/adapters/dev.d.mts +18 -9
  8. package/dist/adapters/dev.mjs +1 -1
  9. package/dist/adapters/embedded.d.mts +6 -6
  10. package/dist/adapters/embedded.mjs +3 -3
  11. package/dist/adapters/mcp.d.mts +3 -3
  12. package/dist/adapters/mcp.mjs +6 -5
  13. package/dist/adapters/vite.d.mts +46 -12
  14. package/dist/adapters/vite.mjs +81 -17
  15. package/dist/chunk-e9Ob2GDo.mjs +26 -0
  16. package/dist/client/index.d.mts +19 -144
  17. package/dist/client/index.mjs +20 -20
  18. package/dist/colors-Bl4W18Mh.mjs +123 -0
  19. package/dist/constants.d.mts +12 -15
  20. package/dist/constants.mjs +12 -29
  21. package/dist/context-DBd794Rn.d.mts +51 -0
  22. package/dist/context-DUibxhrR.mjs +1034 -0
  23. package/dist/{dev-B8i_CBlQ.mjs → dev-BGpTpYiR.mjs} +20 -21
  24. package/dist/{devtool-Bm6zZAw5.d.mts → devframe-DulcIxwu.d.mts} +59 -569
  25. package/dist/diagnostics-BFhNNmST.mjs +56 -0
  26. package/dist/hash-BHZbo80D.mjs +126 -0
  27. package/dist/{human-id-CHS0s28X.mjs → human-id-adtUWQLr.mjs} +12 -4
  28. package/dist/{index-BCo03GEF.d.mts → index-DB2Ie0Or.d.mts} +2 -3
  29. package/dist/index.d.mts +4 -6
  30. package/dist/index.mjs +2 -8
  31. package/dist/launch-editor-KA_21J1T.mjs +581 -0
  32. package/dist/node/auth.d.mts +44 -0
  33. package/dist/node/auth.mjs +55 -0
  34. package/dist/node/index.d.mts +14 -187
  35. package/dist/node/index.mjs +6 -61
  36. package/dist/node/internal.d.mts +16 -0
  37. package/dist/node/internal.mjs +50 -0
  38. package/dist/{open-BtOOEldu.mjs → open-DmFp0qZA.mjs} +15 -6
  39. package/dist/recipes/open-helpers.d.mts +4 -9
  40. package/dist/recipes/open-helpers.mjs +7 -12
  41. package/dist/revoke-DIMz1r7-.mjs +35 -0
  42. package/dist/rpc/index.d.mts +3 -3
  43. package/dist/rpc/index.mjs +4 -4
  44. package/dist/rpc/transports/ws-client.d.mts +1 -1
  45. package/dist/rpc/transports/ws-client.mjs +2 -1
  46. package/dist/rpc/transports/ws-server.d.mts +1 -1
  47. package/dist/rpc/transports/ws-server.mjs +2 -1
  48. package/dist/{rpc-INbWfHoX.mjs → rpc-CkZuoz-m.mjs} +3 -2
  49. package/dist/{serialization-DwKi05Pn.mjs → serialization-CwO31axa.mjs} +1 -2
  50. package/dist/{server-qRRM8t3v.mjs → server-ma8-ZVyX.mjs} +1 -1
  51. package/dist/{server-DksyT-um.d.mts → server-zKEDxgqD.d.mts} +4 -3
  52. package/dist/shared-state-DCDs0e7y.mjs +928 -0
  53. package/dist/{static-dump-C1aVSwxY.mjs → static-dump-D7AvjrgL.mjs} +1 -1
  54. package/dist/storage-CNC38eU-.mjs +117 -0
  55. package/dist/structured-clone-DcDc2Dds.mjs +221 -0
  56. package/dist/types/index.d.mts +4 -4
  57. package/dist/types/index.mjs +11 -2
  58. package/dist/utils/colors.d.mts +28 -0
  59. package/dist/utils/colors.mjs +2 -0
  60. package/dist/utils/events.d.mts +1 -1
  61. package/dist/utils/hash.d.mts +7 -0
  62. package/dist/utils/hash.mjs +2 -0
  63. package/dist/utils/human-id.d.mts +6 -8
  64. package/dist/utils/human-id.mjs +1 -2
  65. package/dist/utils/launch-editor.d.mts +13 -0
  66. package/dist/utils/launch-editor.mjs +2 -0
  67. package/dist/utils/open.d.mts +16 -0
  68. package/dist/utils/open.mjs +2 -0
  69. package/dist/utils/serve-static.d.mts +30 -0
  70. package/dist/utils/serve-static.mjs +152 -0
  71. package/dist/utils/shared-state.d.mts +1 -1
  72. package/dist/utils/shared-state.mjs +1 -35
  73. package/dist/utils/streaming-channel.d.mts +1 -1
  74. package/dist/utils/structured-clone.d.mts +21 -0
  75. package/dist/utils/structured-clone.mjs +2 -0
  76. package/dist/utils/when.d.mts +384 -2
  77. package/dist/utils/when.mjs +20 -2
  78. package/dist/{ws-client-DQySVfF_.d.mts → ws-client-Bavoya6-.d.mts} +1 -1
  79. package/dist/{ws-server-VQqESKAs.d.mts → ws-server-DjvlwLuM.d.mts} +1 -1
  80. package/package.json +23 -13
  81. package/skills/devframe/SKILL.md +93 -117
  82. package/skills/devframe/templates/{counter-devtool.ts → counter-devframe.ts} +5 -10
  83. package/skills/devframe/templates/{spa-devtool.ts → spa-devframe.ts} +5 -10
  84. package/skills/devframe/templates/vite-client.ts +2 -2
  85. package/dist/adapters/kit.d.mts +0 -23
  86. package/dist/adapters/kit.mjs +0 -16
  87. package/dist/context-BfvbAyGk.mjs +0 -7215
  88. package/dist/main-DpINGndA.mjs +0 -601
  89. package/dist/utils/state.d.mts +0 -50
  90. package/dist/utils/state.mjs +0 -26
  91. package/dist/when-aBBXAEh5.d.mts +0 -401
  92. package/dist/{define-Bb4zh-Dc.mjs → define-CW9gLnyG.mjs} +0 -0
  93. package/dist/{host-h3-BMvrFzIJ.mjs → host-h3-Dz8YnFgu.mjs} +2 -2
  94. /package/dist/{transports-BPUzHhI2.mjs → transports-BnCs4rj9.mjs} +0 -0
  95. /package/dist/{types-ag029cAe.d.mts → types-4rdUEi2R.d.mts} +0 -0
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "devframe",
3
3
  "type": "module",
4
- "version": "0.1.20",
4
+ "version": "0.1.22",
5
5
  "description": "Framework for building generic DevTools",
6
6
  "author": "Anthony Fu <anthonyfu117@hotmail.com>",
7
7
  "license": "MIT",
@@ -24,12 +24,13 @@
24
24
  "./adapters/cli": "./dist/adapters/cli.mjs",
25
25
  "./adapters/dev": "./dist/adapters/dev.mjs",
26
26
  "./adapters/embedded": "./dist/adapters/embedded.mjs",
27
- "./adapters/kit": "./dist/adapters/kit.mjs",
28
27
  "./adapters/mcp": "./dist/adapters/mcp.mjs",
29
28
  "./adapters/vite": "./dist/adapters/vite.mjs",
30
29
  "./client": "./dist/client/index.mjs",
31
30
  "./constants": "./dist/constants.mjs",
32
31
  "./node": "./dist/node/index.mjs",
32
+ "./node/auth": "./dist/node/auth.mjs",
33
+ "./node/internal": "./dist/node/internal.mjs",
33
34
  "./recipes/open-helpers": "./dist/recipes/open-helpers.mjs",
34
35
  "./rpc": "./dist/rpc/index.mjs",
35
36
  "./rpc/client": "./dist/rpc/client.mjs",
@@ -37,13 +38,18 @@
37
38
  "./rpc/transports/ws-client": "./dist/rpc/transports/ws-client.mjs",
38
39
  "./rpc/transports/ws-server": "./dist/rpc/transports/ws-server.mjs",
39
40
  "./types": "./dist/types/index.mjs",
41
+ "./utils/colors": "./dist/utils/colors.mjs",
40
42
  "./utils/events": "./dist/utils/events.mjs",
43
+ "./utils/hash": "./dist/utils/hash.mjs",
41
44
  "./utils/human-id": "./dist/utils/human-id.mjs",
45
+ "./utils/launch-editor": "./dist/utils/launch-editor.mjs",
42
46
  "./utils/nanoid": "./dist/utils/nanoid.mjs",
47
+ "./utils/open": "./dist/utils/open.mjs",
43
48
  "./utils/promise": "./dist/utils/promise.mjs",
49
+ "./utils/serve-static": "./dist/utils/serve-static.mjs",
44
50
  "./utils/shared-state": "./dist/utils/shared-state.mjs",
45
- "./utils/state": "./dist/utils/state.mjs",
46
51
  "./utils/streaming-channel": "./dist/utils/streaming-channel.mjs",
52
+ "./utils/structured-clone": "./dist/utils/structured-clone.mjs",
47
53
  "./utils/when": "./dist/utils/when.mjs",
48
54
  "./package.json": "./package.json"
49
55
  },
@@ -62,46 +68,50 @@
62
68
  },
63
69
  "dependencies": {
64
70
  "@valibot/to-json-schema": "^1.7.0",
65
- "ansis": "^4.2.0",
66
71
  "birpc": "^4.0.0",
67
72
  "cac": "^7.0.0",
68
73
  "h3": "^1.15.11",
69
- "immer": "^11.1.7",
70
- "launch-editor": "^2.13.2",
71
74
  "logs-sdk": "^0.0.6",
72
- "ohash": "^2.0.11",
75
+ "mrmime": "^2.0.1",
73
76
  "pathe": "^2.0.3",
74
- "sirv": "^3.0.2",
75
- "structured-clone-es": "^2.0.0",
76
77
  "valibot": "^1.4.0",
77
78
  "ws": "^8.20.0"
78
79
  },
79
80
  "devDependencies": {
80
81
  "@modelcontextprotocol/sdk": "^1.29.0",
82
+ "ansis": "^4.2.0",
83
+ "immer": "^11.1.8",
81
84
  "launch-editor": "^2.13.2",
82
- "tsdown": "^0.21.10",
85
+ "ohash": "^2.0.11",
86
+ "open": "^11.0.0",
87
+ "structured-clone-es": "^2.0.0",
88
+ "tsdown": "^0.22.0",
83
89
  "whenexpr": "^0.1.2"
84
90
  },
85
91
  "inlinedDependencies": {
86
- "acorn": "8.16.0",
92
+ "ansis": "4.2.0",
87
93
  "bundle-name": "4.1.0",
88
94
  "default-browser": "5.4.0",
89
95
  "default-browser-id": "5.0.1",
90
96
  "define-lazy-prop": "3.0.0",
91
97
  "get-port-please": "3.2.0",
92
98
  "human-id": "4.1.3",
99
+ "immer": "11.1.8",
93
100
  "is-docker": "3.0.0",
94
101
  "is-in-ssh": "1.0.0",
95
102
  "is-inside-container": "1.0.0",
96
103
  "is-wsl": "3.1.0",
97
- "mlly": "1.8.2",
104
+ "launch-editor": "2.13.2",
98
105
  "obug": "2.1.1",
106
+ "ohash": "2.0.11",
99
107
  "open": "11.0.0",
100
108
  "p-limit": "7.3.0",
101
109
  "perfect-debounce": "2.1.0",
110
+ "picocolors": "1.1.1",
102
111
  "powershell-utils": "0.1.0",
103
112
  "run-applescript": "7.1.0",
104
- "tinyexec": "1.1.2",
113
+ "shell-quote": "1.8.3",
114
+ "structured-clone-es": "2.0.0",
105
115
  "ua-parser-modern": "0.1.1",
106
116
  "whenexpr": "0.1.2",
107
117
  "wsl-utils": "0.3.1",
@@ -1,26 +1,31 @@
1
1
  ---
2
2
  name: devframe
3
3
  description: >
4
- Use when building devtools with devframe — the framework-neutral
5
- foundation that powers Vite DevTools. Covers DevtoolDefinition,
6
- picking the right adapter (cli / build / spa / vite / kit / embedded /
7
- mcp), designing RPC contracts, registering docks / commands / logs /
8
- terminals, exposing an agent-native surface over MCP, and wiring the
9
- author's SPA client. Triggers on `devframe` imports, `defineDevtool`,
10
- `createCli`, `createMcpServer`, `connectDevtool`, and on migrations of
11
- existing inspectors (eslint-config-inspector, unocss-inspector,
12
- node-modules-inspector-style tools) to devframe.
4
+ Use when building one devtool integration with devframe — the
5
+ portable, framework-neutral container for a single tool. Covers
6
+ DevframeDefinition, picking the right deployment adapter
7
+ (cli / build / spa / vite / embedded / mcp), designing RPC
8
+ contracts, exposing an agent-native surface over MCP, and wiring
9
+ the author's SPA client. Hub-only concerns (docks, terminals,
10
+ commands, the unified messages dock) belong to
11
+ `@vitejs/devtools-kit` see the `vite-devtools-kit` skill for
12
+ those. Triggers on `devframe` imports, `defineDevframe`,
13
+ `createCli`, `createMcpServer`, `connectDevframe`, and on
14
+ migrations of existing inspectors (eslint-config-inspector,
15
+ unocss-inspector, node-modules-inspector-style tools) to devframe.
13
16
  ---
14
17
 
15
18
  # devframe skill
16
19
 
17
- A devtool built on devframe is a **single `DevtoolDefinition`** plus an author-provided SPA. Use one of seven adapters to ship it. `devframe` must not depend on Vite or any `@vitejs/*` package it's the lowest-level layer in the monorepo, and the Kit / core packages build on top.
20
+ **Devframe is the container for one devtool integration, portable across viewers.** A devtool built on devframe is a single `DevframeDefinition` plus an author-provided SPA the same definition deploys as a standalone CLI, a static report, an embedded SPA, an MCP server, or as a dock entry inside the Vite DevTools hub via `createPluginFromDevframe`.
21
+
22
+ Devframe deliberately stops at the boundary of one tool. Anything that only matters across multiple integrations — docks, terminals, command palette, cross-tool toasts — lives in `@vitejs/devtools-kit`, the hub layer. `devframe` must not depend on Vite, any `@vitejs/*` package, or hub-only concepts; it's the lowest-level layer in the monorepo.
18
23
 
19
24
  Full reference: [devfra.me/](https://devfra.me/).
20
25
 
21
26
  ## When to use devframe
22
27
 
23
- All adapter factories share the shape `createXxx(devtoolDef, options?)`.
28
+ All adapter factories share the shape `createXxx(devframeDef, options?)`.
24
29
 
25
30
  | Author goal | Factory | Entry |
26
31
  |-------------|---------|-------|
@@ -28,18 +33,18 @@ All adapter factories share the shape `createXxx(devtoolDef, options?)`.
28
33
  | Run the dev server programmatically (any CLI framework) | `createDevServer(def, options?)` | `devframe/adapters/dev` |
29
34
  | Mount a SPA in an existing Vite dev server | `createVitePlugin(def, options?)` | `devframe/adapters/vite` |
30
35
  | Self-contained static deploy with baked data | `createBuild(def, options?)` | `devframe/adapters/build` |
31
- | Integrate into Vite DevTools | `createKitPlugin(def, options?)` | `devframe/adapters/kit` |
36
+ | Integrate into Vite DevTools | `createPluginFromDevframe(def, options?)` | `@vitejs/devtools-kit/node` |
32
37
  | Register dynamically at runtime | `createEmbedded(def, { ctx })` | `devframe/adapters/embedded` |
33
38
  | Expose to coding agents (MCP) | `createMcpServer(def, options?)` | `devframe/adapters/mcp` *(experimental)* |
34
39
 
35
- The same `DevtoolDefinition` runs under every adapter — pick based on deployment, not on what the tool does.
40
+ The same `DevframeDefinition` runs under every adapter — pick based on deployment, not on what the tool does.
36
41
 
37
- ## Minimum viable devtool
42
+ ## Minimum viable devframe
38
43
 
39
44
  ```ts
40
- import { defineDevtool, defineRpcFunction } from 'devframe'
45
+ import { defineDevframe, defineRpcFunction } from 'devframe'
41
46
 
42
- export default defineDevtool({
47
+ export default defineDevframe({
43
48
  id: 'my-inspector',
44
49
  name: 'My Inspector',
45
50
  icon: 'ph:magnifying-glass-duotone',
@@ -50,46 +55,39 @@ export default defineDevtool({
50
55
  type: 'static',
51
56
  handler: () => ({ count: 42 }),
52
57
  }))
53
- ctx.docks.register({
54
- id: 'my-inspector',
55
- title: 'My Inspector',
56
- icon: 'ph:magnifying-glass-duotone',
57
- type: 'iframe',
58
- url: '/.devtools/',
59
- })
60
58
  },
61
59
  })
62
60
  ```
63
61
 
64
- See `templates/counter-devtool.ts` for a runnable counter example, `templates/spa-devtool.ts` for an SPA-ready shape, and `templates/vite-client.ts` for the author's client entry.
62
+ `setup(ctx)` registers RPC functions, shared state, diagnostics, and any other devframe-level wiring. It does **not** receive `docks` / `terminals` / `messages` / `commands` — those are hub features. When mounted into Vite DevTools via `createPluginFromDevframe(d)`, the kit auto-derives an iframe dock entry from `id` / `name` / `icon` / `basePath`; for richer hub-side behaviour (custom-render, terminals, palette commands) pass `options.setup` to `createPluginFromDevframe`.
63
+
64
+ See `templates/counter-devframe.ts` for a runnable counter example, `templates/spa-devframe.ts` for an SPA-ready shape, and `templates/vite-client.ts` for the author's client entry.
65
65
 
66
66
  ## Namespacing
67
67
 
68
- **Always prefix** RPC names, dock IDs, command IDs, shared-state keys, and agent tool IDs with the devtool `id`:
68
+ **Always prefix** RPC names, dock IDs, command IDs, shared-state keys, and agent tool IDs with the devframe `id`:
69
69
 
70
70
  ```ts
71
71
  'my-inspector:get-modules' // ✓
72
72
  'my-inspector:state' // ✓
73
- 'get-modules' // ✗ — may collide with other devtools sharing the host
73
+ 'get-modules' // ✗ — may collide with other devframes sharing the host
74
74
  ```
75
75
 
76
76
  ## DevToolsNodeContext at a glance
77
77
 
78
- `setup(ctx)` receives the full server-side surface. Each host corresponds to a [docs](https://devfra.me/) page:
78
+ `setup(ctx)` receives the framework-neutral server-side surface. Each host corresponds to a [docs](https://devfra.me/) page:
79
79
 
80
80
  | Host | Purpose |
81
81
  |------|---------|
82
- | `ctx.rpc` | Register RPC functions, broadcast, shared state |
83
- | `ctx.docks` | Dock entries (iframe / action / custom-render / launcher / json-render) |
82
+ | `ctx.rpc` | Register RPC functions, broadcast, shared state, streaming channels |
84
83
  | `ctx.views` | Serve static files via `hostStatic(base, distDir)` |
85
- | `ctx.commands` | Command palette entries with keybindings + `when` gating |
86
- | `ctx.messages` | Structured message entries, toasts, file / element positions |
87
84
  | `ctx.diagnostics` | Structured diagnostics host (logs-sdk) — register custom error codes |
88
- | `ctx.terminals` | Spawn and stream child processes |
89
85
  | `ctx.agent` | Expose tools + resources to coding agents (experimental) |
90
86
  | `ctx.host` | Runtime abstraction — `mountStatic`, `resolveOrigin`, `getStorageDir` |
91
87
  | `ctx.mode` | `'dev'` or `'build'` — gate setup work per runtime |
92
88
 
89
+ > Hub-only hosts (`ctx.docks`, `ctx.terminals`, `ctx.messages`, `ctx.commands`, `ctx.createJsonRenderer`) only exist when the devframe is mounted into Vite DevTools via `createPluginFromDevframe`. See the [`vite-devtools-kit` skill](../../skills/vite-devtools-kit) for those.
90
+
93
91
  ## RPC contracts
94
92
 
95
93
  ```ts
@@ -240,84 +238,36 @@ Readable.fromWeb(reader.readable).pipe(targetNodeWritable)
240
238
 
241
239
  For chat-style UIs that combine both: keep the **conversation log** in shared state (survives reconnects), and use a streaming channel for **active responses**. The action that starts a response appends a placeholder to shared state; on producer close, commit the joined content back to shared state. Working example: [`devframe/examples/devframe-streaming-chat`](https://github.com/vitejs/devtools/tree/main/devframe/examples/devframe-streaming-chat).
242
240
 
243
- ## Dock entries
241
+ ## Mounting into Vite DevTools
244
242
 
245
- Five entry types: `iframe` (full panel), `action` (client script on click), `custom-render` (mount into panel DOM), `launcher` (setup card + server callback), `json-render` (UI from a JSON spec, zero client code).
243
+ A portable devframe definition is dropped into the Vite DevTools hub via `createPluginFromDevframe`:
246
244
 
247
245
  ```ts
248
- // Iframe — most common:
249
- ctx.docks.register({
250
- id: 'my-inspector',
251
- title: 'My Inspector',
252
- icon: 'ph:magnifying-glass-duotone',
253
- type: 'iframe',
254
- url: '/.my-inspector/',
255
- })
256
-
257
- ctx.views.hostStatic('/.my-inspector/', clientDist)
246
+ // vite.config.ts
247
+ import { createPluginFromDevframe } from '@vitejs/devtools-kit/node'
248
+ import myInspector from './my-inspector'
249
+
250
+ export default {
251
+ plugins: [
252
+ createPluginFromDevframe(myInspector, {
253
+ // Optional kit-only setup — runs after the auto-derived dock entry.
254
+ setup(kitCtx) {
255
+ kitCtx.commands.register({
256
+ id: 'my-inspector:clear-cache',
257
+ title: 'Clear Cache',
258
+ handler: () => { /* ... */ },
259
+ })
260
+ },
261
+ }),
262
+ ],
263
+ }
258
264
  ```
259
265
 
260
- All entries accept `when` for conditional visibility and `badge` for short indicator text. See `/devframe/dock-system` for the full type reference.
261
-
262
- ### Remote docks
263
-
264
- Set `remote: true` on an iframe dock to turn a hosted URL into a live DevFrame client. DevFrame injects an auth-approved connection descriptor into the iframe URL; on the hosted page, `connectDevtool()` parses it and returns a fully connected client — no extra wiring. Dev-mode only.
265
-
266
- ## Commands
267
-
268
- ```ts
269
- import { defineCommand } from 'devframe'
270
-
271
- ctx.commands.register(defineCommand({
272
- id: 'my-inspector:clear-cache',
273
- title: 'Clear Cache',
274
- icon: 'ph:trash-duotone',
275
- keybindings: [{ key: 'Mod+Shift+C' }],
276
- when: 'clientType == embedded',
277
- handler: async () => clearCache(),
278
- }))
279
- ```
280
-
281
- - Two-level hierarchy (parent + `children`) max.
282
- - Use `Mod` for platform-aware modifier (Cmd on macOS, Ctrl elsewhere).
283
- - `ctx.commands.execute(id, ...args)` runs a command programmatically.
284
- - `when` is a whenexpr expression — see below.
285
-
286
- ## Logs & notifications
287
-
288
- ```ts
289
- // Fire-and-forget
290
- ctx.messages.add({ message: 'Scan complete', level: 'success', notify: true })
291
-
292
- // With handle for in-place updates
293
- const handle = await ctx.messages.add({
294
- id: 'my-inspector:build',
295
- message: 'Building…',
296
- level: 'info',
297
- status: 'loading',
298
- })
299
- await handle.update({ message: 'Built', level: 'success', status: 'idle' })
300
- ```
301
-
302
- `notify: true` also renders a toast. `filePosition: { file, line, column }` makes the entry click-to-editor. `elementPosition: { selector, boundingBox }` highlights a DOM element. Re-adding with the same `id` updates the existing entry (deduplication pattern).
303
-
304
- ## Terminals
305
-
306
- ```ts
307
- const session = await ctx.terminals.startChildProcess(
308
- { command: 'vite', args: ['build', '--watch'], cwd: process.cwd() },
309
- { id: 'my-inspector:build', title: 'Build', icon: 'ph:terminal-duotone' },
310
- )
311
-
312
- await session.terminate()
313
- await session.restart()
314
- ```
315
-
316
- Color is enabled automatically (`FORCE_COLOR=true`). Output streams into the built-in Terminals panel and is buffered for late-joining clients.
266
+ The kit auto-derives an iframe dock entry from `id` / `name` / `icon` / `basePath`. For dock variations (custom-render, launcher, action, json-render), terminals, palette commands, and toasts, use the `options.setup` hook those APIs live on the kit-augmented context, not on the devframe-level `setup`. See the [`vite-devtools-kit` skill](../../skills/vite-devtools-kit) for the hub-side reference.
317
267
 
318
268
  ## When clauses
319
269
 
320
- Gate dock / command visibility with VS Code-style expressions (evaluated by the external `whenexpr` package):
270
+ Gate kit-side dock / command visibility with VS Code-style expressions. The runtime + types ship bundled from `devframe/utils/when` — no separate install. The consumers (`when` field on docks and commands) live in the kit:
321
271
 
322
272
  ```ts
323
273
  when: 'clientType == embedded'
@@ -325,7 +275,7 @@ when: 'dockOpen && !paletteOpen'
325
275
  when: 'my-inspector.ready && count >= 10'
326
276
  ```
327
277
 
328
- Built-in context: `clientType` (`'embedded' | 'standalone'`), `dockOpen`, `paletteOpen`, `dockSelectedId`. Plugins can add namespaced keys (`.` or `:` separators). Both the types (`WhenExpression<Ctx, S>`) and runtime (`evaluateWhen`, `resolveContextValue`) are re-exported from `devframe/utils/when`.
278
+ Built-in context: `clientType` (`'embedded' | 'standalone'`), `dockOpen`, `paletteOpen`, `dockSelectedId`. Plugins can add namespaced keys (`.` or `:` separators). Both the types (`WhenExpression<Ctx, S>`) and runtime (`evaluateWhen`, `resolveContextValue`) come from `devframe/utils/when`.
329
279
 
330
280
  ## Agent-native surface (experimental)
331
281
 
@@ -369,25 +319,25 @@ Expose via MCP:
369
319
  ```ts
370
320
  import { createMcpServer } from 'devframe/adapters/mcp'
371
321
 
372
- await createMcpServer(devtool, { transport: 'stdio' })
322
+ await createMcpServer(devframe, { transport: 'stdio' })
373
323
  ```
374
324
 
375
- `@modelcontextprotocol/sdk` is a peer dependency. The CLI adapter also exposes `my-devtool mcp` — route host logs to stderr (stdout is the MCP transport). Safety classifications (`'read' | 'action' | 'destructive'`) drive MCP hint annotations that agent clients use to prompt for confirmation.
325
+ `@modelcontextprotocol/sdk` is a peer dependency. The CLI adapter also exposes `my-devframe mcp` — route host logs to stderr (stdout is the MCP transport). Safety classifications (`'read' | 'action' | 'destructive'`) drive MCP hint annotations that agent clients use to prompt for confirmation.
376
326
 
377
327
  ## Author SPA
378
328
 
379
329
  Authors bring their own SPA (any framework or plain HTML). Client entry:
380
330
 
381
331
  ```ts
382
- import { connectDevtool } from 'devframe/client'
332
+ import { connectDevframe } from 'devframe/client'
383
333
 
384
- const rpc = await connectDevtool()
334
+ const rpc = await connectDevframe()
385
335
  // await rpc.ensureTrusted() // WS mode only — blocks until server accepts
386
336
 
387
337
  const data = await rpc.call('my-inspector:get-stats', { limit: 10 })
388
338
  ```
389
339
 
390
- `connectDevtool` auto-detects the backend via `/.devtools/.connection.json`:
340
+ `connectDevframe` auto-detects the backend via `/.devtools/.connection.json`:
391
341
 
392
342
  - **websocket** (dev mode) — full read/write, requires auth handshake. Listen for token updates on the `vite-devtools-auth` BroadcastChannel.
393
343
  - **static** (build / spa output) — read-only, resolves calls from the baked RPC dump.
@@ -416,7 +366,7 @@ At runtime, static clients look up the argument hash in the dump; misses resolve
416
366
 
417
367
  ## CLI adapter subcommands
418
368
 
419
- `createCli(devtool).parse()` gives the tool four subcommands out of the box:
369
+ `createCli(devframe).parse()` gives the tool four subcommands out of the box:
420
370
 
421
371
  | Subcommand | Action |
422
372
  |------------|--------|
@@ -427,26 +377,52 @@ At runtime, static clients look up the argument hash in the dump; misses resolve
427
377
 
428
378
  **Bring your own CLI framework?** `createCli` is just a cac wrapper around three peer factories — `createDevServer` (`devframe/adapters/dev`), `createBuild` (`devframe/adapters/build`), and `createMcpServer` (`devframe/adapters/mcp`). Use them directly with commander/yargs/oclif when `createCli`'s baked-in command structure doesn't fit. `createDevServer` returns a `StartedServer` handle (`origin`, `port`, `app`, `wss`, `close()`) so you can wire SIGINT / hot-reload teardown into the surrounding program. `parseCliFlags(schema, raw)` and `defineCliFlags(...)` (both from `devframe/adapters/cli`) validate an arbitrary flag bag against a `CliFlagsSchema` — typed flags aren't tied to cac.
429
379
 
380
+ ## Bundled utilities
381
+
382
+ Devframe re-exports a curated set of helpers under `devframe/utils/*`. They are bundled — never add the underlying packages to a devtool's own `package.json`:
383
+
384
+ | Import | Wraps | Use for |
385
+ |--------|-------|---------|
386
+ | `colors` from `devframe/utils/colors` | `ansis` | Terminal ANSI colors (`c.red`, `c.green`, tagged templates) |
387
+ | `open` from `devframe/utils/open` | `open` | Open URLs / files in the OS default handler |
388
+ | `launchEditor` from `devframe/utils/launch-editor` | `launch-editor` | Open `file:line:column` in the user's editor (optional `editor` arg) |
389
+ | `hash` from `devframe/utils/hash` | `ohash` | Stable structural hash — cache keys, dedup |
390
+ | `structuredClone{Serialize,Deserialize,Stringify,Parse}` from `devframe/utils/structured-clone` | `structured-clone-es` | JSON-safe round-trip of `Map` / `Set` / `Date` / `BigInt` / cycles |
391
+ | `humanId` from `devframe/utils/human-id` | `human-id` | Human-readable IDs (`bright-orange-tiger`) |
392
+ | `nanoid` from `devframe/utils/nanoid` | (vendored) | URL-safe random IDs |
393
+ | `promiseWithResolver` from `devframe/utils/promise` | — | Externally-controlled `Promise` |
394
+ | `createEventEmitter` from `devframe/utils/events` | — | Typed event bus |
395
+ | `createSharedState` from `devframe/utils/shared-state` | (immer internal) | Immutable state container (see `ctx.rpc.sharedState`) |
396
+ | `createStreamSink` / `createStreamReader` from `devframe/utils/streaming-channel` | — | Low-level streaming primitives |
397
+ | `evaluateWhen` / `WhenExpression` from `devframe/utils/when` | `whenexpr` | When-clause expressions |
398
+
399
+ For "open file in editor" + "reveal in finder", prefer the prebuilt `openHelpers` RPC recipe — it wires the two utilities into named RPC functions ready to register.
400
+
430
401
  ## Testing
431
402
 
432
403
  - Unit-test host classes with fake contexts.
433
- - Run `templates/counter-devtool.ts` under each adapter for integration coverage.
404
+ - Run `templates/counter-devframe.ts` under each adapter for integration coverage.
434
405
  - Snapshot the build-static RPC dump (`<outDir>/.devtools/.rpc-dump/index.json`) to catch accidental drift in `static` function outputs.
435
406
 
436
407
  ## Further reading
437
408
 
438
- All of the above has a dedicated page at [devfra.me](https://devfra.me/):
409
+ Devframe-level pages (one-tool, portable surface):
439
410
 
440
- - [Devtool Definition](https://devfra.me/devtool-definition) — fields, runtime flags, multi-adapter wiring
441
- - [Adapters](https://devfra.me/adapters) — full reference for all seven adapters
411
+ - [Devframe Definition](https://devfra.me/devframe-definition) — fields, runtime flags, multi-adapter wiring
412
+ - [Adapters](https://devfra.me/adapters) — full reference for all deployment adapters
442
413
  - [RPC](https://devfra.me/rpc) — types, schema, broadcasts, dumps
443
414
  - [Shared State](https://devfra.me/shared-state) — patches, events, client-side mutation
444
415
  - [Streaming](https://devfra.me/streaming) — chunked feeds, uploads, replay, Web/Node Streams interop
445
- - [Dock System](https://devfra.me/dock-system) — every entry type + remote docks
446
- - [Commands](https://devfra.me/commands) — palette, keybindings, sub-commands
447
416
  - [When Clauses](https://devfra.me/when-clauses) — syntax, context, type-safe wrappers
448
- - [Messages & Notifications](https://devfra.me/messages) — entry fields, positional hints
449
417
  - [Structured Diagnostics](https://devfra.me/diagnostics) — coded errors via `ctx.diagnostics`, register custom codes
450
- - [Terminals](https://devfra.me/terminals) — child processes, external sessions
418
+ - [Utilities](https://devfra.me/utilities) — bundled `devframe/utils/*` helpers (colors, hash, launchEditor, structured-clone, …)
451
419
  - [Client](https://devfra.me/client) — auth handshake, modes, discovery
452
420
  - [Agent-Native](https://devfra.me/agent-native) — agent field, tools/resources, MCP + Claude Desktop
421
+
422
+ Hub-only surfaces (Vite DevTools Kit — only available when mounted into the hub):
423
+
424
+ - [Vite DevTools Kit overview](https://devtools.vite.dev/kit/)
425
+ - [Dock System](https://devtools.vite.dev/kit/dock-system) — every entry type + remote docks
426
+ - [Commands](https://devtools.vite.dev/kit/commands) — palette, keybindings, sub-commands
427
+ - [Messages & Notifications](https://devtools.vite.dev/kit/messages) — entry fields, positional hints
428
+ - [Terminals](https://devtools.vite.dev/kit/terminals) — child processes, external sessions
@@ -1,9 +1,11 @@
1
- // Smallest possible devtool.
2
- import { defineDevtool, defineRpcFunction } from 'devframe'
1
+ // Smallest possible devframe. The dock entry is auto-derived from
2
+ // `id` / `name` / `icon` when this definition is mounted into Vite
3
+ // DevTools via `createPluginFromDevframe(devframe)`.
4
+ import { defineDevframe, defineRpcFunction } from 'devframe'
3
5
 
4
6
  let counter = 0
5
7
 
6
- export default defineDevtool({
8
+ export default defineDevframe({
7
9
  id: 'counter',
8
10
  name: 'Counter',
9
11
  icon: 'ph:counter-duotone',
@@ -18,12 +20,5 @@ export default defineDevtool({
18
20
  type: 'action',
19
21
  handler: () => ({ count: ++counter }),
20
22
  }))
21
- ctx.docks.register({
22
- id: 'counter',
23
- title: 'Counter',
24
- icon: 'ph:counter-duotone',
25
- type: 'iframe',
26
- url: '/counter/',
27
- })
28
23
  },
29
24
  })
@@ -1,8 +1,10 @@
1
- // Devtool with setupBrowser + SPA query-loader — deployable as a static site.
2
- import { defineDevtool, defineRpcFunction } from 'devframe'
1
+ // Devframe with setupBrowser + SPA query-loader — deployable as a static site.
2
+ // When mounted into Vite DevTools via `createPluginFromDevframe`, the kit
3
+ // auto-derives an iframe dock from `id` / `name` / `icon`.
4
+ import { defineDevframe, defineRpcFunction } from 'devframe'
3
5
  import * as v from 'valibot'
4
6
 
5
- export default defineDevtool({
7
+ export default defineDevframe({
6
8
  id: 'my-inspector',
7
9
  name: 'My Inspector',
8
10
  icon: 'ph:magnifying-glass-duotone',
@@ -16,13 +18,6 @@ export default defineDevtool({
16
18
  return { url, verdict: 'ok' as const }
17
19
  },
18
20
  }))
19
- ctx.docks.register({
20
- id: 'my-inspector',
21
- title: 'My Inspector',
22
- icon: 'ph:magnifying-glass-duotone',
23
- type: 'iframe',
24
- url: '/my-inspector/',
25
- })
26
21
  },
27
22
  setupBrowser() {
28
23
  // Browser-side implementation — used by the SPA adapter so the
@@ -1,8 +1,8 @@
1
1
  // Minimum SPA client that talks to a devframe-hosted RPC.
2
- import { connectDevtool } from 'devframe/client'
2
+ import { connectDevframe } from 'devframe/client'
3
3
 
4
4
  async function main() {
5
- const rpc = await connectDevtool()
5
+ const rpc = await connectDevframe()
6
6
  // The method names below are just examples — replace with your own.
7
7
  const data = await rpc.call('my-inspector:getStats' as any)
8
8
  document.getElementById('root')!.textContent = JSON.stringify(data)
@@ -1,23 +0,0 @@
1
- import { r as DevtoolDefinition } from "../devtool-Bm6zZAw5.mjs";
2
-
3
- //#region src/adapters/kit.d.ts
4
- interface CreateKitPluginOptions {
5
- /**
6
- * Optional plugin name override. Defaults to `devframe:<devtool-id>`.
7
- */
8
- name?: string;
9
- }
10
- interface KitPlugin {
11
- name: string;
12
- devtools: {
13
- setup: DevtoolDefinition['setup'];
14
- capabilities?: DevtoolDefinition['capabilities'];
15
- };
16
- }
17
- /**
18
- * Produce a Vite plugin object that Kit's plugin-scan picks up via
19
- * `Plugin.devtools`.
20
- */
21
- declare function createKitPlugin(d: DevtoolDefinition, options?: CreateKitPluginOptions): KitPlugin;
22
- //#endregion
23
- export { CreateKitPluginOptions, KitPlugin, createKitPlugin };
@@ -1,16 +0,0 @@
1
- //#region src/adapters/kit.ts
2
- /**
3
- * Produce a Vite plugin object that Kit's plugin-scan picks up via
4
- * `Plugin.devtools`.
5
- */
6
- function createKitPlugin(d, options = {}) {
7
- return {
8
- name: options.name ?? `devframe:${d.id}`,
9
- devtools: {
10
- setup: d.setup,
11
- capabilities: d.capabilities
12
- }
13
- };
14
- }
15
- //#endregion
16
- export { createKitPlugin };