@dimina-kit/devtools 0.3.1 → 0.3.2-dev.20260522085907

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 (190) hide show
  1. package/README.md +297 -133
  2. package/dist/main/api.d.ts +6 -2
  3. package/dist/main/api.js +5 -2
  4. package/dist/main/app/app.d.ts +1 -1
  5. package/dist/main/app/app.js +84 -36
  6. package/dist/main/app/bootstrap.js +2 -1
  7. package/dist/main/app/launch.d.ts +2 -2
  8. package/dist/main/app/launch.js +10 -8
  9. package/dist/main/index.bundle.js +1567 -477
  10. package/dist/main/ipc/app.d.ts +2 -1
  11. package/dist/main/ipc/app.js +5 -4
  12. package/dist/main/ipc/index.d.ts +5 -4
  13. package/dist/main/ipc/index.js +5 -4
  14. package/dist/main/ipc/panels.d.ts +2 -1
  15. package/dist/main/ipc/panels.js +16 -13
  16. package/dist/main/ipc/popover.d.ts +4 -1
  17. package/dist/main/ipc/popover.js +15 -5
  18. package/dist/main/ipc/projects.d.ts +6 -1
  19. package/dist/main/ipc/projects.js +127 -6
  20. package/dist/main/ipc/session.d.ts +4 -1
  21. package/dist/main/ipc/session.js +34 -6
  22. package/dist/main/ipc/settings.d.ts +4 -1
  23. package/dist/main/ipc/settings.js +51 -23
  24. package/dist/main/ipc/simulator-module.d.ts +8 -0
  25. package/dist/main/ipc/simulator-module.js +19 -0
  26. package/dist/main/ipc/simulator.d.ts +2 -1
  27. package/dist/main/ipc/simulator.js +23 -18
  28. package/dist/main/ipc/toolbar.d.ts +2 -1
  29. package/dist/main/ipc/toolbar.js +3 -2
  30. package/dist/main/menu/index.js +11 -0
  31. package/dist/main/services/automation/exec.d.ts +2 -0
  32. package/dist/main/services/automation/exec.js +7 -9
  33. package/dist/main/services/automation/handlers/app.js +37 -51
  34. package/dist/main/services/automation/handlers/element.js +27 -41
  35. package/dist/main/services/automation/index.js +88 -13
  36. package/dist/main/services/default-adapter.js +3 -3
  37. package/dist/main/services/mcp/index.d.ts +1 -0
  38. package/dist/main/services/mcp/index.js +1 -0
  39. package/dist/main/services/mcp/server.d.ts +2 -1
  40. package/dist/main/services/mcp/server.js +10 -0
  41. package/dist/main/services/mcp/status.d.ts +10 -0
  42. package/dist/main/services/mcp/status.js +14 -0
  43. package/dist/main/services/mcp/target-manager.js +2 -1
  44. package/dist/main/services/module.d.ts +18 -0
  45. package/dist/main/services/module.js +2 -0
  46. package/dist/main/services/notifications/renderer-notifier.d.ts +5 -3
  47. package/dist/main/services/notifications/renderer-notifier.js +3 -6
  48. package/dist/main/services/projects/builtin-templates.d.ts +3 -0
  49. package/dist/main/services/projects/builtin-templates.js +24 -0
  50. package/dist/main/services/projects/create-project-service.d.ts +7 -0
  51. package/dist/main/services/projects/create-project-service.js +84 -0
  52. package/dist/main/services/projects/index.d.ts +7 -0
  53. package/dist/main/services/projects/index.js +9 -0
  54. package/dist/main/services/projects/local-provider.d.ts +3 -0
  55. package/dist/main/services/projects/local-provider.js +25 -0
  56. package/dist/main/services/projects/project-repository.d.ts +1 -1
  57. package/dist/main/services/projects/project-repository.js +3 -0
  58. package/dist/main/services/projects/templates.d.ts +21 -0
  59. package/dist/main/services/projects/templates.js +39 -0
  60. package/dist/main/services/projects/thumbnail.d.ts +8 -0
  61. package/dist/main/services/projects/thumbnail.js +37 -0
  62. package/dist/main/services/projects/types.d.ts +118 -0
  63. package/dist/main/services/projects/types.js +19 -0
  64. package/dist/main/services/settings/index.d.ts +11 -0
  65. package/dist/main/services/settings/index.js +18 -2
  66. package/dist/main/services/simulator/custom-apis.d.ts +10 -0
  67. package/dist/main/services/simulator/custom-apis.js +26 -0
  68. package/dist/main/services/simulator-storage/index.d.ts +22 -1
  69. package/dist/main/services/simulator-storage/index.js +334 -97
  70. package/dist/main/services/update/update-manager.d.ts +16 -1
  71. package/dist/main/services/update/update-manager.js +18 -15
  72. package/dist/main/services/views/view-manager.d.ts +7 -7
  73. package/dist/main/services/views/view-manager.js +53 -29
  74. package/dist/main/services/window-service.d.ts +24 -0
  75. package/dist/main/services/window-service.js +26 -0
  76. package/dist/main/services/workbench-context.d.ts +49 -2
  77. package/dist/main/services/workbench-context.js +15 -2
  78. package/dist/main/services/workspace/workspace-service.d.ts +9 -6
  79. package/dist/main/services/workspace/workspace-service.js +71 -11
  80. package/dist/main/simulator-apis.d.ts +23 -0
  81. package/dist/main/simulator-apis.js +24 -0
  82. package/dist/main/utils/disposable.d.ts +13 -0
  83. package/dist/main/utils/disposable.js +60 -0
  84. package/dist/main/utils/ipc-registry.d.ts +39 -0
  85. package/dist/main/utils/ipc-registry.js +109 -0
  86. package/dist/main/utils/ipc-schema.d.ts +28 -0
  87. package/dist/main/utils/ipc-schema.js +38 -0
  88. package/dist/main/utils/paths.d.ts +6 -0
  89. package/dist/main/utils/paths.js +6 -0
  90. package/dist/main/utils/sender-policy.d.ts +25 -0
  91. package/dist/main/utils/sender-policy.js +44 -0
  92. package/dist/main/utils/theme.d.ts +24 -0
  93. package/dist/main/utils/theme.js +38 -1
  94. package/dist/main/windows/main-window/create.d.ts +6 -0
  95. package/dist/main/windows/main-window/create.js +66 -10
  96. package/dist/main/windows/main-window/events.d.ts +2 -1
  97. package/dist/main/windows/main-window/events.js +25 -2
  98. package/dist/main/windows/navigation-hardening.d.ts +24 -0
  99. package/dist/main/windows/navigation-hardening.js +55 -0
  100. package/dist/main/windows/settings-window/create.js +11 -1
  101. package/dist/preload/index.d.ts +22 -0
  102. package/dist/preload/index.js +19 -0
  103. package/dist/preload/instrumentation/app-data.d.ts +32 -2
  104. package/dist/preload/instrumentation/app-data.js +253 -79
  105. package/dist/preload/instrumentation/index.d.ts +2 -2
  106. package/dist/preload/instrumentation/index.js +2 -2
  107. package/dist/preload/instrumentation/wxml.d.ts +16 -4
  108. package/dist/preload/instrumentation/wxml.js +188 -178
  109. package/dist/preload/miniapp-snapshot/host.d.ts +12 -0
  110. package/dist/preload/miniapp-snapshot/host.js +117 -0
  111. package/dist/preload/miniapp-snapshot/types.d.ts +62 -0
  112. package/dist/preload/miniapp-snapshot/types.js +15 -0
  113. package/dist/preload/runtime/bridge.js +5 -24
  114. package/dist/preload/runtime/custom-apis.d.ts +6 -0
  115. package/dist/preload/runtime/custom-apis.js +43 -0
  116. package/dist/preload/runtime/host.d.ts +1 -0
  117. package/dist/preload/runtime/host.js +13 -0
  118. package/dist/preload/shared/expose.d.ts +15 -0
  119. package/dist/preload/shared/expose.js +33 -0
  120. package/dist/preload/shared/page-iframe.d.ts +3 -0
  121. package/dist/preload/shared/page-iframe.js +6 -0
  122. package/dist/preload/shared/types.d.ts +2 -0
  123. package/dist/preload/windows/main.cjs +47 -0
  124. package/dist/preload/windows/main.cjs.map +7 -0
  125. package/dist/preload/windows/simulator.js +501 -272
  126. package/dist/renderer/assets/constants-DI382mTP.js +2 -0
  127. package/dist/renderer/assets/index-D8VFYBh-.js +46 -0
  128. package/dist/renderer/assets/{input-DxfYnzX_.js → input-CoWcfa8u.js} +2 -2
  129. package/dist/renderer/assets/ipc-transport-Cd2xPrsa.js +9 -0
  130. package/dist/renderer/assets/ipc-transport-DqbRdZNO.css +1 -0
  131. package/dist/renderer/assets/popover-Nq5gT9DO.js +2 -0
  132. package/dist/renderer/assets/select-By5KH-UG.js +2 -0
  133. package/dist/renderer/assets/{settings-DteGraEU.js → settings-Dj_N70qR.js} +2 -2
  134. package/dist/renderer/assets/settings-api-Do0_Smq1.js +2 -0
  135. package/dist/renderer/assets/workbenchSettings-CazSLGYt.js +8 -0
  136. package/dist/renderer/entries/main/index.html +13 -5
  137. package/dist/renderer/entries/popover/index.html +8 -5
  138. package/dist/renderer/entries/settings/index.html +7 -5
  139. package/dist/renderer/entries/workbench-settings/index.html +7 -4
  140. package/dist/shared/ipc-channels.d.ts +46 -13
  141. package/dist/shared/ipc-channels.js +60 -14
  142. package/dist/shared/ipc-schemas.d.ts +118 -0
  143. package/dist/shared/ipc-schemas.js +133 -0
  144. package/dist/shared/simulator-route.d.ts +72 -0
  145. package/dist/shared/simulator-route.js +169 -0
  146. package/dist/shared/types.d.ts +82 -8
  147. package/dist/simulator/assets/simulator-DJCozrU5.js +9 -0
  148. package/dist/simulator/simulator.html +6 -43
  149. package/package.json +18 -29
  150. package/templates/blank/app.js +6 -0
  151. package/templates/blank/app.json +11 -0
  152. package/templates/blank/app.wxss +5 -0
  153. package/templates/blank/pages/index/index.js +6 -0
  154. package/templates/blank/pages/index/index.json +3 -0
  155. package/templates/blank/pages/index/index.wxml +3 -0
  156. package/templates/blank/pages/index/index.wxss +11 -0
  157. package/templates/blank/project.config.json +13 -0
  158. package/templates/blank/sitemap.json +9 -0
  159. package/templates/taro-todo/app.js +1 -0
  160. package/templates/taro-todo/app.json +1 -0
  161. package/templates/taro-todo/app.wxss +1 -0
  162. package/templates/taro-todo/base.wxml +851 -0
  163. package/templates/taro-todo/common.js +1 -0
  164. package/templates/taro-todo/comp.js +1 -0
  165. package/templates/taro-todo/comp.json +1 -0
  166. package/templates/taro-todo/comp.wxml +2 -0
  167. package/templates/taro-todo/custom-wrapper.js +1 -0
  168. package/templates/taro-todo/custom-wrapper.json +1 -0
  169. package/templates/taro-todo/custom-wrapper.wxml +4 -0
  170. package/templates/taro-todo/pages/index/index.js +2 -0
  171. package/templates/taro-todo/pages/index/index.json +1 -0
  172. package/templates/taro-todo/pages/index/index.wxml +2 -0
  173. package/templates/taro-todo/pages/index/index.wxss +1 -0
  174. package/templates/taro-todo/project.config.json +44 -0
  175. package/templates/taro-todo/runtime.js +1 -0
  176. package/templates/taro-todo/taro.js +2 -0
  177. package/templates/taro-todo/utils.wxs +39 -0
  178. package/templates/taro-todo/vendors.js +2 -0
  179. package/dist/preload/instrumentation/disposable.d.ts +0 -11
  180. package/dist/preload/instrumentation/disposable.js +0 -15
  181. package/dist/preload/windows/main.d.ts +0 -6
  182. package/dist/preload/windows/main.js +0 -6
  183. package/dist/renderer/assets/index-D1p6crtf.js +0 -46
  184. package/dist/renderer/assets/ipc-transport-ClIvDcYY.js +0 -9
  185. package/dist/renderer/assets/ipc-transport-EiWxu_hG.css +0 -1
  186. package/dist/renderer/assets/popover-CtXcBJtM.js +0 -2
  187. package/dist/renderer/assets/select-DMfp49f1.js +0 -2
  188. package/dist/renderer/assets/settings-api-CY84UMpN.js +0 -2
  189. package/dist/renderer/assets/workbenchSettings-DjELLnSJ.js +0 -8
  190. package/dist/simulator/assets/simulator-C1eHXnuq.js +0 -9
package/README.md CHANGED
@@ -83,6 +83,7 @@ import { app, globalShortcut } from 'electron'
83
83
  import path from 'path'
84
84
  import { createMainWindow } from '@dimina-kit/devtools/create-window'
85
85
  import { createWorkbenchContext } from '@dimina-kit/devtools/context'
86
+ import { registerAppIpc } from '@dimina-kit/devtools'
86
87
  import { registerSimulatorIpc } from '@dimina-kit/devtools/ipc-simulator'
87
88
  import { registerPanelsIpc } from '@dimina-kit/devtools/ipc-panels'
88
89
  import { registerToolbarIpc } from '@dimina-kit/devtools/ipc-toolbar'
@@ -95,7 +96,7 @@ import { rendererDir, defaultPreloadPath } from '@dimina-kit/devtools/paths'
95
96
  app.whenReady().then(() => {
96
97
  const mainWindow = createMainWindow({
97
98
  title: 'My DevTools',
98
- indexHtml: path.join(rendererDir, 'index.html'),
99
+ indexHtml: path.join(rendererDir, 'entries/main/index.html'),
99
100
  })
100
101
 
101
102
  const ctx = createWorkbenchContext({
@@ -105,6 +106,9 @@ app.whenReady().then(() => {
105
106
  rendererDir,
106
107
  })
107
108
 
109
+ // registerAppIpc 必装:renderer 启动时调用 app:getPreloadPath / app:getBranding,
110
+ // 缺它会卡在加载阶段。
111
+ registerAppIpc(ctx)
108
112
  registerProjectsIpc(ctx)
109
113
  registerSessionIpc(ctx)
110
114
  registerSimulatorIpc(ctx)
@@ -112,6 +116,11 @@ app.whenReady().then(() => {
112
116
  registerToolbarIpc(ctx)
113
117
  registerPopoverIpc(ctx)
114
118
 
119
+ // Storage / 元素选区面板的后端 handler 由 setupSimulatorStorage 单独装。
120
+ // 该函数当前**未列入稳定公共 API**(在 `@dimina-kit/devtools` 之外)。
121
+ // 若需要这两个面板,建议改用上方的 `createWorkbenchApp({ onSetup })` 路线,
122
+ // 框架会自动注册;模块组装路线下你只能用不依赖它们的精简面板集。
123
+
115
124
  // 添加自定义 IPC — 通过 ctx.workspace 访问会话状态
116
125
  ipcMain.handle('my:action', () => {
117
126
  console.log('current project:', ctx.workspace.getProjectPath())
@@ -150,9 +159,6 @@ src/
150
159
  app.ts # createWorkbenchApp 工厂
151
160
  bootstrap.ts # suppressEpipe / setupCdpPort
152
161
  lifecycle.ts # Electron app 生命周期注册
153
- windows/
154
- main-window/ # 主窗口创建 + 事件接线
155
- settings-window/ # 独立设置窗口
156
162
  ipc/ # 只做 handler 注册,不写业务
157
163
  index.ts # 聚合 register 函数导出
158
164
  simulator.ts # simulator attach/detach/resize
@@ -166,17 +172,33 @@ src/
166
172
  settings/ # 用户级 workbench 设置读写 + 主题应用
167
173
  projects/ # 项目列表 CRUD(持久化)
168
174
  layout/ # 布局常量 + bounds 计算
175
+ views/ # ViewManager(settings / popover overlay 等)
176
+ workspace/ # 项目会话生命周期
177
+ notifications/ # 主进程 → renderer 的事件通知
169
178
  mcp/ # MCP server
170
179
  automation/ # 自动化 WebSocket 服务
171
180
  simulator/ # simulator dir / referer
181
+ simulator-storage/ # CDP DOMStorage + 元素 inspect 桥接
182
+ update/ # UpdateManager + GitHubReleaseChecker
172
183
  workbench-context.ts # 共享状态类型 + 工厂 + 辅助函数
184
+ window-service.ts # main / settings 窗口聚合访问
185
+ module.ts # WorkbenchModule 协议
173
186
  default-adapter.ts # 默认 CompilationAdapter
174
187
  menu/ # 应用菜单
175
- utils/paths.ts # rendererDir / defaultPreloadPath
188
+ utils/
189
+ paths.ts # rendererDir / defaultPreloadPath / simulatorDir
190
+ disposable.ts # DisposableRegistry + AggregateError 聚合
191
+ ipc-registry.ts # ipcMain.handle 包装 + SenderPolicy 闸门
192
+ sender-policy.ts # sender webContents id 白名单
193
+ ipc-schema.ts # zod schema 校验工具
194
+ windows/
195
+ main-window/ # 主窗口创建 + 事件接线
196
+ settings-window/ # 独立设置窗口
197
+ navigation-hardening.ts # will-navigate / setWindowOpenHandler 限流
176
198
 
177
199
  preload/ # 按注入目标分
178
200
  windows/ # contextBridge 类型 preload
179
- main.ts # 主窗口 preload,可组合导出 install*Instrumentation
201
+ main.ts # workbench 三窗口 preload,仅暴露 window.devtools.ipc
180
202
  simulator.ts # simulator webview 的默认 preload
181
203
  shared/ # preload 之间共享
182
204
  api-compat.ts # setupApiCompatHook
@@ -184,19 +206,23 @@ src/
184
206
  types.ts
185
207
  instrumentation/ # 注入到小程序 runtime 的探针
186
208
  console.ts # 控制台拦截
187
- storage.ts # localStorage 拦截
188
- app-data.ts # Worker setData 拦截
189
- wxml.ts # Vue 组件树提取
209
+ app-data.ts # Worker setData 拦截 → createAppDataSource
210
+ wxml.ts # Vue 组件树提取 → createWxmlSource
211
+ disposable.ts # instrumentation 共用的清理工具
212
+ miniapp-snapshot/ # 面板数据统一快照框架(docs/miniapp-snapshot.md)
213
+ types.ts # MiniappSnapshotSource / SnapshotEnvelope
214
+ host.ts # createMiniappSnapshotHost → push/pull/__miniappSnapshot
190
215
  runtime/
191
- bridge.ts # installSimulatorBridge
192
- host.ts
216
+ bridge.ts # installSimulatorBridge → window.__simulatorData
217
+ custom-apis.ts # installCustomApisBridge → window.__diminaCustomApis
218
+ host.ts # sendToHost 推送封装
193
219
 
194
220
  renderer/
195
221
  entries/ # 各窗口 HTML + React 挂载点
196
222
  main/ popover/ settings/ workbench-settings/
197
223
  modules/ # 先按窗口分,再按区域
198
224
  main/
199
- app/ # 主窗口 App
225
+ main.tsx # 主窗口 React
200
226
  features/ # 主窗口内的业务区域
201
227
  project-runtime/ # 项目视图 + 工具栏 + 右侧面板切换
202
228
  right-panel/ # WXML / AppData / Storage 面板
@@ -248,6 +274,8 @@ src/
248
274
  | `onSetup` | `(instance) => void` | — | 窗口和 context 创建后的回调,用于注册自定义 IPC |
249
275
  | `onBeforeClose` | `(instance) => void` | — | 窗口关闭前的回调,session 关闭由框架自动处理 |
250
276
  | `window` | `WorkbenchWindowConfig` | — | 窗口尺寸覆盖 |
277
+ | `updateChecker` | `UpdateChecker` | — | 自定义更新检查器;提供后启用"检查更新"功能 |
278
+ | `updateOptions` | `{ checkInterval?, initialDelay?, getCurrentVersion? }` | — | 仅当 `updateChecker` 提供时生效,默认 1h / 5s |
251
279
 
252
280
  ### 内置面板 ID
253
281
 
@@ -259,6 +287,126 @@ src/
259
287
 
260
288
  ---
261
289
 
290
+ ## Embedding & Extending the Project Panel
291
+
292
+ 宿主(如 qdmp)通过 `createWorkbenchApp({...})` 嵌入 devtools 时,可对项目面板做三个正交扩展:
293
+
294
+ | 扩展点 | 用途 |
295
+ | --- | --- |
296
+ | `projectsProvider` | 接管项目列表存储 —— 替换默认 `<userData>/dimina-projects.json`,对接 qdmp 后台 / IDE workspace / 远端工程库 |
297
+ | `projectTemplates` + `builtinTemplates` | 注入/覆盖/裁剪"新建项目"模板列表(同 id 覆盖内置;`builtinTemplates` 控制内置策略) |
298
+ | `customCreateProjectDialog` | 用宿主自家页面替换内置"新建项目"对话框(main 进程 hook,可 `new BrowserWindow` 加载任意 URL,通过 IPC/postMessage 回传结果) |
299
+
300
+ ### 何时需要哪个扩展点
301
+
302
+ | 场景 | 需要的扩展点 |
303
+ | --- | --- |
304
+ | 项目列表来自 qdmp 后台 / 团队工程库 | `projectsProvider` |
305
+ | 仅替换可选模板(e.g. 只提供 taro / qdmp 自家脚手架) | `projectTemplates` + `builtinTemplates` |
306
+ | 创建项目流程要走宿主自己的 wizard / 登录态 | `customCreateProjectDialog` |
307
+
308
+ ### 最小示例
309
+
310
+ ```typescript
311
+ import { createWorkbenchApp } from '@dimina-kit/devtools/app'
312
+ import type { ProjectsProvider, ProjectTemplate } from '@dimina-kit/devtools/projects-provider'
313
+ import { BrowserWindow } from 'electron'
314
+
315
+ const provider: ProjectsProvider = {
316
+ async listProjects() {
317
+ return await qdmp.api.listProjects()
318
+ },
319
+ async validateProjectDir(dirPath) {
320
+ return (await qdmp.api.isMiniApp(dirPath)) ? null : '不是合法的小程序工程'
321
+ },
322
+ async addProject(dirPath) {
323
+ return await qdmp.api.addProject(dirPath)
324
+ },
325
+ async removeProject(dirPath) {
326
+ await qdmp.api.removeProject(dirPath)
327
+ },
328
+ async updateLastOpened(dirPath) {
329
+ await qdmp.api.touchLastOpened(dirPath)
330
+ },
331
+ async getCompileConfig(dirPath) {
332
+ return await qdmp.api.getCompileConfig(dirPath)
333
+ },
334
+ async saveCompileConfig(dirPath, cfg) {
335
+ await qdmp.api.saveCompileConfig(dirPath, cfg)
336
+ },
337
+ // 缩略图走云端存储——dataUrl 形如 'data:image/png;base64,...'
338
+ async saveThumbnail(dirPath, imageDataUrl) {
339
+ await qdmp.api.uploadThumbnail(dirPath, imageDataUrl)
340
+ },
341
+ async getThumbnail(dirPath) {
342
+ return await qdmp.api.fetchThumbnail(dirPath)
343
+ },
344
+ }
345
+
346
+ const qdmpBlank: ProjectTemplate = {
347
+ id: 'blank', // 同 id 覆盖内置 blank
348
+ name: 'qdmp 空白工程',
349
+ description: '由 qdmp 维护的官方空白模板',
350
+ source: { type: 'directory', path: '/abs/path/to/template' },
351
+ }
352
+
353
+ createWorkbenchApp({
354
+ projectsProvider: provider,
355
+ projectTemplates: [qdmpBlank],
356
+ builtinTemplates: ['taro-todo'], // 只保留 taro-todo,干掉默认 blank
357
+ customCreateProjectDialog: async ({ parentWindow }) => {
358
+ const win = new BrowserWindow({ parent: parentWindow, modal: true, width: 720, height: 520 })
359
+ await win.loadURL('https://qdmp.example.com/devtools/new-project')
360
+ return await new Promise((resolve) => {
361
+ win.webContents.ipc.once('qdmp:create-project:done', (_e, payload) => {
362
+ win.close()
363
+ // payload 三选一(CustomCreateProjectDialogResult):
364
+ // null → 用户取消
365
+ // CreateProjectInput → 让 devtools 在本地物化模板并注册到 provider
366
+ // { ready: Project } → 宿主后端已经创建好,devtools 直接刷新列表
367
+ resolve(payload ?? null)
368
+ })
369
+ win.on('closed', () => resolve(null))
370
+ })
371
+ },
372
+ }).start()
373
+ ```
374
+
375
+ ### `customCreateProjectDialog` 返回值
376
+
377
+ `hook` 返回 `CustomCreateProjectDialogResult`,三种情形分别对应不同后续动作:
378
+
379
+ | 返回 | 行为 |
380
+ | --- | --- |
381
+ | `null` | 用户取消,无副作用 |
382
+ | `CreateProjectInput`(`{ name, path, templateId?, extra? }`) | devtools 在本地拷贝/生成模板 → 改写 `project.config.json` → `provider.addProject(path)`;适合"只想换 UI 但物化由 devtools 兜底" |
383
+ | `{ ready: Project }` | devtools 跳过物化,只刷新列表并打开该项目;适合宿主后端已经远端创建好项目,本地完全无需落盘 |
384
+
385
+ 物化失败(路径已存在/模板缺失/`provider.addProject` reject)会经 native dialog 弹出错误,再 reject 给渲染层;宿主端无需自己 toast。
386
+
387
+ ### 内置模板
388
+
389
+ devtools 自带两个 `source`-style 模板,位于 `packages/devtools/templates/`:
390
+
391
+ - `blank` — 最小空白小程序骨架(pages/index + app.js/json/wxss + project.config.json,约 8 个文件)
392
+ - `taro-todo` — 复制自 `dimina/fe/example/taro-todo`,作为 Taro 编译产物的端到端演示工程
393
+
394
+ `builtinTemplates: 'none'` 排除全部内置;`builtinTemplates: ['taro-todo']` 仅保留指定 id;`projectTemplates` 同 id 注入会覆盖(例如上文 `qdmpBlank` 覆盖了内置 `blank`)。
395
+
396
+ ### Provider 部分实现 / fallback 行为
397
+
398
+ `ProjectsProvider` 的多数方法是可选的;当宿主只实现 `listProjects` / `addProject` / `removeProject` 时:
399
+
400
+ - `validateProjectDir` 缺省 → 返回 `null`(不校验)
401
+ - `updateLastOpened` 缺省 → 静默 no-op,"最近"排序退化为 `listProjects` 返回顺序
402
+ - `getCompileConfig` 缺省 → 返回 `DEFAULT_COMPILE_CONFIG`(`{ startPage: '', scene: 1001, queryParams: [] }`)
403
+ - `saveCompileConfig` 缺省 → 静默 no-op,编译配置面板的编辑不会持久化
404
+ - `saveThumbnail` / `getThumbnail` 缺省 → save 静默 no-op,get 返回 `null`;项目卡缩略图不显示。实现这两个方法可让远端项目用云端缩略图(详见示例)
405
+
406
+ > 完整契约、参数语义和默认值见 `src/main/services/projects/types.ts` 的 JSDoc,那是 source of truth。
407
+
408
+ ---
409
+
262
410
  ## CompilationAdapter
263
411
 
264
412
  实现此接口接入自定义构建流程:
@@ -285,37 +433,63 @@ const myAdapter: CompilationAdapter = {
285
433
 
286
434
  ## Preload Instrumentation
287
435
 
288
- 模拟器 webview 注入 preload 脚本在全局安装 instrumentation。内置 preload(`preload/windows/simulator.ts`)组装了以下模块:
436
+ 模拟器 webview 注入 preload 脚本,在 webview 全局上安装两类东西:**桥接**(把数据通道暴露到 webview)+ **instrumentation**(监听运行时事件并写入桥接)。内置 preload 见 `src/preload/windows/simulator.ts`。
437
+
438
+ ### 必装:桥接
439
+
440
+ | 函数 | 作用 | 不装会怎样 |
441
+ | --- | --- | --- |
442
+ | `installSimulatorBridge()` | 暴露 `window.__simulatorData`,承载 `highlightElement` / `unhighlightElement` / `getAppdata` / `getWxml` / `getStorageSnapshot` 等只读 API(供主进程 `executeJavaScript` 拉取) | 元素选区 overlay 不显示;automation `Page.getData` 返回空对象;MCP `simulator_get_overview` 在 hints 中追加 `simulator bridge not ready (window.__simulatorData missing)`。注:Storage 面板走主进程 CDP,不受影响;Console/AppData/WXML 推送走 `sendToHost`,也不受影响 |
443
+ | `installCustomApisBridge()` | 暴露 `window.__diminaCustomApis`,承载 `list` / `invoke`,让模拟器侧把主进程注册的 API 代理回小程序 runtime | `registerSimulatorApi` 注册的业务 API 在小程序里调用全部 no-op(参见下方 "Simulator 自定义 API") |
444
+ | `setupApiCompatHook()` | 兼容上游 API 名称变更 | 部分 API 调用兼容性问题 |
445
+
446
+ 下游写自定义 preload 时,这三项原则上都要装。若不需要 `registerSimulatorApi`,`installCustomApisBridge` 可省略。
289
447
 
290
- | Instrumentation | 捕获内容 |
291
- | ----------------------------------------- | ----------------------------------------------- |
292
- | Console (`installConsoleInstrumentation`) | `console.*`、`window.onerror`、未捕获 rejection |
293
- | Storage (`installStorageInstrumentation`) | `localStorage.setItem/removeItem`、全量快照 |
294
- | AppData (`installAppDataInstrumentation`) | Worker `type='u'` 消息、setData 调用 |
295
- | WXML (`installWxmlInstrumentation`) | Vue 组件树提取、MutationObserver 自动更新 |
448
+ ### 按需:instrumentation
296
449
 
297
- 所有 install\* 函数从 `@dimina-kit/devtools/preload` 统一导出,调用后通过 `installSimulatorBridge` 暴露的内部桥接通道把数据推到宿主。面板打开时调用 `panel:eval` 通过 `executeJavaScript` 拉取当前状态。
450
+ Console 是独立 instrumentation;AppData WXML 已迁移到 **miniappSnapshot** 框架——各自实现一个 `MiniappSnapshotSource`,由 `MiniappSnapshotHost` 统一负责推送 / 拉取 / reload 重同步(详见 `docs/miniapp-snapshot.md`)。
451
+
452
+ | 探针 | 捕获内容 | 数据通道 |
453
+ | --- | --- | --- |
454
+ | `installConsoleInstrumentation()` | `console.*`、`window.onerror`、未捕获 rejection | `sendToHost` |
455
+ | `createAppDataSource()` | Worker `ub` 消息、setData / page init | miniappSnapshot 框架(`miniapp-snapshot:push`) |
456
+ | `createWxmlSource()` | Vue 组件树提取、MutationObserver 自动更新 | miniappSnapshot 框架(`miniapp-snapshot:push`) |
457
+
458
+ > Storage 面板的数据由主进程通过 CDP `DOMStorage` 域抓取(`src/main/services/simulator-storage`),**不需要 preload 侧 instrumentation**。
459
+
460
+ 各面板的数据流详见下方 "数据流" 章节。
298
461
 
299
462
  ### 自定义 Preload
300
463
 
301
- 按需组合或追加自定义逻辑(`src/preload/windows/simulator.ts` 作为参考):
464
+ 参考 `src/preload/windows/simulator.ts`:
302
465
 
303
466
  ```typescript
304
467
  // my-preload.ts
305
468
  import {
306
469
  installSimulatorBridge,
470
+ installCustomApisBridge,
307
471
  installConsoleInstrumentation,
308
- installStorageInstrumentation,
472
+ createMiniappSnapshotHost,
473
+ createAppDataSource,
474
+ createWxmlSource,
309
475
  setupApiCompatHook,
310
476
  } from '@dimina-kit/devtools/preload'
311
- // 不需要 WXML/AppData,不导入
312
477
 
478
+ // 1. 兼容 hook + 桥接(必装,且应在 instrumentation 之前)
313
479
  setupApiCompatHook()
314
480
  installSimulatorBridge()
481
+ installCustomApisBridge() // 若用到 registerSimulatorApi,必装
482
+
483
+ // 2. Console instrumentation(按需)
315
484
  installConsoleInstrumentation()
316
- installStorageInstrumentation()
317
485
 
318
- // 自定义 hook
486
+ // 3. miniappSnapshot 框架:注册面板数据源后 install()
487
+ const snapshotHost = createMiniappSnapshotHost()
488
+ snapshotHost.register(createAppDataSource())
489
+ snapshotHost.register(createWxmlSource())
490
+ snapshotHost.install()
491
+
492
+ // 4. 自定义 hook
319
493
  window.addEventListener('error', (e) => {
320
494
  console.error('[my-preload]', e.message)
321
495
  })
@@ -329,49 +503,94 @@ launch({ preloadPath: '/absolute/path/to/my-preload.js' })
329
503
 
330
504
  ---
331
505
 
506
+ ## Simulator 自定义 API
507
+
508
+ 下游可以通过 `registerSimulatorApi` 把业务 API 注入到模拟器内运行的小程序。Handler 在 Electron **主进程**执行,能用任何 Node 能力(fs、net、原生模块、持久状态);模拟器侧拿到 `wx.<name>(params)` 调用后通过 IPC 转发到主进程,await 返回结果,handler 抛错则原型回传给小程序。
509
+
510
+ > ⚠️ 使用本功能要求模拟器 preload 调用 `installCustomApisBridge()`(详见上方 "Preload Instrumentation")。内置 preload 已包含此调用;若你用了自定义 preload 又忘记调用,注册的 API 在小程序运行时**没有任何反应**,且不会报错。
511
+
512
+ ### 命名约定
513
+
514
+ `name` 是 dimina service 层 `invokeAPI(name, opts)` 用的**裸名**,不带 `wx.` 前缀。注册之后小程序里通过 `wx.<name>(...)`(以及你在 `apiNamespaces` 配的其它命名空间)调用都会命中:
515
+
516
+ | 小程序里写 | `registerSimulatorApi` 的 name |
517
+ | --- | --- |
518
+ | `wx.login(...)` | `'login'` |
519
+ | `wx.request(...)` | `'request'` |
520
+ | `wx.getStorage(...)` 覆盖内置 | `'getStorage'`(小心:这会**屏蔽** dimina 容器的实现) |
521
+
522
+ ```typescript
523
+ import { registerSimulatorApi } from '@dimina-kit/devtools/simulator-apis'
524
+
525
+ // 提供 wx.login 的实现(dimina 容器默认未实现,注册后才能用)
526
+ const dispose = registerSimulatorApi('login', async ({ success }) => {
527
+ // 主进程上下文:可调用内部 HTTP、读取凭证文件、访问原生模块
528
+ const code = await callInternalAuth()
529
+ return { code }
530
+ })
531
+
532
+ // 不再需要时取消注册(不传也行,进程退出会一起清理)
533
+ dispose()
534
+ ```
535
+
536
+ ### 行为约定
537
+
538
+ - **命中顺序**:小程序运行时按 `apiRegistry[name] → MiniApp 实例方法 → 扩展模块兜底` 查找,所以 `registerSimulatorApi` 注册的 name **优先于内置实现**——既能给"未实现"的 wx.* 补功能(如 `wx.login`),也能覆盖默认的 wx.* 行为(如 `wx.request`,dimina-kit 本身就在用这条路把 `request` 接到主进程 fetch)。
539
+ - 同名重复注册:后注册的覆盖前者,静默替换。
540
+ - `dispose()` 只会移除自己创建的那次注册——如果之后被别人覆盖了,旧的 disposer 是 no-op。
541
+ - 调用未注册且容器内也没有的 name:小程序侧拿到 reject,错误信息里带 name。
542
+ - Handler 可同步或异步返回;**返回值需可 JSON 序列化**(IPC 限制)。函数、Symbol、Map/Set、循环引用都会丢失。
543
+
544
+ ---
545
+
332
546
  ## 模块导出一览
333
547
 
548
+ ### Stable public exports
549
+
550
+ `@dimina-kit/devtools` 的稳定入口,签名遵循 semver;新版本不会做破坏性改动(除非 major bump)。
551
+
334
552
  ```
335
553
  @dimina-kit/devtools launch, createWorkbenchApp, buildDefaultMenu,
336
554
  openSettingsWindow, suppressEpipe, setupCdpPort,
337
- createWorkbenchContext, createMainWindow, ...
338
- (api.ts 聚合了下方全部入口)
555
+ createWorkbenchContext, createMainWindow,
556
+ createViewManager, register*Ipc,
557
+ registerSimulatorApi,
558
+ setHeaderHeight, UpdateManager,
559
+ createGitHubReleaseChecker, ...
560
+ (api.ts 聚合了所有公共 API;优先从根入口导入)
339
561
  @dimina-kit/devtools/launch launch(config?), buildDefaultMenu, openSettingsWindow
340
562
  @dimina-kit/devtools/app createWorkbenchApp(config?)
341
563
  @dimina-kit/devtools/types TypeScript 类型定义
564
+ @dimina-kit/devtools/bootstrap suppressEpipe(), setupCdpPort()
565
+ @dimina-kit/devtools/paths rendererDir, defaultPreloadPath, simulatorDir,
566
+ getRendererDir, getPreloadDir, getRendererHtml
567
+ @dimina-kit/devtools/simulator-apis registerSimulatorApi(name, handler) →
568
+ 注入由主进程托管的小程序 API(详见上方"Simulator 自定义 API")
569
+ @dimina-kit/devtools/preload installSimulatorBridge,
570
+ installCustomApisBridge,
571
+ installConsoleInstrumentation,
572
+ createMiniappSnapshotHost,
573
+ createAppDataSource, createWxmlSource,
574
+ setupApiCompatHook
575
+ (storage 面板数据由主进程 CDP 抓取,无 preload 侧 hook)
576
+ ```
577
+
578
+ ### Experimental exports (v0.x — signatures may change in minor versions)
579
+
580
+ 下列子路径主要用于"模块组装"等深度定制场景。在 0.x 阶段,函数签名和模块边界可能在 minor 版本之间调整;如果你不需要逐模块组装,请优先使用上方的 stable 入口或根 barrel。
581
+
582
+ ```
342
583
  @dimina-kit/devtools/context createWorkbenchContext(opts),
343
584
  hasBuiltinPanel(ctx, panelId), getDefaultTab(ctx)
344
585
  @dimina-kit/devtools/create-window createMainWindow(opts)
345
- @dimina-kit/devtools/view-manager createViewManager(ctx) → ViewManager
346
- (attachSimulator, detachSimulator, showSimulator,
347
- hideSimulator, showSettings, hideSettings,
348
- showPopover, hidePopover, resize,
349
- setVisible, repositionAll, disposeAll)
350
- @dimina-kit/devtools/layout computeRightPanelBounds, computeSimulatorBounds,
351
- computeSettingsBounds, computePopoverBounds,
352
- setHeaderHeight, getRightX,
353
- HEADER_H, SPLITTER_W, SETTINGS_W
354
- @dimina-kit/devtools/projects listProjects, addProject, removeProject,
355
- getCompileConfig, saveCompileConfig,
356
- updateLastOpened
357
- @dimina-kit/devtools/paths rendererDir, defaultPreloadPath,
358
- getRendererDir, getPreloadDir, getRendererHtml
359
586
  @dimina-kit/devtools/ipc-simulator registerSimulatorIpc(ctx)
360
587
  @dimina-kit/devtools/ipc-panels registerPanelsIpc(ctx)
361
588
  @dimina-kit/devtools/ipc-toolbar registerToolbarIpc(ctx)
362
589
  @dimina-kit/devtools/ipc-popover registerPopoverIpc(ctx)
363
590
  @dimina-kit/devtools/ipc-settings registerSettingsIpc(ctx)
364
591
  @dimina-kit/devtools/ipc-projects registerProjectsIpc(ctx)
365
- @dimina-kit/devtools/ipc-session registerSessionIpc(ctx), sendStatus(ctx, status, msg)
366
- @dimina-kit/devtools/bootstrap suppressEpipe(), setupCdpPort()
592
+ @dimina-kit/devtools/ipc-session registerSessionIpc(ctx), sessionModule
367
593
  @dimina-kit/devtools/workbench-settings loadWorkbenchSettings(), saveWorkbenchSettings(), applyTheme()
368
- @dimina-kit/devtools/preload installConsoleInstrumentation,
369
- installStorageInstrumentation,
370
- installAppDataInstrumentation, sendAllAppData,
371
- installWxmlInstrumentation, sendWxmlTree,
372
- setupWxmlObserver, installSimulatorBridge,
373
- setupApiCompatHook
374
- @dimina-kit/devtools/simulator-dir simulatorDir
375
594
  ```
376
595
 
377
596
  ---
@@ -382,7 +601,6 @@ launch({ preloadPath: '/absolute/path/to/my-preload.js' })
382
601
 
383
602
  ```typescript
384
603
  interface WorkbenchContext {
385
- mainWindow: BrowserWindow
386
604
  adapter: CompilationAdapter
387
605
  preloadPath: string
388
606
  rendererDir: string
@@ -391,24 +609,24 @@ interface WorkbenchContext {
391
609
  appName: string
392
610
  toolbarActions?: () => Promise<ToolbarAction[]> | ToolbarAction[]
393
611
  brandingProvider?: () => Promise<{ appName: string }> | { appName: string }
394
- workbenchSettingsWindow: BrowserWindow | null
395
612
 
396
613
  // ── Services(运行时状态封装在内部,通过方法访问)──
614
+ windows: WindowService // ctx.windows.mainWindow, ctx.windows.settingsWindow, ...
397
615
  views: ViewManager // ctx.views.repositionAll(), ctx.views.getSimulatorWebContentsId(), ...
398
616
  notify: RendererNotifier // ctx.notify.projectStatus(), ctx.notify.windowNavigateBack(), ...
399
617
  workspace: WorkspaceService // ctx.workspace.getProjectPath(), ctx.workspace.hasActiveSession(), ...
618
+
619
+ // ── Internal lifecycle / security (host 不直接消费) ──
620
+ registry: DisposableRegistry // 框架在创建时统一聚合 dispose
621
+ senderPolicy: SenderPolicy // IpcRegistry 自动校验 sender 白名单
400
622
  }
401
623
  ```
402
624
 
403
- 会话和视图状态不再作为 ctx 的直接字段暴露,而是封装在对应 service 的私有闭包中:
625
+ 会话和视图状态封装在对应 service 的私有闭包中,通过方法访问,例如:
404
626
 
405
- | 旧写法 | 新写法 |
406
- | ---------------------------- | ----------------------------------------------------------------- |
407
- | `ctx.currentProjectPath` | `ctx.workspace.getProjectPath()` |
408
- | `ctx.currentSession` | `ctx.workspace.getSession()` / `ctx.workspace.hasActiveSession()` |
409
- | `ctx.simulatorWebContentsId` | `ctx.views.getSimulatorWebContentsId()` |
410
- | `ctx.devToolsViewAdded` | `ctx.views.isSimulatorAdded()` |
411
- | `ctx.lastSimWidth` | `ctx.views.getLastSimWidth()` |
627
+ - `ctx.workspace.getProjectPath()` / `ctx.workspace.getSession()` / `ctx.workspace.hasActiveSession()`
628
+ - `ctx.views.getSimulatorWebContentsId()` / `ctx.views.isSimulatorAdded()` / `ctx.views.getLastSimWidth()`
629
+ - `ctx.windows.mainWindow` / `ctx.windows.settingsWindow`
412
630
 
413
631
  ---
414
632
 
@@ -438,76 +656,22 @@ flowchart TB
438
656
 
439
657
  ### 数据流
440
658
 
441
- 内置面板采用**拉取式**数据流,避免长期订阅:
659
+ 按面板 / 场景拆分:
442
660
 
443
- ```mermaid
444
- sequenceDiagram
445
- autonumber
446
- actor User as 用户
447
- participant UI as 面板 UI (React)
448
- participant R as renderer
449
- participant M as main<br/>ipc/panels.ts
450
- participant P as preload<br/>instrumentation
451
-
452
- User->>UI: 打开面板 / 刷新
453
- UI->>R: invokeMain('panel:eval', expression)
454
- R->>M: IPC: panel:eval
455
- M->>P: webContents.executeJavaScript(expression)
456
- Note over P: window 上已挂好取值函数
457
- P-->>M: 结构化数据
458
- M-->>R: 返回结果
459
- R-->>UI: 渲染
460
- ```
661
+ | 面板 / 场景 | 模式 | 路径 |
662
+ | --- | --- | --- |
663
+ | Console | 推送 | `installConsoleInstrumentation` 经 `runtime/host.ts:sendToHost` → webview `ipcRenderer.sendToHost` 推到宿主 → renderer 监听 `ipc-message` |
664
+ | AppData / WXML 树 | 推送 + 拉取 | **miniappSnapshot 框架**:preload `MiniappSnapshotHost` 经 `miniapp-snapshot:push` 推全量快照,renderer `useMiniappSnapshot` 整份投影;面板「刷新」走 `miniapp-snapshot:pull`(详见 `docs/miniapp-snapshot.md`) |
665
+ | Storage | 拉取 + 推送 | renderer `ipcInvoke(SimulatorStorageChannel.GetSnapshot)` → 主进程 CDP `DOMStorage` 域;变更事件由主进程通过 `SimulatorStorageChannel.Event` 推回 renderer |
666
+ | 元素选区 / `Page.getData` / MCP overview | 拉取 | 主进程 `webContents.executeJavaScript(...)` 或 `Runtime.evaluate(...)` 读 `window.__simulatorData.*`(由 `installSimulatorBridge` 暴露);面板快照亦可经 `window.__miniappSnapshot.get(id)` 同步读取(由 `MiniappSnapshotHost` 暴露) |
461
667
 
462
- Console 输出等推送场景仍由 preload 通过 `installSimulatorBridge()` 经由 webview ipcRenderer 送至宿主,再由 renderer 分发到相应面板。
668
+ > `src/main/ipc/panels.ts` 暴露 `panel:eval` handler 供外部 host 自定义面板复用,内置 renderer 不消费它。
463
669
 
464
670
  ---
465
671
 
466
672
  ## IPC 通信总览
467
673
 
468
- | 频道 | 方向 | 说明 |
469
- | --------------------------------- | ----- | ---------------------------------------------- |
470
- | `projects:list` | R→M | 获取项目列表 |
471
- | `projects:add` | R→M | 添加项目 |
472
- | `projects:remove` | R→M | 删除项目 |
473
- | `dialog:openDirectory` | R→M | 打开目录选择对话框 |
474
- | `project:open` | R→M | 编译并启动项目 |
475
- | `project:close` | R→M | 停止编译,清理 View |
476
- | `project:status` | M→R | 编译状态推送 |
477
- | `project:getPages` | R→M | 读取 app.json pages |
478
- | `project:getCompileConfig` | R→M | 读取编译配置 |
479
- | `project:saveCompileConfig` | R→M | 保存编译配置 |
480
- | `app:getPreloadPath` | R→M | 获取 preload 脚本路径 |
481
- | `app:getBranding` | R→M | 读取品牌信息(`brandingProvider`) |
482
- | `toolbar:getActions` | R→M | 读取自定义工具栏按钮 |
483
- | `workbench:getPanelConfig` | R→M | 获取 panels 配置 |
484
- | `workbench:getApiNamespaces` | R→M | 获取自定义 API namespaces |
485
- | `simulator:attach` | R→M | 绑定 simulator webContents,创建 simulatorView |
486
- | `simulator:detach` | R→M | 销毁所有 View |
487
- | `simulator:resize` | R→M | 更新 View 位置(分割线拖动) |
488
- | `simulator:setVisible` | R→M | 显示/隐藏 simulator 面板 |
489
- | `workbench:reset` | R→M | 通知主窗口重置面板状态 |
490
- | `panel:list` | R→M | 获取启用的内置面板列表 |
491
- | `panel:eval` | R→M | 在 simulator webContents 执行 JS 并返回结果 |
492
- | `panel:select` | R→M | 切换到指定内置面板 |
493
- | `panel:selectSimulator` | R→M | 切换到 simulator tab |
494
- | `popover:show` | R→M | 创建弹窗 |
495
- | `popover:hide` | R→M | 销毁弹窗 |
496
- | `popover:init` | M→P | 初始化弹窗数据 |
497
- | `popover:relaunch` | P→M→R | 重新编译 |
498
- | `popover:closed` | M→R | 弹窗关闭通知 |
499
- | `settings:setVisible` | R→M | 显示/隐藏设置视图 |
500
- | `settings:init` | M→P | 初始化设置面板 |
501
- | `settings:configChanged` | P→M→R | 编译配置变更通知 |
502
- | `settings:projectSettingsChanged` | P→M | 项目级设置(如 sourcemap)落盘 |
503
- | `settings:closed` | M→R | 设置面板关闭通知 |
504
- | `workbenchSettings:get` | R→M | 读取用户级 workbench 设置 |
505
- | `workbenchSettings:save` | R→M | 保存 workbench 设置并应用主题 |
506
- | `workbenchSettings:setTheme` | R→M | 仅切换主题 |
507
- | `workbenchSettings:getCdpStatus` | R→M | 读取当前 CDP 端口状态 |
508
- | `workbenchSettings:setVisible` | R→M | 打开/关闭独立设置窗口 |
509
-
510
- R=渲染进程,M=主进程,P=子 WebContentsView
674
+ IPC 频道名常量集中定义在 `src/shared/ipc-channels.ts`,按域分组(`SimulatorChannel` / `ProjectChannel` / `PanelChannel` / `WorkbenchSettingsChannel` 等)。该文件是频道清单的唯一真相源;此处不再维护手抄表,以免与代码漂移。
511
675
 
512
676
  ---
513
677
 
@@ -545,18 +709,18 @@ pnpm test # 运行测试
545
709
 
546
710
  ## 安全说明
547
711
 
548
- - 本工具仅用于本地开发调试,不应部署到生产环境
549
- - 为方便开发调试,BrowserWindow 启用了 `nodeIntegration` 并禁用了 `contextIsolation`,这在生产环境中存在安全风险
550
- - 仅在受信任的本地开发环境中使用本工具
551
- - 不要在 devtools 窗口中加载不受信任的远程内容
552
- - 如需在非本地环境使用,请自行评估并加固安全配置
712
+ 本工具仅用于本地开发调试。当前的安全配置:
553
713
 
554
- ### MCP Server 风险
714
+ - **Workbench 窗口**(main / settings / popover overlay)均启用 `contextIsolation` 并禁用 `nodeIntegration`;renderer 通过 main preload 经 `contextBridge` 拿到 `window.devtools.ipc`,每个 IPC handler 经 sender whitelist 校验调用方
715
+ - **Simulator 加载的小程序代码** 运行在独立 `<webview>` 中(`partition='persist:simulator'`、`nodeIntegration=false`),preload 由 `session.registerPreloadScript` 在 session 层固定,渲染进程无法替换
716
+ - **renderer 入口** 启用了保守 CSP;`will-navigate` / `setWindowOpenHandler` 屏蔽外部跳转
555
717
 
556
- 内置的 MCP server 默认关闭,由 `startMcpServer` 入口显式启动,或通过 workbench 设置中的 `mcp.enabled` 开启。开启后会在本机监听 SSE 端点,向任何可以连接到该端点的 MCP 客户端暴露一组工具,能力包括:在页面上下文执行任意 JS(`evaluate`)、读取 DOM 结构、截屏、拉取网络日志、触发导航等。
718
+ 仍然不要在 devtools 窗口中加载不受信任的远程内容;本工具不打算在非本地环境部署。
719
+
720
+ ### MCP Server 风险
557
721
 
558
- 由于 workbench 主窗口出于调试需要启用了 `nodeIntegration` 并关闭了 `contextIsolation`,通过 MCP 客户端执行的 `evaluate` 实际拥有 Node API 访问权限。换言之,开启 MCP 等同于允许已连接的本机 MCP 客户端在 DevTools 进程中执行 Node 代码,读写本机文件和启动子进程均在其能力范围内。
722
+ 内置的 MCP server 默认关闭,由 `startMcpServer` 入口显式启动,或通过 workbench 设置中的 `mcp.enabled` 开启。开启后会在本机监听 SSE 端点,向任何可以连接到该端点的 MCP 客户端暴露一组工具,能力包括:读取 DOM 结构、截屏、拉取网络日志、触发导航等。
559
723
 
560
- 因此仅在连接到可信的本机 MCP 客户端或被信任的 AI 工具时启用该功能;不要在公共 WiFi、共享机器或存在远程 SSH 端口转发的场景下开启,以免监听端口被非预期的客户端访问。
724
+ `workbench_evaluate` 已从 MCP 工具集中移除,workbench 只暴露只读诊断工具(截屏、console 日志、DOM、网络日志等)。`simulator_evaluate` 仍然保留,但 simulator 使用 `<webview>`、`nodeIntegration=false`,其 `evaluate` 仅在页面 JS 上下文执行,不具备 Node API 访问能力。
561
725
 
562
- 作为收窄 RCE 面的默认策略,`workbench_evaluate` 已从 MCP 工具集中移除,workbench 只暴露只读诊断工具(截屏、console 日志、DOM、网络日志等)。`simulator_evaluate` 仍然保留,因为 simulator 使用 `<webview>`,默认 `nodeIntegration=false`,其 `evaluate` 仅在页面 JS 上下文执行,不具备 Node API 访问能力。
726
+ 仅在连接到可信的本机 MCP 客户端或被信任的 AI 工具时启用该功能;不要在公共 WiFi、共享机器或存在远程 SSH 端口转发的场景下开启,以免监听端口被非预期的客户端访问。
@@ -7,6 +7,10 @@ export type { WorkbenchContext, CreateContextOptions } from './services/workbenc
7
7
  export { createMainWindow } from './windows/main-window/index.js';
8
8
  export { createViewManager } from './services/views/view-manager.js';
9
9
  export type { ViewManager } from './services/views/view-manager.js';
10
+ export type { WorkspaceService } from './services/workspace/workspace-service.js';
11
+ export type { Project, ProjectPages, ProjectSettings } from './services/projects/project-repository.js';
12
+ export { registerSimulatorApi } from './simulator-apis.js';
13
+ export type { SimulatorApiHandler } from './simulator-apis.js';
10
14
  export { registerAppIpc } from './ipc/app.js';
11
15
  export { registerSimulatorIpc } from './ipc/simulator.js';
12
16
  export { registerPanelsIpc } from './ipc/panels.js';
@@ -15,8 +19,8 @@ export { registerSettingsIpc } from './ipc/settings.js';
15
19
  export { registerProjectsIpc } from './ipc/projects.js';
16
20
  export { registerSessionIpc } from './ipc/session.js';
17
21
  export { registerToolbarIpc } from './ipc/toolbar.js';
18
- export { rendererDir, defaultPreloadPath, getRendererDir, getPreloadDir, getRendererHtml } from './utils/paths.js';
19
- export { simulatorDir } from './services/simulator/dir.js';
22
+ export { rendererDir, defaultPreloadPath, simulatorDir, getRendererDir, getPreloadDir, getRendererHtml, } from './utils/paths.js';
23
+ export { setHeaderHeight } from './services/layout/index.js';
20
24
  export { UpdateManager, createGitHubReleaseChecker } from './services/update/index.js';
21
25
  export type { UpdateManagerOptions, GitHubReleaseCheckerOptions, PickAssetContext, VersionScheme, } from './services/update/index.js';
22
26
  export type { WorkbenchConfig, WorkbenchAppConfig, CompilationAdapter, ProjectSession, ToolbarAction, BuiltinPanelId, BuiltinModuleId, UpdateChecker, UpdateInfo, } from '../shared/types.js';