@ubean/devtools 0.6.2 → 0.6.4
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.
- package/README.md +209 -0
- package/README.zh-CN.md +209 -0
- package/dist/client/assets/{browser-agent-rpc-BXhoSh1z-2YZkPEaj.js → browser-agent-rpc-BXhoSh1z-BTqFol0H.js} +1 -1
- package/dist/client/assets/index-CqTOBCCw.js +82 -0
- package/dist/client/index.html +1 -1
- package/package.json +11 -11
- package/dist/client/assets/index-B9lST-pU.js +0 -82
package/README.md
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
# @ubean/devtools
|
|
2
|
+
|
|
3
|
+
**English | [中文](./README.zh-CN.md)**
|
|
4
|
+
|
|
5
|
+
Dev-time visual panel for ubean — routes, pages, API, config, database, terminal and AI, hosted on a devframe hub.
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { createUbeanDevframe, ubeanDevtoolsPlugin } from '@ubean/devtools';
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Table of Contents
|
|
12
|
+
|
|
13
|
+
- [@ubean/devtools](#ubeandevtools)
|
|
14
|
+
- [Package Positioning](#package-positioning)
|
|
15
|
+
- [Install](#install)
|
|
16
|
+
- [Quick Start](#quick-start)
|
|
17
|
+
- [Devframe Integration](#devframe-integration)
|
|
18
|
+
- [RPC Layer](#rpc-layer)
|
|
19
|
+
- [Custom Tabs](#custom-tabs)
|
|
20
|
+
- [File Operations](#file-operations)
|
|
21
|
+
- [Type Safety](#type-safety)
|
|
22
|
+
- [Architecture Notes](#architecture-notes)
|
|
23
|
+
|
|
24
|
+
## Package Positioning
|
|
25
|
+
|
|
26
|
+
| Layer | Responsibility |
|
|
27
|
+
| ------------------------- | ----------------------------------------------------------------------------- |
|
|
28
|
+
| `@ubean/devtools` (node) | The ubean devframe definition, the Vite plugin, RPC function aggregation |
|
|
29
|
+
| `@ubean/devtools` (rpc) | Server-side CRUD / terminal / AI servers exposed over the hub's RPC transport |
|
|
30
|
+
| `@ubean/devtools` (panel) | The prebuilt iframe SPA served by the hub as the devframe's client assets |
|
|
31
|
+
|
|
32
|
+
**Included:**
|
|
33
|
+
|
|
34
|
+
- `ubeanDevtoolsPlugin` / `createUbeanDevframe` — the plugin you add to the dev pipeline and the `DevframeDefinition` it produces.
|
|
35
|
+
- `createAllRpcFunctions` — aggregates every DevTools RPC method (info, env, CRUD, playground, terminal, AI).
|
|
36
|
+
- `createCrudServer`, `createAiServer`, `createTerminalServer`, `createDevToolsHooks` — the individual servers, usable on their own.
|
|
37
|
+
- `buildDevToolsInfo` / `emptyDevToolsInfo` / `maskSensitiveEnv` — the snapshot pushed to the panel.
|
|
38
|
+
- `defineDevToolsTab` / `getCustomTabs` / `clearCustomTabs` — the custom tab registry.
|
|
39
|
+
- The namespace constants `UBEAN_RPC_NAMESPACE`, `UBEAN_INFO_STATE_KEY`, `UBEAN_AI_STREAM_STATE_KEY`, `UBEAN_ANCHOR_DOCK`.
|
|
40
|
+
|
|
41
|
+
**NOT included** (deliberately):
|
|
42
|
+
|
|
43
|
+
- No dependency on the aggregate `ubean` package. `@ubean/devtools` declares **no peer on `ubean`** — that would create a cycle with `@ubean/cli`. All the data it needs (cwd, app fetcher, scan result, config meta) is injected through `UbeanDevtoolsPluginOptions`.
|
|
44
|
+
- No RPC transport of its own. WebSocket transport, the dock shell, frame navigation and authentication come from the devframe hub (`@devframes/hub`).
|
|
45
|
+
- No production code. DevTools is dev-time only — production builds emit no DevTools code and pay no runtime overhead.
|
|
46
|
+
- No hard dependency in the aggregate package. It is opt-in: install it explicitly.
|
|
47
|
+
- No hook registration entry point yet. `createDevToolsHooks()` builds the registry and is currently called internally by the plugin; config-level registration is not exposed.
|
|
48
|
+
|
|
49
|
+
**Runtime dependency whitelist (main entry):** `hookable`, `pathe`.
|
|
50
|
+
|
|
51
|
+
**Optional peers:** `hono` (`^4.0.0`) and `vue` (`^3.0.0`), both marked optional. `ai` / `@ai-sdk/openai-compatible` are optional dependencies used only by the AI view — without them the AI view is unavailable and every other view keeps working.
|
|
52
|
+
|
|
53
|
+
## Install
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
# opt-in: not part of the aggregate ubean dependency graph
|
|
57
|
+
pnpm add -D @ubean/devtools
|
|
58
|
+
|
|
59
|
+
# peers, if you use the parts that need them
|
|
60
|
+
pnpm add hono # hosting the RPC servers on a Hono app
|
|
61
|
+
pnpm add vue # the panel client
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Quick Start
|
|
65
|
+
|
|
66
|
+
**1. Enable DevTools**
|
|
67
|
+
|
|
68
|
+
```ts
|
|
69
|
+
// ubean.config.ts
|
|
70
|
+
import { defineConfig } from 'ubean';
|
|
71
|
+
|
|
72
|
+
export default defineConfig({
|
|
73
|
+
devtools: {
|
|
74
|
+
enabled: true,
|
|
75
|
+
route: '/_devtools',
|
|
76
|
+
ai: { enabled: false }
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
**2. Open the panel**
|
|
82
|
+
|
|
83
|
+
Open the URL printed in the dev server banner — by default `/_devtools`, which 302-redirects to the devframe hub shell. The panel renders as an iframe in the hub's dock sidebar; no floating button and no client script are injected into your app pages.
|
|
84
|
+
|
|
85
|
+
The CLI prints the same information:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
ubean devtools info # how to reach it, available features, config
|
|
89
|
+
ubean devtools path --port 9527 # print the URL path
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Built-in views: Overview, Pages, API, Middleware, Crons, Config, Env, API Docs, Database, Terminal and AI.
|
|
93
|
+
|
|
94
|
+
**3. Register a custom tab**
|
|
95
|
+
|
|
96
|
+
```ts
|
|
97
|
+
import { defineDevToolsTab } from '@ubean/devtools';
|
|
98
|
+
|
|
99
|
+
defineDevToolsTab({
|
|
100
|
+
id: 'my-panel',
|
|
101
|
+
label: 'My Panel',
|
|
102
|
+
icon: 'lucide:puzzle',
|
|
103
|
+
src: '/my-panel/index.html',
|
|
104
|
+
sandbox: ['allow-scripts', 'allow-same-origin']
|
|
105
|
+
});
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Devframe Integration
|
|
109
|
+
|
|
110
|
+
`@ubean/devtools` is a devframe, not a standalone server. `createUbeanDevframe(options)` returns a `DevframeDefinition` describing the panel; the host (the devframe hub) owns the shell, the dock sidebar, the RPC transport and authentication.
|
|
111
|
+
|
|
112
|
+
| Option | Purpose |
|
|
113
|
+
| ----------------- | ---------------------------------------------------------------- |
|
|
114
|
+
| `getCwd` | Project root — required. |
|
|
115
|
+
| `getApp` | The running app's `fetch`, so the panel can invoke your routes. |
|
|
116
|
+
| `getScanResult` | Current scan result (routes, pages, middleware, layouts, crons). |
|
|
117
|
+
| `getConfigMeta` | Resolved config metadata (preset, dirs, OpenAPI settings). |
|
|
118
|
+
| `getCustomTabs` | Custom tabs to surface in the panel. |
|
|
119
|
+
| `scaffoldOps` | File operations used by the create/update/delete flows. |
|
|
120
|
+
| `ai` | `{ apiKey, apiBase, model }` for the AI view. |
|
|
121
|
+
| `triggerRescan` | Ask the dev runner to rescan the project. |
|
|
122
|
+
| `registerRefresh` | Receive a callback the panel can call to refresh its data. |
|
|
123
|
+
| `basePath` | Panel base path, default `/_devtools/`. |
|
|
124
|
+
|
|
125
|
+
Reserved route namespaces:
|
|
126
|
+
|
|
127
|
+
- `/__devframes/**` — the hub namespace: shell, `__connection.json`, `__ws` WebSocket, and each devframe's artifacts under `/__devframes/ubean/`.
|
|
128
|
+
- `/_devtools` — the user-visible entry; 302-redirects to the hub shell.
|
|
129
|
+
- `/__devtools*` — kept only for projects still on `@vitejs/devtools`.
|
|
130
|
+
|
|
131
|
+
Framework HTML pages (`/_devtools`, `/_scalar`, everything under `/__devframes/**`) are skipped by the app's HTML transform. Without that skip the app client entry would be injected into a page with no `#app`, and the hub shell — which ships its own `embedded.js` — would boot twice.
|
|
132
|
+
|
|
133
|
+
## RPC Layer
|
|
134
|
+
|
|
135
|
+
The transport belongs to the hub. `createAllRpcFunctions` aggregates the methods ubean registers under the `ubean` scope; wire names are `ubean:<bare-name>`.
|
|
136
|
+
|
|
137
|
+
| RPC | Kind | Description |
|
|
138
|
+
| ------------------------- | -------- | ---------------------------------------------------------------- |
|
|
139
|
+
| `ubean:get-info` | query | The `DevToolsInfo` snapshot (routes, pages, config, counts). |
|
|
140
|
+
| `ubean:get-env` | query | Environment variables, sensitive keys masked. |
|
|
141
|
+
| `ubean:crud-read` | query | Read a page / API / layout / middleware / reuse / cron resource. |
|
|
142
|
+
| `ubean:crud-create` | mutation | Create a scaffolded resource. |
|
|
143
|
+
| `ubean:crud-update` | mutation | Update a resource. |
|
|
144
|
+
| `ubean:crud-delete` | mutation | Delete a resource (backup kept). |
|
|
145
|
+
| `ubean:crud-restore` | mutation | Restore a resource from backup. |
|
|
146
|
+
| `ubean:playground-invoke` | mutation | Invoke an API route from the panel. |
|
|
147
|
+
|
|
148
|
+
Client-side, connect to the hub and call through the scope:
|
|
149
|
+
|
|
150
|
+
```ts
|
|
151
|
+
import { connectDevframe } from '@devframes/hub/client';
|
|
152
|
+
|
|
153
|
+
const client = await connectDevframe();
|
|
154
|
+
const result = await client.call('ubean:crud-read', { type: 'page', path: 'src/pages/index.vue' });
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Volatile data (for example the info snapshot or the AI stream) is published through shared state instead of being polled:
|
|
158
|
+
|
|
159
|
+
```ts
|
|
160
|
+
const info = client.sharedState.get(UBEAN_INFO_STATE_KEY);
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
`UBEAN_RPC_NAMESPACE` is `'ubean'`, `UBEAN_INFO_STATE_KEY` is `'ubean:info'`, and `UBEAN_AI_STREAM_STATE_KEY` is `'ubean:ai:stream'`.
|
|
164
|
+
|
|
165
|
+
`CrudResult` reports `{ success, created?, deleted?, restored?, updated?, skipped?, errors? }` so the panel can show exactly what changed.
|
|
166
|
+
|
|
167
|
+
## Custom Tabs
|
|
168
|
+
|
|
169
|
+
`DevToolsTabDefinition` is `{ id, label, icon?, src, sandbox? }` — `src` points at the tab's HTML entry and `sandbox` maps to the iframe sandbox attributes.
|
|
170
|
+
|
|
171
|
+
| Export | Description |
|
|
172
|
+
| ------------------------ | ------------------------------------------------------------ |
|
|
173
|
+
| `defineDevToolsTab(tab)` | Register (or replace by `id`) a custom tab; returns the tab. |
|
|
174
|
+
| `getCustomTabs()` | Snapshot of the registered tabs. |
|
|
175
|
+
| `clearCustomTabs()` | Empty the registry. |
|
|
176
|
+
|
|
177
|
+
The registry is a process singleton stored on `globalThis`. In dev the same process often holds two copies of this package (the CLI imports it dynamically, your `vite.config.ts` imports it statically), so a module-level array would silently show a tab as "registered but never visible".
|
|
178
|
+
|
|
179
|
+
## File Operations
|
|
180
|
+
|
|
181
|
+
Everything that writes to disk goes through the same safety policies:
|
|
182
|
+
|
|
183
|
+
1. **AST-first** — structural edits rather than text splicing.
|
|
184
|
+
2. **Backup before change** — the previous file is copied to `.ubean/backup/`.
|
|
185
|
+
3. **Transactional writes** — write a temporary file, then rename.
|
|
186
|
+
4. **Path constraints** — only the project root and an allowlist.
|
|
187
|
+
5. **Least privilege for AI** — read-only by default; writes require a diff and explicit confirmation.
|
|
188
|
+
6. **Operation confirmation** — deletes and bulk operations need a second confirmation.
|
|
189
|
+
7. **Git detection** — DevTools advises committing first; it never auto-commits.
|
|
190
|
+
|
|
191
|
+
`createDevToolsHooks()` provides six lifecycle hooks — `beforeCreate`, `afterCreate`, `beforeUpdate`, `afterUpdate`, `beforeDelete`, `afterDelete` — each receiving a `CrudHookContext` with `{ type, path?, key?, content?, value? }`.
|
|
192
|
+
|
|
193
|
+
## Type Safety
|
|
194
|
+
|
|
195
|
+
- `UbeanDevtoolsPluginOptions` is a structural contract, which is what lets this package avoid a static dependency on `ubean` — the dev runner injects the data.
|
|
196
|
+
- `DevToolsInfo` types the snapshot shared with the panel, including the optional `routes`, `pagesList`, `middlewaresList`, `layoutsList`, `cronsList`, `customTabs`, `openAPI`, `database` and `ai` sections.
|
|
197
|
+
- `CrudResourceType` (`'page' | 'api' | 'layout' | 'middleware' | 'reuse' | 'cron' | 'plugin'`) and `DevToolsScaffoldType` keep resource names closed unions.
|
|
198
|
+
- `RpcRequest` / `RpcResponse<T>` and `RpcHandler` describe the call shape crossing the hub boundary.
|
|
199
|
+
- The package augments the hub client's types, so `client.call(...)` and `client.sharedState.get(...)` are typed on both server and client.
|
|
200
|
+
|
|
201
|
+
## Architecture Notes
|
|
202
|
+
|
|
203
|
+
- **Devframe, not a server.** `@ubean/devtools` contributes a `DevframeDefinition`; the hub owns the shell, dock and transport. The panel is an iframe, not an injected script.
|
|
204
|
+
- **No `ubean` peer.** Data arrives through injected getters, which keeps the dependency direction one-way and avoids a cycle with `@ubean/cli`.
|
|
205
|
+
- **Opt-in by construction.** The aggregate package does not depend on DevTools; production builds contain none of it.
|
|
206
|
+
- **The panel declares its own views.** The client posts a view manifest to the hub shell over frame navigation, and the shell composes the dock buttons — the server hardcodes no view list.
|
|
207
|
+
- **`globalThis` registries where dev holds two copies.** Custom tabs use a process singleton for the same reason the islands server-component registry does.
|
|
208
|
+
- **Backups are part of the contract.** Every mutation is reversible: delete writes a backup, restore reads it back.
|
|
209
|
+
- **AI drives RPC, not files.** The assistant calls the same RPC methods the panel uses, so the file-safety policies apply uniformly.
|
package/README.zh-CN.md
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
# @ubean/devtools
|
|
2
|
+
|
|
3
|
+
**[English](./README.md) | 中文**
|
|
4
|
+
|
|
5
|
+
ubean 的 dev 期可视化面板 —— 路由、页面、API、配置、数据库、终端与 AI,托管在 devframe hub 上。
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { createUbeanDevframe, ubeanDevtoolsPlugin } from '@ubean/devtools';
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## 目录
|
|
12
|
+
|
|
13
|
+
- [@ubean/devtools](#ubeandevtools)
|
|
14
|
+
- [包定位](#包定位)
|
|
15
|
+
- [安装](#安装)
|
|
16
|
+
- [快速开始](#快速开始)
|
|
17
|
+
- [devframe 集成](#devframe-集成)
|
|
18
|
+
- [RPC 层](#rpc-层)
|
|
19
|
+
- [自定义 tab](#自定义-tab)
|
|
20
|
+
- [文件操作](#文件操作)
|
|
21
|
+
- [类型安全](#类型安全)
|
|
22
|
+
- [架构说明](#架构说明)
|
|
23
|
+
|
|
24
|
+
## 包定位
|
|
25
|
+
|
|
26
|
+
| 分层 | 职责 |
|
|
27
|
+
| -------------------------- | --------------------------------------------------------------- |
|
|
28
|
+
| `@ubean/devtools`(node) | ubean 的 devframe 定义、Vite 插件、RPC 函数聚合 |
|
|
29
|
+
| `@ubean/devtools`(rpc) | 通过 hub 的 RPC 传输暴露的 CRUD / terminal / AI 服务端 |
|
|
30
|
+
| `@ubean/devtools`(panel) | 由 hub 作为该 devframe 的 client assets 提供的预构建 iframe SPA |
|
|
31
|
+
|
|
32
|
+
**包含:**
|
|
33
|
+
|
|
34
|
+
- `ubeanDevtoolsPlugin` / `createUbeanDevframe` —— 加入 dev 流水线的插件,以及它产出的 `DevframeDefinition`。
|
|
35
|
+
- `createAllRpcFunctions` —— 聚合全部 DevTools RPC 方法(info、env、CRUD、playground、terminal、AI)。
|
|
36
|
+
- `createCrudServer`、`createAiServer`、`createTerminalServer`、`createDevToolsHooks` —— 各个服务端模块,可单独使用。
|
|
37
|
+
- `buildDevToolsInfo` / `emptyDevToolsInfo` / `maskSensitiveEnv` —— 推送给面板的快照。
|
|
38
|
+
- `defineDevToolsTab` / `getCustomTabs` / `clearCustomTabs` —— 自定义 tab 注册表。
|
|
39
|
+
- 命名空间常量 `UBEAN_RPC_NAMESPACE`、`UBEAN_INFO_STATE_KEY`、`UBEAN_AI_STREAM_STATE_KEY`、`UBEAN_ANCHOR_DOCK`。
|
|
40
|
+
|
|
41
|
+
**不包含**(刻意为之):
|
|
42
|
+
|
|
43
|
+
- 不依赖聚合包 `ubean`。`@ubean/devtools` **不对 `ubean` 声明 peer** —— 那会与 `@ubean/cli` 形成环。它需要的数据(cwd、app fetcher、scan 结果、config meta)全部通过 `UbeanDevtoolsPluginOptions` 注入。
|
|
44
|
+
- 不自带 RPC 传输。WebSocket 传输、dock 外壳、frame 导航与鉴权都由 devframe hub(`@devframes/hub`)提供。
|
|
45
|
+
- 不含生产代码。DevTools 只在 dev 期存在 —— 生产构建不输出任何 DevTools 代码,零运行时开销。
|
|
46
|
+
- 不进聚合包硬依赖。它是 opt-in:需要时显式安装。
|
|
47
|
+
- 尚无 hook 注册入口。`createDevToolsHooks()` 构建注册表,目前由插件内部调用;配置级注册尚未对外暴露。
|
|
48
|
+
|
|
49
|
+
**运行时依赖白名单(主入口):** `hookable`、`pathe`。
|
|
50
|
+
|
|
51
|
+
**可选 peer:** `hono`(`^4.0.0`)与 `vue`(`^3.0.0`),两者都标记为 optional。`ai` / `@ai-sdk/openai-compatible` 是可选依赖,仅 AI 视图使用 —— 缺少它们时 AI 视图不可用,其余视图照常工作。
|
|
52
|
+
|
|
53
|
+
## 安装
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
# opt-in:不在聚合包 ubean 的依赖图里
|
|
57
|
+
pnpm add -D @ubean/devtools
|
|
58
|
+
|
|
59
|
+
# peer,用到对应能力时才需要
|
|
60
|
+
pnpm add hono # 在 Hono 应用上托管 RPC 服务端
|
|
61
|
+
pnpm add vue # 面板客户端
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## 快速开始
|
|
65
|
+
|
|
66
|
+
**1. 启用 DevTools**
|
|
67
|
+
|
|
68
|
+
```ts
|
|
69
|
+
// ubean.config.ts
|
|
70
|
+
import { defineConfig } from 'ubean';
|
|
71
|
+
|
|
72
|
+
export default defineConfig({
|
|
73
|
+
devtools: {
|
|
74
|
+
enabled: true,
|
|
75
|
+
route: '/_devtools',
|
|
76
|
+
ai: { enabled: false }
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
**2. 打开面板**
|
|
82
|
+
|
|
83
|
+
打开 dev server banner 里打印的 URL —— 默认是 `/_devtools`,会 302 跳转到 devframe hub 外壳。面板以 iframe 形式渲染在 hub 的 dock 侧栏中;不会往你的应用页面注入浮动按钮或客户端脚本。
|
|
84
|
+
|
|
85
|
+
CLI 会打印同样的信息:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
ubean devtools info # 如何访问、可用功能、配置
|
|
89
|
+
ubean devtools path --port 9527 # 打印 URL 路径
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
内置视图:Overview、Pages、API、Middleware、Crons、Config、Env、API Docs、Database、Terminal 与 AI。
|
|
93
|
+
|
|
94
|
+
**3. 注册自定义 tab**
|
|
95
|
+
|
|
96
|
+
```ts
|
|
97
|
+
import { defineDevToolsTab } from '@ubean/devtools';
|
|
98
|
+
|
|
99
|
+
defineDevToolsTab({
|
|
100
|
+
id: 'my-panel',
|
|
101
|
+
label: 'My Panel',
|
|
102
|
+
icon: 'lucide:puzzle',
|
|
103
|
+
src: '/my-panel/index.html',
|
|
104
|
+
sandbox: ['allow-scripts', 'allow-same-origin']
|
|
105
|
+
});
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## devframe 集成
|
|
109
|
+
|
|
110
|
+
`@ubean/devtools` 是一个 devframe,而不是独立服务器。`createUbeanDevframe(options)` 返回描述该面板的 `DevframeDefinition`;宿主(devframe hub)拥有外壳、dock 侧栏、RPC 传输与鉴权。
|
|
111
|
+
|
|
112
|
+
| 选项 | 用途 |
|
|
113
|
+
| ----------------- | -------------------------------------------------- |
|
|
114
|
+
| `getCwd` | 项目根目录 —— 必填。 |
|
|
115
|
+
| `getApp` | 运行中应用的 `fetch`,让面板可以调用你的路由。 |
|
|
116
|
+
| `getScanResult` | 当前 scan 结果(路由、页面、中间件、布局、cron)。 |
|
|
117
|
+
| `getConfigMeta` | 解析后的配置元信息(preset、目录、OpenAPI 设置)。 |
|
|
118
|
+
| `getCustomTabs` | 要在面板中展示的自定义 tab。 |
|
|
119
|
+
| `scaffoldOps` | 创建/更新/删除流程使用的文件操作。 |
|
|
120
|
+
| `ai` | AI 视图的 `{ apiKey, apiBase, model }`。 |
|
|
121
|
+
| `triggerRescan` | 请求 dev runner 重新扫描项目。 |
|
|
122
|
+
| `registerRefresh` | 接收一个面板可调用以刷新数据的回调。 |
|
|
123
|
+
| `basePath` | 面板基础路径,默认 `/_devtools/`。 |
|
|
124
|
+
|
|
125
|
+
保留的路由命名空间:
|
|
126
|
+
|
|
127
|
+
- `/__devframes/**` —— hub 命名空间:外壳、`__connection.json`、`__ws` WebSocket,以及各 devframe 的产物(`/__devframes/ubean/`)。
|
|
128
|
+
- `/_devtools` —— 用户可见入口;302 跳转到 hub 外壳。
|
|
129
|
+
- `/__devtools*` —— 仅为仍在使用 `@vitejs/devtools` 的项目保留。
|
|
130
|
+
|
|
131
|
+
框架内置 HTML 页面(`/_devtools`、`/_scalar`、`/__devframes/**` 下的一切)会被应用的 HTML transform 跳过。没有这个跳过,应用客户端入口会被注入到没有 `#app` 的页面上;而自带 `embedded.js` 的 hub 外壳会启动两次。
|
|
132
|
+
|
|
133
|
+
## RPC 层
|
|
134
|
+
|
|
135
|
+
传输属于 hub。`createAllRpcFunctions` 聚合 ubean 注册在 `ubean` scope 下的方法;wire 名为 `ubean:<裸名>`。
|
|
136
|
+
|
|
137
|
+
| RPC | 类型 | 说明 |
|
|
138
|
+
| ------------------------- | -------- | ----------------------------------------------------------- |
|
|
139
|
+
| `ubean:get-info` | query | `DevToolsInfo` 快照(路由、页面、配置、计数)。 |
|
|
140
|
+
| `ubean:get-env` | query | 环境变量,敏感键已打码。 |
|
|
141
|
+
| `ubean:crud-read` | query | 读取 page / api / layout / middleware / reuse / cron 资源。 |
|
|
142
|
+
| `ubean:crud-create` | mutation | 创建脚手架资源。 |
|
|
143
|
+
| `ubean:crud-update` | mutation | 更新资源。 |
|
|
144
|
+
| `ubean:crud-delete` | mutation | 删除资源(保留备份)。 |
|
|
145
|
+
| `ubean:crud-restore` | mutation | 从备份恢复资源。 |
|
|
146
|
+
| `ubean:playground-invoke` | mutation | 从面板调用某个 API 路由。 |
|
|
147
|
+
|
|
148
|
+
客户端侧连接 hub 并通过 scope 调用:
|
|
149
|
+
|
|
150
|
+
```ts
|
|
151
|
+
import { connectDevframe } from '@devframes/hub/client';
|
|
152
|
+
|
|
153
|
+
const client = await connectDevframe();
|
|
154
|
+
const result = await client.call('ubean:crud-read', { type: 'page', path: 'src/pages/index.vue' });
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
易变数据(例如 info 快照或 AI 流)通过 shared state 发布,而不是轮询:
|
|
158
|
+
|
|
159
|
+
```ts
|
|
160
|
+
const info = client.sharedState.get(UBEAN_INFO_STATE_KEY);
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
`UBEAN_RPC_NAMESPACE` 为 `'ubean'`,`UBEAN_INFO_STATE_KEY` 为 `'ubean:info'`,`UBEAN_AI_STREAM_STATE_KEY` 为 `'ubean:ai:stream'`。
|
|
164
|
+
|
|
165
|
+
`CrudResult` 报告 `{ success, created?, deleted?, restored?, updated?, skipped?, errors? }`,让面板能准确展示变更内容。
|
|
166
|
+
|
|
167
|
+
## 自定义 tab
|
|
168
|
+
|
|
169
|
+
`DevToolsTabDefinition` 为 `{ id, label, icon?, src, sandbox? }` —— `src` 指向 tab 的 HTML 入口,`sandbox` 映射到 iframe 的 sandbox 属性。
|
|
170
|
+
|
|
171
|
+
| 导出 | 说明 |
|
|
172
|
+
| ------------------------ | ---------------------------------------------- |
|
|
173
|
+
| `defineDevToolsTab(tab)` | 注册(或按 `id` 替换)自定义 tab;返回该 tab。 |
|
|
174
|
+
| `getCustomTabs()` | 已注册 tab 的快照。 |
|
|
175
|
+
| `clearCustomTabs()` | 清空注册表。 |
|
|
176
|
+
|
|
177
|
+
注册表是挂在 `globalThis` 上的进程单例。dev 下同一进程常常存在两份本包(CLI 动态导入一份、你的 `vite.config.ts` 静态导入一份),模块级数组会让 tab 静默表现为「已注册但永不显示」。
|
|
178
|
+
|
|
179
|
+
## 文件操作
|
|
180
|
+
|
|
181
|
+
所有写盘操作都走同一套安全策略:
|
|
182
|
+
|
|
183
|
+
1. **AST 优先** —— 结构化编辑,而非文本拼接。
|
|
184
|
+
2. **改前备份** —— 旧文件先复制到 `.ubean/backup/`。
|
|
185
|
+
3. **事务写入** —— 先写临时文件,再 rename。
|
|
186
|
+
4. **路径约束** —— 仅限项目根目录与允许清单。
|
|
187
|
+
5. **AI 最小权限** —— 默认只读;写入需先给出 diff 并显式确认。
|
|
188
|
+
6. **操作确认** —— 删除与批量操作需要二次确认。
|
|
189
|
+
7. **git 检测** —— DevTools 建议先提交,但绝不自动提交。
|
|
190
|
+
|
|
191
|
+
`createDevToolsHooks()` 提供六个生命周期 hook —— `beforeCreate`、`afterCreate`、`beforeUpdate`、`afterUpdate`、`beforeDelete`、`afterDelete` —— 每个都收到 `CrudHookContext`,含 `{ type, path?, key?, content?, value? }`。
|
|
192
|
+
|
|
193
|
+
## 类型安全
|
|
194
|
+
|
|
195
|
+
- `UbeanDevtoolsPluginOptions` 是一份结构化契约,本包因此可以不静态依赖 `ubean` —— 数据由 dev runner 注入。
|
|
196
|
+
- `DevToolsInfo` 为与面板共享的快照提供类型,包含可选的 `routes`、`pagesList`、`middlewaresList`、`layoutsList`、`cronsList`、`customTabs`、`openAPI`、`database`、`ai` 各段。
|
|
197
|
+
- `CrudResourceType`(`'page' | 'api' | 'layout' | 'middleware' | 'reuse' | 'cron' | 'plugin'`)与 `DevToolsScaffoldType` 让资源名保持为闭合联合。
|
|
198
|
+
- `RpcRequest` / `RpcResponse<T>` 与 `RpcHandler` 描述跨 hub 边界的调用形状。
|
|
199
|
+
- 本包对 hub client 的类型做了模块增强,因此 `client.call(...)` 与 `client.sharedState.get(...)` 在服务端与客户端都有类型。
|
|
200
|
+
|
|
201
|
+
## 架构说明
|
|
202
|
+
|
|
203
|
+
- **是 devframe,不是服务器。** `@ubean/devtools` 贡献一个 `DevframeDefinition`;外壳、dock 与传输归 hub。面板是 iframe,不是注入脚本。
|
|
204
|
+
- **不对 `ubean` 声明 peer。** 数据通过注入的 getter 到达,依赖方向保持单向,也避免了与 `@ubean/cli` 成环。
|
|
205
|
+
- **构造上就是 opt-in。** 聚合包不依赖 DevTools;生产构建里没有它的任何代码。
|
|
206
|
+
- **面板自己声明视图。** 客户端通过 frame 导航把视图清单发给 hub 外壳,外壳据此组装 dock 按钮 —— 服务端不硬编码视图列表。
|
|
207
|
+
- **dev 存在两份副本的地方用 `globalThis` 注册表。** 自定义 tab 使用进程单例,原因与 islands 的 server component 注册表相同。
|
|
208
|
+
- **备份是契约的一部分。** 每个变更都可回滚:删除会写备份,恢复会读回。
|
|
209
|
+
- **AI 驱动 RPC,不直接改文件。** 助手调用的是面板用的同一批 RPC 方法,因此文件安全策略统一生效。
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{t as e}from"./index-
|
|
1
|
+
import{t as e}from"./index-CqTOBCCw.js";var t=Symbol.for(`devframe:browser-agent-registry`),{tools:n,listeners:r}=globalThis[t]??={tools:new Map,listeners:new Set};function i(){return[...n.values()]}function a(e){return r.add(e),()=>r.delete(e)}var o=`devframe:client-id`,s;function c(t=globalThis.window){try{let n=t?.sessionStorage;if(n){let t=n.getItem(o);return t||(t=e(),n.setItem(o,t)),t}}catch{}return s??=e(),s}function l(e){e.client.register({name:`devframe:agent:invoke-client-tool`,type:`action`,jsonSerializable:!0,handler:async(e,t)=>{let n=i().find(t=>t.id===e);if(!n)throw Error(`[devframe/agent] browser tool "${e}" not found`);return await n.invoke(t)}});let t=!1,n=!1,r=0,o=()=>{t||n||(t=!0,queueMicrotask(async()=>{if(t=!1,n)return;let a=i().map(({invoke:e,...t})=>t);(a.length!==0||r!==0)&&(r=a.length,await e.callOptional(`devframe:agent:sync-client-tools`,c(),a).catch(()=>{}))}))},s=a(o),l=e.events.on(`connection:status`,e=>{e===`connected`&&o()});return o(),()=>{n=!0,s(),l()}}export{l as setupBrowserAgentRpcBridge};
|