@dimina-kit/devtools 0.4.0-dev.20260828161241 → 0.4.0-dev.20260907055341

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 (277) hide show
  1. package/README.md +52 -729
  2. package/dist/main/app/app.d.ts +27 -7
  3. package/dist/main/app/app.js +285 -681
  4. package/dist/main/app/editor-view.d.ts +21 -0
  5. package/dist/main/app/editor-view.js +71 -0
  6. package/dist/main/app/global-mirrors.d.ts +23 -0
  7. package/dist/main/app/global-mirrors.js +37 -0
  8. package/dist/main/app/host-sidebar-default.d.ts +19 -0
  9. package/dist/main/app/host-sidebar-default.js +44 -0
  10. package/dist/main/app/menu-setup.d.ts +13 -0
  11. package/dist/main/app/menu-setup.js +49 -0
  12. package/dist/main/app/open-project-ipc.d.ts +13 -0
  13. package/dist/main/app/open-project-ipc.js +21 -0
  14. package/dist/main/app/project-list-surface.d.ts +31 -0
  15. package/dist/main/app/project-list-surface.js +20 -0
  16. package/dist/main/app/project-window.d.ts +36 -0
  17. package/dist/main/app/project-window.js +93 -0
  18. package/dist/main/app/servers.d.ts +17 -0
  19. package/dist/main/app/servers.js +60 -0
  20. package/dist/main/app/ui-extension-targets.d.ts +42 -0
  21. package/dist/main/app/ui-extension-targets.js +101 -0
  22. package/dist/main/app/window-close-reveal.harness.d.ts +34 -0
  23. package/dist/main/app/window-close-reveal.harness.js +65 -0
  24. package/dist/main/app/window-events.d.ts +15 -0
  25. package/dist/main/app/window-events.js +45 -0
  26. package/dist/main/app/window-runtime-services.d.ts +41 -0
  27. package/dist/main/app/window-runtime-services.js +178 -0
  28. package/dist/main/app/workbench-modules.d.ts +24 -0
  29. package/dist/main/app/workbench-modules.js +51 -0
  30. package/dist/main/app/workbench-window.d.ts +85 -0
  31. package/dist/main/app/workbench-window.js +310 -0
  32. package/dist/main/index.bundle.js +10669 -9096
  33. package/dist/main/ipc/app.d.ts +4 -1
  34. package/dist/main/ipc/app.js +4 -3
  35. package/dist/main/ipc/device-picker.d.ts +16 -0
  36. package/dist/main/ipc/device-picker.js +27 -0
  37. package/dist/main/ipc/index.d.ts +1 -0
  38. package/dist/main/ipc/index.js +1 -0
  39. package/dist/main/ipc/internal-devtools.d.ts +2 -1
  40. package/dist/main/ipc/internal-devtools.js +4 -3
  41. package/dist/main/ipc/popover.d.ts +4 -1
  42. package/dist/main/ipc/popover.js +25 -9
  43. package/dist/main/ipc/project-create.d.ts +2 -1
  44. package/dist/main/ipc/project-create.js +6 -5
  45. package/dist/main/ipc/project-fs.d.ts +3 -1
  46. package/dist/main/ipc/project-fs.js +17 -17
  47. package/dist/main/ipc/projects.d.ts +3 -3
  48. package/dist/main/ipc/projects.js +13 -12
  49. package/dist/main/ipc/session.d.ts +4 -1
  50. package/dist/main/ipc/session.js +16 -11
  51. package/dist/main/ipc/settings.d.ts +4 -1
  52. package/dist/main/ipc/settings.js +12 -19
  53. package/dist/main/ipc/simulator-module.d.ts +5 -0
  54. package/dist/main/ipc/simulator-module.js +9 -5
  55. package/dist/main/ipc/simulator.d.ts +4 -1
  56. package/dist/main/ipc/simulator.js +12 -18
  57. package/dist/main/ipc/tooltip.d.ts +2 -1
  58. package/dist/main/ipc/tooltip.js +8 -7
  59. package/dist/main/ipc/views.d.ts +4 -1
  60. package/dist/main/ipc/views.js +20 -9
  61. package/dist/main/runtime/devtools-backend-before-quit.harness.d.ts +2 -20
  62. package/dist/main/runtime/devtools-backend-before-quit.harness.js +14 -283
  63. package/dist/main/runtime/devtools-backend.js +14 -3
  64. package/dist/main/runtime/devtools-runtime-mock.harness.d.ts +21 -0
  65. package/dist/main/runtime/devtools-runtime-mock.harness.js +313 -0
  66. package/dist/main/services/app-services.d.ts +62 -0
  67. package/dist/main/services/app-services.js +64 -0
  68. package/dist/main/services/automation/connection-target.d.ts +36 -0
  69. package/dist/main/services/automation/connection-target.js +29 -0
  70. package/dist/main/services/automation/console-bridge.d.ts +28 -0
  71. package/dist/main/services/automation/console-bridge.js +91 -0
  72. package/dist/main/services/automation/handlers/app.js +4 -4
  73. package/dist/main/services/automation/handlers/element.js +55 -21
  74. package/dist/main/services/automation/index.d.ts +12 -1
  75. package/dist/main/services/automation/index.js +54 -133
  76. package/dist/main/services/default-adapter.js +1 -1
  77. package/dist/main/services/fs-bridge-protocol.d.ts +61 -0
  78. package/dist/main/services/fs-bridge-protocol.js +34 -0
  79. package/dist/main/services/fs-watch-sse.d.ts +8 -1
  80. package/dist/main/services/fs-watch-sse.js +19 -5
  81. package/dist/main/services/mcp/connection-owner.d.ts +38 -0
  82. package/dist/main/services/mcp/connection-owner.js +79 -0
  83. package/dist/main/services/mcp/index.d.ts +3 -1
  84. package/dist/main/services/mcp/index.js +4 -3
  85. package/dist/main/services/mcp/opened-project.d.ts +88 -0
  86. package/dist/main/services/mcp/opened-project.js +60 -0
  87. package/dist/main/services/mcp/target-manager.d.ts +71 -23
  88. package/dist/main/services/mcp/target-manager.js +269 -142
  89. package/dist/main/services/mcp/target-selection.d.ts +47 -0
  90. package/dist/main/services/mcp/target-selection.js +71 -0
  91. package/dist/main/services/mcp/tools/context-tools.js +20 -5
  92. package/dist/main/services/mcp/tools/project-tools.d.ts +29 -6
  93. package/dist/main/services/mcp/tools/project-tools.js +37 -25
  94. package/dist/main/services/module.d.ts +13 -5
  95. package/dist/main/services/notifications/renderer-notifier.d.ts +28 -4
  96. package/dist/main/services/notifications/renderer-notifier.js +15 -3
  97. package/dist/main/services/projects/local-provider.js +2 -0
  98. package/dist/main/services/projects/project-repository.d.ts +31 -1
  99. package/dist/main/services/projects/project-repository.js +144 -20
  100. package/dist/main/services/projects/types.d.ts +31 -8
  101. package/dist/main/services/safe-area/index.d.ts +19 -5
  102. package/dist/main/services/safe-area/index.js +38 -13
  103. package/dist/main/services/simulator/ui-extensions.d.ts +8 -0
  104. package/dist/main/services/simulator/ui-extensions.js +16 -6
  105. package/dist/main/services/simulator-storage/index.d.ts +12 -1
  106. package/dist/main/services/simulator-storage/index.js +22 -7
  107. package/dist/main/services/simulator-storage/window-scope.d.ts +20 -0
  108. package/dist/main/services/simulator-storage/window-scope.js +20 -0
  109. package/dist/main/services/views/host-slot-port-channel.d.ts +20 -3
  110. package/dist/main/services/views/host-slot-port-channel.js +33 -5
  111. package/dist/main/services/views/managed-web-contents-view.js +21 -1
  112. package/dist/main/services/views/native-simulator-view.js +13 -16
  113. package/dist/main/services/views/overlay-panels-view.d.ts +13 -0
  114. package/dist/main/services/views/overlay-panels-view.js +31 -0
  115. package/dist/main/services/views/view-manager.d.ts +1 -1
  116. package/dist/main/services/views/view-manager.js +3 -0
  117. package/dist/main/services/window-contexts/context-router.d.ts +36 -0
  118. package/dist/main/services/window-contexts/context-router.js +55 -0
  119. package/dist/main/services/workbench-coi-host.d.ts +52 -0
  120. package/dist/main/services/workbench-coi-host.js +227 -0
  121. package/dist/main/services/workbench-coi-server.js +75 -133
  122. package/dist/main/services/workbench-coi-shutdown.d.ts +40 -0
  123. package/dist/main/services/workbench-coi-shutdown.js +69 -0
  124. package/dist/main/services/workbench-coi-static.d.ts +23 -0
  125. package/dist/main/services/workbench-coi-static.js +87 -0
  126. package/dist/main/services/workbench-context.d.ts +27 -3
  127. package/dist/main/services/workbench-context.js +10 -5
  128. package/dist/main/services/workspace/compile-mode-adapter.d.ts +18 -0
  129. package/dist/main/services/workspace/compile-mode-adapter.js +57 -0
  130. package/dist/main/services/workspace/compile-mode-store.d.ts +25 -0
  131. package/dist/main/services/workspace/compile-mode-store.js +71 -0
  132. package/dist/main/services/workspace/workspace-compile-modes.d.ts +59 -0
  133. package/dist/main/services/workspace/workspace-compile-modes.js +93 -0
  134. package/dist/main/services/workspace/workspace-referer.d.ts +17 -0
  135. package/dist/main/services/workspace/workspace-referer.js +26 -0
  136. package/dist/main/services/workspace/workspace-service.d.ts +4 -0
  137. package/dist/main/services/workspace/workspace-service.js +51 -84
  138. package/dist/main/services/workspace/workspace-thumbnails.d.ts +22 -0
  139. package/dist/main/services/workspace/workspace-thumbnails.js +67 -0
  140. package/dist/main/utils/ipc-context-source.d.ts +40 -0
  141. package/dist/main/utils/ipc-context-source.js +23 -0
  142. package/dist/main/utils/ipc-registry.d.ts +42 -36
  143. package/dist/main/utils/ipc-registry.js +117 -50
  144. package/dist/main/utils/sender-policy.d.ts +9 -0
  145. package/dist/main/utils/sender-policy.js +26 -3
  146. package/dist/main/utils/theme.d.ts +3 -2
  147. package/dist/main/utils/theme.js +3 -2
  148. package/dist/main/windows/main-window/create.d.ts +16 -0
  149. package/dist/main/windows/main-window/create.js +19 -11
  150. package/dist/main/windows/main-window/events.d.ts +1 -1
  151. package/dist/main/windows/main-window/events.js +26 -13
  152. package/dist/main/windows/main-window/index.d.ts +1 -1
  153. package/dist/main/windows/main-window/index.js +1 -1
  154. package/dist/native-host/common/common.js +94 -73
  155. package/dist/native-host/render/render.js +4079 -3171
  156. package/dist/native-host/service/service.js +2 -2
  157. package/dist/preload/runtime/native-host.d.ts +4 -0
  158. package/dist/preload/runtime/temp-files.js +9 -2
  159. package/dist/preload/runtime/wait-for-slot-root.d.ts +7 -4
  160. package/dist/preload/runtime/wait-for-slot-root.js +36 -8
  161. package/dist/preload/windows/host-dialog-runtime.cjs +10 -3
  162. package/dist/preload/windows/host-dialog-runtime.cjs.map +2 -2
  163. package/dist/preload/windows/host-sidebar-runtime.cjs +10 -3
  164. package/dist/preload/windows/host-sidebar-runtime.cjs.map +2 -2
  165. package/dist/preload/windows/host-toolbar-runtime.cjs +10 -3
  166. package/dist/preload/windows/host-toolbar-runtime.cjs.map +2 -2
  167. package/dist/preload/windows/main.cjs +181 -4
  168. package/dist/preload/windows/main.cjs.map +4 -4
  169. package/dist/preload/windows/simulator.cjs +10 -0
  170. package/dist/preload/windows/simulator.cjs.map +2 -2
  171. package/dist/preload/windows/simulator.js +10 -0
  172. package/dist/render-host/pageFrame.html +1 -1
  173. package/dist/render-host/preload.cjs +16 -4
  174. package/dist/renderer/assets/button-CB2MWjHY.js +2 -0
  175. package/dist/renderer/assets/constants-CkoGPQTS.js +2 -0
  176. package/dist/renderer/assets/constants-zQZ2-y21.js +2 -0
  177. package/dist/renderer/assets/{createLucideIcon-Bqi8hpdi.js → createLucideIcon-cZ9FlZZw.js} +2 -2
  178. package/dist/renderer/assets/devicePicker-H2eIO4e1.js +2 -0
  179. package/dist/renderer/assets/dialog-pHzEA8Vx.js +46 -0
  180. package/dist/renderer/assets/dist-B5HADirS.js +2 -0
  181. package/dist/renderer/assets/{dist-DKWdE1TK.js → dist-DIFlRMKe.js} +2 -2
  182. package/dist/renderer/assets/hostSidebarDefault-DRWh6OCt.js +2 -0
  183. package/dist/renderer/assets/index-CEL_XFge.js +2 -0
  184. package/dist/renderer/assets/{input-Ct3alvkq.js → input-CAObw95L.js} +2 -2
  185. package/dist/renderer/assets/ipc-channels-overlays-gIPUFnqc.js +2 -0
  186. package/dist/renderer/assets/jsx-runtime-DICEQH_0.css +1 -0
  187. package/dist/renderer/assets/{jsx-runtime-DGLHmmOq.js → jsx-runtime-DIw5wnYl.js} +1 -1
  188. package/dist/renderer/assets/plus-BQ9u5EbL.js +2 -0
  189. package/dist/renderer/assets/popover-Cw7G2Ctp.js +2 -0
  190. package/dist/renderer/assets/presets-DMZOb9ay.js +2 -0
  191. package/dist/renderer/assets/project-api-YTOr_Yvo.js +2 -0
  192. package/dist/renderer/assets/{projectCreateDialog-Bbjz75bP.js → projectCreateDialog-BmLqiYxn.js} +2 -2
  193. package/dist/renderer/assets/search-BMvuYF48.js +2 -0
  194. package/dist/renderer/assets/select-nFP95TxM.js +2 -0
  195. package/dist/renderer/assets/settings-CnpVfSWt.js +2 -0
  196. package/dist/renderer/assets/settings-api-Ccsf-Nsj.js +2 -0
  197. package/dist/renderer/assets/settings-tab-bar-CAzrv32m.js +2 -0
  198. package/dist/renderer/assets/smartphone-Bb2GdIKy.js +2 -0
  199. package/dist/renderer/assets/tabs-CPKN3Mmq.js +2 -0
  200. package/dist/renderer/assets/{tooltip-B_-_YVbw.js → tooltip-D6AxXRk5.js} +2 -2
  201. package/dist/renderer/assets/types-Bh0hA7El.js +2 -0
  202. package/dist/renderer/assets/updateDialog-CwndJ0Bl.js +2 -0
  203. package/dist/renderer/assets/{utils-kfQov6Pa.js → utils-sEB5OZEQ.js} +2 -2
  204. package/dist/renderer/assets/view-api-B-2zPBR5.js +2 -0
  205. package/dist/renderer/assets/view-ids-BfaDVV5P.js +2 -0
  206. package/dist/renderer/assets/workbench-BLJ0wKsg.js +5 -0
  207. package/dist/renderer/assets/{workbenchSettings-CV4LVA9b.js → workbenchSettings-YD0Ctbm_.js} +3 -3
  208. package/dist/renderer/entries/device-picker/index.html +28 -0
  209. package/dist/renderer/entries/host-sidebar-default/index.html +6 -5
  210. package/dist/renderer/entries/main/index.html +16 -17
  211. package/dist/renderer/entries/popover/index.html +16 -10
  212. package/dist/renderer/entries/project-create-dialog/index.html +12 -12
  213. package/dist/renderer/entries/settings/index.html +10 -10
  214. package/dist/renderer/entries/tooltip/index.html +5 -5
  215. package/dist/renderer/entries/update-dialog/index.html +10 -10
  216. package/dist/renderer/entries/workbench/index.html +49 -0
  217. package/dist/renderer/entries/workbench-settings/index.html +12 -11
  218. package/dist/service-host/host-env-update.cjs +23 -0
  219. package/dist/service-host/preload.cjs +24 -49
  220. package/dist/service-host/service-message-queue.cjs +71 -0
  221. package/dist/service-host/sync-impls/system-info.js +31 -9
  222. package/dist/shared/compile-mode-state.d.ts +73 -0
  223. package/dist/shared/compile-mode-state.js +100 -0
  224. package/dist/shared/compile-modes.d.ts +152 -0
  225. package/dist/shared/compile-modes.js +237 -0
  226. package/dist/shared/ipc-channels-overlays.d.ts +8 -2
  227. package/dist/shared/ipc-channels-overlays.js +19 -2
  228. package/dist/shared/ipc-channels.d.ts +5 -10
  229. package/dist/shared/ipc-channels.js +17 -14
  230. package/dist/shared/ipc-schemas.d.ts +76 -24
  231. package/dist/shared/ipc-schemas.js +55 -10
  232. package/dist/shared/project-window-types.d.ts +42 -0
  233. package/dist/shared/project-window-types.js +2 -0
  234. package/dist/shared/types.d.ts +43 -17
  235. package/dist/shared/view-ids.d.ts +1 -0
  236. package/dist/shared/view-ids.js +3 -1
  237. package/dist/simulator/assets/bridge-channels-B3JAmRfl.js +2 -0
  238. package/dist/simulator/assets/device-shell-ATEhHV2_.css +1 -0
  239. package/dist/simulator/assets/device-shell-pxnZZp10.js +431 -0
  240. package/dist/simulator/assets/simulator-Dwp7lnvu.js +10 -0
  241. package/dist/simulator/assets/simulator-mini-app-DFo7fhi5.js +2 -0
  242. package/dist/simulator/assets/simulator-ui-B2ddJB1R.js +2 -0
  243. package/dist/simulator/simulator.html +3 -3
  244. package/dist/simulator/temp-files.d.ts +6 -0
  245. package/dist/simulator/temp-files.js +46 -4
  246. package/dist/simulator/types.d.ts +7 -0
  247. package/dist/vscode-workbench/assets/__vite-browser-external-JIkWewFf.js +1 -0
  248. package/dist/vscode-workbench/assets/{dist-CMfmHflW.js → dist-CXG-u1VB.js} +3 -3
  249. package/dist/vscode-workbench/assets/{iconv-lite-umd-Bx8CgaZq.js → iconv-lite-umd-Dxx9Qyb4.js} +1 -1
  250. package/dist/vscode-workbench/assets/{index-CdG6YWhW.js → index-6VJMsaWj.js} +460 -460
  251. package/dist/vscode-workbench/assets/{jschardet-M0qgd2lN.js → jschardet-Ba3D16vt.js} +1 -1
  252. package/dist/vscode-workbench/index.html +1 -1
  253. package/package.json +11 -8
  254. package/dist/renderer/assets/button-D5Q2wkXq.js +0 -2
  255. package/dist/renderer/assets/constants-D7DfVqMp.js +0 -2
  256. package/dist/renderer/assets/constants-D8zsejFq.js +0 -2
  257. package/dist/renderer/assets/dialog-e1TecTOY.js +0 -46
  258. package/dist/renderer/assets/hostSidebarDefault-B3yLfy8j.js +0 -2
  259. package/dist/renderer/assets/index-CsPD68N_.js +0 -5
  260. package/dist/renderer/assets/ipc-channels-overlays-LsDzGAtV.js +0 -2
  261. package/dist/renderer/assets/jsx-runtime-2vXHouwr.css +0 -1
  262. package/dist/renderer/assets/popover-Dix5cm_b.js +0 -2
  263. package/dist/renderer/assets/project-api-k7Oq9iaq.js +0 -2
  264. package/dist/renderer/assets/select-acGb0AmJ.js +0 -2
  265. package/dist/renderer/assets/settings-CQrTMr43.js +0 -2
  266. package/dist/renderer/assets/settings-api-CrUQ9rYV.js +0 -2
  267. package/dist/renderer/assets/settings-tab-bar-Cw1kVIf2.js +0 -2
  268. package/dist/renderer/assets/types-CsEKtFyr.js +0 -2
  269. package/dist/renderer/assets/updateDialog-NsF8223A.js +0 -2
  270. package/dist/renderer/assets/view-api-CLn3rcQE.js +0 -2
  271. package/dist/simulator/assets/bridge-channels-zhsumfky.js +0 -2
  272. package/dist/simulator/assets/device-shell-CmtM1QxP.js +0 -2
  273. package/dist/simulator/assets/device-shell-iFZo1igL.css +0 -1
  274. package/dist/simulator/assets/simulator-CIobn3Mh.js +0 -10
  275. package/dist/simulator/assets/simulator-mini-app-CRe6n9br.js +0 -2
  276. package/dist/simulator/assets/simulator-ui-C_cP602X.js +0 -2
  277. package/dist/vscode-workbench/assets/__vite-browser-external-Bc1vizTf.js +0 -1
@@ -1,41 +1,35 @@
1
- import { ServiceHostChannel, SimulatorChannel, SimulatorCustomApiChannel } from '../../shared/ipc-channels.js';
1
+ import { SimulatorChannel, SimulatorCustomApiChannel } from '../../shared/ipc-channels.js';
2
2
  import { SimulatorAttachNativeSchema, SimulatorCustomApiInvokeSchema, SimulatorSetDeviceInfoSchema, SimulatorSoftReloadSchema, } from '../../shared/ipc-schemas.js';
3
- import { deviceInfoToHostEnv } from '../../shared/bridge-channels.js';
4
3
  import { validate } from '../utils/ipc-schema.js';
5
4
  import { IpcRegistry } from '../utils/ipc-registry.js';
6
- export function registerSimulatorIpc(ctx) {
7
- return new IpcRegistry(ctx.senderPolicy)
8
- .handle(SimulatorChannel.AttachNative, (_, ...args) => {
5
+ import { toIpcContextSource } from '../utils/ipc-context-source.js';
6
+ export function registerSimulatorIpc(input) {
7
+ return new IpcRegistry(toIpcContextSource(input))
8
+ .handleRouted(SimulatorChannel.AttachNative, (ctx, _e, ...args) => {
9
9
  const [simulatorUrl, simWidth] = validate(SimulatorChannel.AttachNative, SimulatorAttachNativeSchema, args);
10
10
  return ctx.views.attachNativeSimulator(simulatorUrl, simWidth);
11
11
  })
12
- .handle(SimulatorChannel.SoftReload, (_, ...args) => {
12
+ .handleRouted(SimulatorChannel.SoftReload, (ctx, _e, ...args) => {
13
13
  const [simulatorUrl] = validate(SimulatorChannel.SoftReload, SimulatorSoftReloadSchema, args);
14
14
  return ctx.views.softReloadNativeSimulator(simulatorUrl);
15
15
  })
16
- .handle(SimulatorChannel.Detach, () => {
16
+ .handleRouted(SimulatorChannel.Detach, (ctx) => {
17
17
  ctx.views.detachSimulator();
18
18
  })
19
- .handle(SimulatorChannel.SetDeviceInfo, (_, ...args) => {
19
+ .handleRouted(SimulatorChannel.SetDeviceInfo, (ctx, _e, ...args) => {
20
20
  const [device] = validate(SimulatorChannel.SetDeviceInfo, SimulatorSetDeviceInfoSchema, args);
21
21
  // Cache the selection (rides the next NATIVE_HOST_ENABLED reply for a
22
22
  // race-free DeviceShell init) and push DEVICE_CHANGE to the live simulator
23
23
  // WCV so the DeviceShell resizes the bezel + re-renders status bar / notch.
24
+ // `setDevice` also pushes `hostEnvUpdate` + `pageResize` to every running
25
+ // service host, so `wx.getSystemInfoSync()` and `Page.onResize` follow
26
+ // the selection without a relaunch.
24
27
  ctx.bridge?.setDevice(device);
25
28
  // Re-push the CSS env(safe-area-inset-*) override to attached render-host
26
29
  // guests so notch-aware page layout updates without a reload.
27
30
  ctx.views.reapplySafeArea(device);
28
- // Live-update the running service-host window's host-env snapshot so
29
- // `wx.getSystemInfoSync()` reflects the selected device without a relaunch.
30
- // The service-host preload mutates `__diminaSpawnContext` in place;
31
- // `getSystemInfoSync` reads it fresh on each call. No service window yet
32
- // (pre-spawn) → no-op.
33
- const serviceWc = ctx.bridge?.getServiceWc();
34
- if (serviceWc && !serviceWc.isDestroyed()) {
35
- serviceWc.send(ServiceHostChannel.HostEnvUpdate, deviceInfoToHostEnv(device));
36
- }
37
31
  })
38
- .handle(SimulatorCustomApiChannel.Invoke, (_, ...args) => {
32
+ .handleRouted(SimulatorCustomApiChannel.Invoke, (ctx, _e, ...args) => {
39
33
  const [name, params] = validate(SimulatorCustomApiChannel.Invoke, SimulatorCustomApiInvokeSchema, args);
40
34
  return ctx.simulatorApis.invoke(name, params);
41
35
  });
@@ -2,12 +2,13 @@ import type { WorkbenchModule } from '../services/module.js';
2
2
  import type { ViewManager } from '../services/views/view-manager.js';
3
3
  import type { Disposable } from '@dimina-kit/electron-deck/main';
4
4
  import { type SenderPolicy } from '../utils/ipc-registry.js';
5
+ import { type IpcInput } from '../utils/ipc-context-source.js';
5
6
  /** Module-local narrow deps — deliberately NOT `Pick<WorkbenchContext, ...>`
6
7
  * (the gate in eslint.config.* is shrink-only; see its message). */
7
8
  export interface TooltipIpcDeps {
8
9
  views: Pick<ViewManager, 'prepareTooltip' | 'showTooltip' | 'hideTooltip' | 'markOverlayReady' | 'applyTooltipMeasurement'>;
9
10
  senderPolicy?: SenderPolicy;
10
11
  }
11
- export declare function registerTooltipIpc(ctx: TooltipIpcDeps): Disposable;
12
+ export declare function registerTooltipIpc(input: IpcInput<TooltipIpcDeps>): Disposable;
12
13
  export declare const tooltipModule: WorkbenchModule;
13
14
  //# sourceMappingURL=tooltip.d.ts.map
@@ -2,22 +2,23 @@ import { OverlayChannel, TooltipChannel } from '../../shared/ipc-channels-overla
2
2
  import { TooltipMeasuredSchema, TooltipShowSchema } from '../../shared/ipc-schemas.js';
3
3
  import { validate } from '../utils/ipc-schema.js';
4
4
  import { IpcRegistry } from '../utils/ipc-registry.js';
5
- export function registerTooltipIpc(ctx) {
6
- return new IpcRegistry(ctx.senderPolicy)
7
- .on(TooltipChannel.Prepare, () => {
5
+ import { toIpcContextSource } from '../utils/ipc-context-source.js';
6
+ export function registerTooltipIpc(input) {
7
+ return new IpcRegistry(toIpcContextSource(input))
8
+ .onRouted(TooltipChannel.Prepare, (ctx) => {
8
9
  ctx.views.prepareTooltip();
9
10
  })
10
- .on(TooltipChannel.Show, (_event, ...args) => {
11
+ .onRouted(TooltipChannel.Show, (ctx, _event, ...args) => {
11
12
  const [data] = validate(TooltipChannel.Show, TooltipShowSchema, args);
12
13
  ctx.views.showTooltip(data);
13
14
  })
14
- .on(TooltipChannel.Hide, () => {
15
+ .onRouted(TooltipChannel.Hide, (ctx) => {
15
16
  ctx.views.hideTooltip();
16
17
  })
17
- .on(OverlayChannel.Ready, (event) => {
18
+ .onRouted(OverlayChannel.Ready, (ctx, event) => {
18
19
  ctx.views.markOverlayReady(event.sender.id);
19
20
  })
20
- .on(TooltipChannel.Measured, (event, ...args) => {
21
+ .onRouted(TooltipChannel.Measured, (ctx, event, ...args) => {
21
22
  const [measurement] = validate(TooltipChannel.Measured, TooltipMeasuredSchema, args);
22
23
  ctx.views.applyTooltipMeasurement(event.sender.id, measurement);
23
24
  });
@@ -1,5 +1,7 @@
1
1
  import type { WorkbenchContext } from '../services/workbench-context.js';
2
2
  import type { Disposable } from '@dimina-kit/electron-deck/main';
3
+ import { type IpcInput } from '../utils/ipc-context-source.js';
4
+ type ViewsIpcCtx = Pick<WorkbenchContext, 'views' | 'senderPolicy'>;
3
5
  /**
4
6
  * Renderer-driven overlay bounds, plus the renderer bootstrap's
5
7
  * placement-generation seed pull.
@@ -29,5 +31,6 @@ import type { Disposable } from '@dimina-kit/electron-deck/main';
29
31
  * disables it on the fatal boot-failure page, or leave placement silently
30
32
  * non-functional. See disabled-module.test.ts for the end-to-end guard.
31
33
  */
32
- export declare function registerViewsIpc(ctx: Pick<WorkbenchContext, 'views' | 'senderPolicy'>): Disposable;
34
+ export declare function registerViewsIpc(input: IpcInput<ViewsIpcCtx>): Disposable;
35
+ export {};
33
36
  //# sourceMappingURL=views.d.ts.map
@@ -3,6 +3,7 @@ import { ViewChannel } from '../../shared/ipc-channels-overlays.js';
3
3
  import { PlacementSnapshotSchema, HostToolbarAdvertiseHeightSchema, HostSidebarAdvertiseWidthSchema, HostDialogAdvertiseSizeSchema, } from '../../shared/ipc-schemas.js';
4
4
  import { validate } from '../utils/ipc-schema.js';
5
5
  import { IpcRegistry } from '../utils/ipc-registry.js';
6
+ import { toIpcContextSource } from '../utils/ipc-context-source.js';
6
7
  /**
7
8
  * Renderer-driven overlay bounds, plus the renderer bootstrap's
8
9
  * placement-generation seed pull.
@@ -32,16 +33,23 @@ import { IpcRegistry } from '../utils/ipc-registry.js';
32
33
  * disables it on the fatal boot-failure page, or leave placement silently
33
34
  * non-functional. See disabled-module.test.ts for the end-to-end guard.
34
35
  */
35
- export function registerViewsIpc(ctx) {
36
- const registry = new IpcRegistry(ctx.senderPolicy)
36
+ export function registerViewsIpc(input) {
37
+ const source = toIpcContextSource(input);
38
+ // The raw listeners below trust an exact wc id, and each window mounts its
39
+ // own host slots — so the id itself names the owning window. Scanning the
40
+ // live contexts for the one whose slot holds this sender is both the trust
41
+ // gate and the routing decision; no match means the message came from
42
+ // somewhere that is not a host slot at all, and is dropped.
43
+ const ownerOfSlot = (event, slotWebContentsId) => source.list().find((ctx) => slotWebContentsId(ctx) === event.sender.id) ?? null;
44
+ const registry = new IpcRegistry(source)
37
45
  // Renderer bootstrap: allocate this session's placement-generation seed
38
46
  // (see renderer-placement-generation.ts / PlacementReconciler.allocateGeneration).
39
- .handle(ViewChannel.AllocatePlacementGeneration, () => ctx.views.allocatePlacementGeneration())
47
+ .handleRouted(ViewChannel.AllocatePlacementGeneration, (ctx) => ctx.views.allocatePlacementGeneration())
40
48
  // Window-level placement snapshot: the single source of truth for every
41
49
  // managed native view's bounds/visibility/z-order. The renderer's central
42
50
  // publisher coalesces one snapshot per frame; the reconciler diffs it
43
51
  // against the actual view tree. Supersedes the per-view bounds channels.
44
- .handle(ViewChannel.PlacementSnapshot, (_event, ...args) => {
52
+ .handleRouted(ViewChannel.PlacementSnapshot, (ctx, _event, ...args) => {
45
53
  const [snapshot] = validate(ViewChannel.PlacementSnapshot, PlacementSnapshotSchema, args);
46
54
  ctx.views.setPlacementSnapshot(snapshot);
47
55
  })
@@ -53,10 +61,10 @@ export function registerViewsIpc(ctx) {
53
61
  // senderPolicy-gated registry as HostToolbarBounds: the toolbar WCV's
54
62
  // arbitrary host content must not reach this — only the trusted main
55
63
  // renderer pulls. Live delegation, not a registration-time snapshot.
56
- .handle(ViewChannel.HostToolbarGetHeight, () => ctx.views.getHostToolbarHeight())
64
+ .handleRouted(ViewChannel.HostToolbarGetHeight, (ctx) => ctx.views.getHostToolbarHeight())
57
65
  // Same mount-time replay role as HostToolbarGetHeight, on the sidebar's
58
66
  // inline (width) axis.
59
- .handle(ViewChannel.HostSidebarGetWidth, () => ctx.views.getHostSidebarWidth());
67
+ .handleRouted(ViewChannel.HostSidebarGetWidth, (ctx) => ctx.views.getHostSidebarWidth());
60
68
  // Reverse size-advertiser: the toolbar WCV's OWN renderer sends this, and the
61
69
  // host loads ARBITRARY content into that WCV. We DELIBERATELY do NOT add the
62
70
  // toolbar wc to the global sender policy — that would trust it for ALL ~72
@@ -68,7 +76,8 @@ export function registerViewsIpc(ctx) {
68
76
  // The host content can reach ONLY this one channel, carrying only a
69
77
  // non-negative integer height.
70
78
  const onAdvertiseHeight = (event, ...args) => {
71
- if (event.sender.id !== ctx.views.getHostToolbarWebContentsId())
79
+ const ctx = ownerOfSlot(event, (c) => c.views.getHostToolbarWebContentsId());
80
+ if (!ctx)
72
81
  return;
73
82
  let extent;
74
83
  try {
@@ -84,7 +93,8 @@ export function registerViewsIpc(ctx) {
84
93
  // Same precise-sender-id trust model as onAdvertiseHeight, on the
85
94
  // sidebar's inline (width) axis.
86
95
  const onAdvertiseWidth = (event, ...args) => {
87
- if (event.sender.id !== ctx.views.getHostSidebarWebContentsId())
96
+ const ctx = ownerOfSlot(event, (c) => c.views.getHostSidebarWebContentsId());
97
+ if (!ctx)
88
98
  return;
89
99
  let extent;
90
100
  try {
@@ -102,7 +112,8 @@ export function registerViewsIpc(ctx) {
102
112
  // slot: either axis may arrive, and the view manager re-centers using
103
113
  // whichever axes it has measured so far.
104
114
  const onAdvertiseDialogSize = (event, ...args) => {
105
- if (event.sender.id !== ctx.views.getHostDialogWebContentsId())
115
+ const ctx = ownerOfSlot(event, (c) => c.views.getHostDialogWebContentsId());
116
+ if (!ctx)
106
117
  return;
107
118
  let axis;
108
119
  let extent;
@@ -1,30 +1,12 @@
1
1
  import type { WorkbenchAppConfig } from '../../shared/types.js';
2
2
  import type { RuntimeBackend } from '@dimina-kit/electron-deck';
3
- declare const stubs: {
4
- handlers: Map<string, (...args: unknown[]) => unknown>;
5
- projectsJsonPath: string;
6
- getProjectsJson(): string | null;
7
- setProjectsJson(v: string | null): void;
8
- projectsWithAppJson: Set<string>;
9
- makeEmitter: () => {
10
- listeners: Record<string, Set<(...args: unknown[]) => unknown>>;
11
- on(event: string, fn: (...args: unknown[]) => unknown): /*elided*/ any;
12
- once(event: string, fn: (...args: unknown[]) => unknown): /*elided*/ any;
13
- off(event: string, fn: (...args: unknown[]) => unknown): /*elided*/ any;
14
- removeListener(event: string, fn: (...args: unknown[]) => unknown): /*elided*/ any;
15
- emit(event: string, ...args: unknown[]): void;
16
- };
17
- reset: () => void;
18
- };
19
- declare const devkitStubs: {
20
- sessionClose: import("vitest").Mock<() => Promise<void>>;
21
- };
22
3
  declare const viewManagerStubs: {
23
4
  createdManagers: Array<{
24
5
  disposeAll: () => void;
25
6
  }>;
26
7
  };
27
- export { stubs, devkitStubs, viewManagerStubs };
8
+ export { stubs, devkitStubs } from './devtools-runtime-mock.harness.js';
9
+ export { viewManagerStubs };
28
10
  /**
29
11
  * Shared per-test setup both `devtools-backend-before-quit.test.ts` and
30
12
  * `devtools-backend-shutdown-race.test.ts` need identically: reset modules
@@ -1,291 +1,21 @@
1
1
  /**
2
2
  * Shared vitest mock harness for `devtools-backend-before-quit.test.ts` and
3
3
  * `devtools-backend-shutdown-race.test.ts` — both drive the REAL
4
- * `createDevtoolsBackend`/`createDevtoolsRuntime` against this same
5
- * electron/fs/`@dimina-kit/devkit`/view-manager mock set (lifted from
6
- * `quit-flag-onclose.test.ts`), split out to keep each test file under the
7
- * repo's 500-line file-length ratchet without duplicating ~350 lines of
8
- * mock setup between them.
4
+ * `createDevtoolsBackend`/`createDevtoolsRuntime` against the electron/fs/
5
+ * `@dimina-kit/devkit` mock set defined in `./devtools-runtime-mock.harness.ts`,
6
+ * plus the view-manager spy shim and backend-lifecycle helpers below that
7
+ * only these two tests need.
9
8
  *
10
- * `vi.mock(...)` calls here run once per importing test file's own isolated
11
- * module graph (vitest scopes mocking per test file), so importing this
12
- * module has the same effect as if each call were written directly in the
13
- * importing file — both test files' `beforeEach` still dynamically
14
- * `await import('./devtools-backend.js')` AFTER `vi.resetModules()`, well
15
- * after this module's mock registrations have already run.
9
+ * `vi.mock(...)` calls in the imported core module run once per importing
10
+ * test file's own isolated module graph (vitest scopes mocking per test
11
+ * file); chaining through this module has the same effect as if they were
12
+ * written directly in the importing file — both test files' `beforeEach`
13
+ * still dynamically `await import('./devtools-backend.js')` AFTER
14
+ * `vi.resetModules()`, well after the core module's mock registrations have
15
+ * already run.
16
16
  */
17
17
  import { beforeEach, expect, vi } from 'vitest';
18
- // ── Hoisted stub state (lifted from quit-flag-onclose.test.ts) ────────────
19
- // `export const x = vi.hoisted(...)` is rejected by vitest's hoisting
20
- // transform ("Cannot export hoisted variable") — declare then export below.
21
- const stubs = vi.hoisted(() => {
22
- const handlers = new Map();
23
- const projectsJsonPath = '/tmp/dimina-test-userdata/dimina-projects.json';
24
- let projectsJsonContent = null;
25
- const projectsWithAppJson = new Set();
26
- function makeEmitter() {
27
- const listeners = {};
28
- return {
29
- listeners,
30
- on(event, fn) {
31
- ;
32
- (listeners[event] ??= new Set()).add(fn);
33
- return this;
34
- },
35
- once(event, fn) {
36
- const wrap = (...args) => {
37
- listeners[event]?.delete(wrap);
38
- return fn(...args);
39
- };
40
- (listeners[event] ??= new Set()).add(wrap);
41
- return this;
42
- },
43
- off(event, fn) {
44
- listeners[event]?.delete(fn);
45
- return this;
46
- },
47
- removeListener(event, fn) {
48
- listeners[event]?.delete(fn);
49
- return this;
50
- },
51
- emit(event, ...args) {
52
- for (const fn of [...(listeners[event] ?? [])])
53
- fn(...args);
54
- },
55
- };
56
- }
57
- function reset() {
58
- handlers.clear();
59
- projectsJsonContent = null;
60
- projectsWithAppJson.clear();
61
- }
62
- return {
63
- handlers,
64
- projectsJsonPath,
65
- getProjectsJson() {
66
- return projectsJsonContent;
67
- },
68
- setProjectsJson(v) {
69
- projectsJsonContent = v;
70
- },
71
- projectsWithAppJson,
72
- makeEmitter,
73
- reset,
74
- };
75
- });
76
- // ── electron stub ────────────────────────────────────────────────────────
77
- // `app` is a live emitter so `registerAppLifecycle` can attach a
78
- // `before-quit` listener that the test fires directly.
79
- vi.mock('electron', () => {
80
- const ipcEmitter = stubs.makeEmitter();
81
- const ipcMain = {
82
- ...ipcEmitter,
83
- handle: vi.fn((channel, fn) => {
84
- stubs.handlers.set(channel, fn);
85
- }),
86
- removeHandler: vi.fn((channel) => {
87
- stubs.handlers.delete(channel);
88
- }),
89
- on: vi.fn((event, fn) => ipcEmitter.on(event, fn)),
90
- removeListener: vi.fn((event, fn) => ipcEmitter.removeListener(event, fn)),
91
- };
92
- const appEmitter = stubs.makeEmitter();
93
- const app = {
94
- ...appEmitter,
95
- isPackaged: true,
96
- whenReady: vi.fn(() => Promise.resolve()),
97
- getPath: vi.fn(() => '/tmp/dimina-test-userdata'),
98
- quit: vi.fn(),
99
- setName: vi.fn(),
100
- commandLine: {
101
- getSwitchValue: vi.fn(() => ''),
102
- appendSwitch: vi.fn(),
103
- },
104
- };
105
- // `WebContents` and `BrowserWindow` below both wrap a `stubs.makeEmitter()`
106
- // and need the SAME on/once/off/removeListener/emit delegation (the
107
- // emitter's own methods use `this` internally, so a plain property copy
108
- // would call them with the wrong receiver — each needs `.bind(em)`). Shared
109
- // base class instead of re-declaring the same 5 bound fields in both.
110
- class EmittingStub {
111
- em = stubs.makeEmitter();
112
- on = this.em.on.bind(this.em);
113
- once = this.em.once.bind(this.em);
114
- off = this.em.off.bind(this.em);
115
- removeListener = this.em.removeListener.bind(this.em);
116
- emit = this.em.emit.bind(this.em);
117
- }
118
- class WebContents extends EmittingStub {
119
- destroyed = false;
120
- id = Math.floor(Math.random() * 1e6);
121
- send = vi.fn();
122
- isDestroyed = () => this.destroyed;
123
- openDevTools = vi.fn();
124
- closeDevTools = vi.fn();
125
- setDevToolsWebContents = vi.fn();
126
- setWindowOpenHandler = vi.fn();
127
- loadFile = vi.fn(() => Promise.resolve());
128
- loadURL = vi.fn(() => Promise.resolve());
129
- executeJavaScript = vi.fn(() => Promise.resolve(undefined));
130
- reload = vi.fn();
131
- getType = () => 'window';
132
- getURL = () => '';
133
- debugger = {
134
- attach: vi.fn(),
135
- detach: vi.fn(),
136
- isAttached: () => false,
137
- on: vi.fn(),
138
- removeListener: vi.fn(),
139
- sendCommand: vi.fn(() => Promise.resolve({ entries: [] })),
140
- };
141
- close = vi.fn(() => {
142
- this.destroyed = true;
143
- });
144
- }
145
- class WebContentsView {
146
- webContents = new WebContents();
147
- setBounds = vi.fn();
148
- setBackgroundColor = vi.fn();
149
- }
150
- class View {
151
- children = [];
152
- addChildView(child) {
153
- this.children.push(child);
154
- }
155
- removeChildView(child) {
156
- const i = this.children.indexOf(child);
157
- if (i >= 0)
158
- this.children.splice(i, 1);
159
- }
160
- }
161
- class BrowserWindow extends EmittingStub {
162
- destroyed = false;
163
- webContents = new WebContents();
164
- contentView = new WebContentsView();
165
- isDestroyed = () => this.destroyed;
166
- getContentSize = () => [1280, 980];
167
- setIcon = vi.fn();
168
- setTitle = vi.fn();
169
- show = vi.fn();
170
- showInactive = vi.fn();
171
- focus = vi.fn();
172
- close = vi.fn();
173
- destroy = vi.fn(() => {
174
- this.destroyed = true;
175
- });
176
- loadFile = vi.fn(() => Promise.resolve());
177
- loadURL = vi.fn(() => Promise.resolve());
178
- static getAllWindows = vi.fn(() => []);
179
- }
180
- const sessionStub = {
181
- fromPartition: vi.fn(() => ({
182
- webRequest: {
183
- onBeforeSendHeaders: vi.fn(),
184
- onHeadersReceived: vi.fn(),
185
- },
186
- registerPreloadScript: vi.fn(),
187
- protocol: { handle: vi.fn(), unhandle: vi.fn() },
188
- })),
189
- defaultSession: {
190
- protocol: { handle: vi.fn(), unhandle: vi.fn() },
191
- },
192
- };
193
- const dialog = {
194
- showOpenDialog: vi.fn(() => Promise.resolve({ canceled: true, filePaths: [] })),
195
- showMessageBox: vi.fn(() => Promise.resolve({ response: 0 })),
196
- };
197
- const Menu = {
198
- buildFromTemplate: vi.fn((tpl) => ({ template: tpl })),
199
- setApplicationMenu: vi.fn(),
200
- };
201
- const shell = {
202
- openExternal: vi.fn(() => Promise.resolve()),
203
- openPath: vi.fn(() => Promise.resolve('')),
204
- };
205
- const nativeImage = {
206
- createFromPath: vi.fn(() => ({ isEmpty: () => true })),
207
- };
208
- const nativeTheme = { ...stubs.makeEmitter(), themeSource: 'system' };
209
- const globalShortcut = {
210
- register: vi.fn(() => false),
211
- unregister: vi.fn(),
212
- unregisterAll: vi.fn(),
213
- };
214
- const webContentsStatic = {
215
- fromId: vi.fn(() => null),
216
- getAllWebContents: vi.fn(() => []),
217
- };
218
- const Tray = vi.fn();
219
- return {
220
- app,
221
- ipcMain,
222
- BrowserWindow,
223
- WebContentsView,
224
- BrowserView: WebContentsView,
225
- View,
226
- webContents: webContentsStatic,
227
- session: sessionStub,
228
- protocol: { registerSchemesAsPrivileged: vi.fn(), handle: vi.fn(), unhandle: vi.fn() },
229
- dialog,
230
- Menu,
231
- shell,
232
- nativeImage,
233
- nativeTheme,
234
- globalShortcut,
235
- Tray,
236
- default: {},
237
- };
238
- });
239
- vi.mock('fs', async () => {
240
- const real = await vi.importActual('fs');
241
- function existsSync(p) {
242
- const s = String(p);
243
- if (s === stubs.projectsJsonPath)
244
- return stubs.getProjectsJson() !== null;
245
- if (s.endsWith('/app.json') || s.endsWith('\\app.json')) {
246
- const dir = s.replace(/[\\/]app\.json$/, '');
247
- return stubs.projectsWithAppJson.has(dir);
248
- }
249
- return true;
250
- }
251
- function readFileSync(p, opts) {
252
- const s = String(p);
253
- if (s === stubs.projectsJsonPath) {
254
- const content = stubs.getProjectsJson();
255
- if (content === null)
256
- throw Object.assign(new Error('ENOENT'), { code: 'ENOENT' });
257
- return content;
258
- }
259
- return real.readFileSync(p, opts);
260
- }
261
- function writeFileSync(p, data) {
262
- const s = String(p);
263
- if (s === stubs.projectsJsonPath) {
264
- stubs.setProjectsJson(typeof data === 'string' ? data : Buffer.from(data).toString('utf8'));
265
- }
266
- }
267
- const mocked = {
268
- ...real,
269
- existsSync,
270
- readFileSync,
271
- writeFileSync,
272
- mkdirSync: vi.fn(),
273
- statSync: vi.fn(() => ({ isDirectory: () => true, isFile: () => false, size: 0, mtimeMs: 0 })),
274
- watch: vi.fn(),
275
- realpathSync: vi.fn((p) => p),
276
- };
277
- return { ...mocked, default: mocked };
278
- });
279
- const devkitStubs = vi.hoisted(() => ({
280
- sessionClose: vi.fn(() => Promise.resolve()),
281
- }));
282
- vi.mock('@dimina-kit/devkit', () => ({
283
- openProject: vi.fn(() => Promise.resolve({
284
- port: 12345,
285
- appInfo: { appId: 'fakeApp' },
286
- close: devkitStubs.sessionClose,
287
- })),
288
- }));
18
+ import { stubs, devkitStubs } from './devtools-runtime-mock.harness.js';
289
19
  // ── view-manager spy shim ───────────────────────────────────────────────
290
20
  // `createDevtoolsBackend` keeps its assembled `instance` in a private
291
21
  // closure — the returned `RuntimeBackend` exposes no getter for
@@ -309,7 +39,8 @@ vi.mock('../services/views/view-manager.js', async (importOriginal) => {
309
39
  },
310
40
  };
311
41
  });
312
- export { stubs, devkitStubs, viewManagerStubs };
42
+ export { stubs, devkitStubs } from './devtools-runtime-mock.harness.js';
43
+ export { viewManagerStubs };
313
44
  export function registerBackendTestLifecycle() {
314
45
  const state = {};
315
46
  beforeEach(async () => {
@@ -1,5 +1,6 @@
1
1
  import { runDevtoolsBootstrap, createDevtoolsRuntime } from '../app/app.js';
2
2
  import { isAppQuitting, registerAppLifecycle } from '../app/lifecycle.js';
3
+ import { closeAllCoiHosts } from '../services/workbench-coi-host.js';
3
4
  /**
4
5
  * Adapts the devtools runtime into a {@link RuntimeBackend} the framework
5
6
  * (`@dimina-kit/electron-deck`) orchestrates. The framework owns the process
@@ -61,7 +62,7 @@ export function createDevtoolsBackend(config = {}) {
61
62
  // handler closing an already-torn-down MessagePort segfaults natively.
62
63
  // Safe to run again from `onShutdown`'s `instance.dispose()` afterwards
63
64
  // — `views.disposeAll()` and its constituents are dispose-idempotent.
64
- registerAppLifecycle(() => instance?.context.views.disposeAll());
65
+ registerAppLifecycle(() => instance?.disposeViews());
65
66
  // `onInstanceCreated` (not the return value) is what assigns `instance`:
66
67
  // `createDevtoolsRuntime` awaits the host's `config.onSetup(instance)`
67
68
  // — which may run arbitrarily long and can itself load the host toolbar
@@ -74,7 +75,7 @@ export function createDevtoolsBackend(config = {}) {
74
75
  // this instance existed, so the hook above ran with nothing to
75
76
  // dispose. Self-heal: run the same teardown now that there is.
76
77
  if (isAppQuitting())
77
- instance.context.views.disposeAll();
78
+ instance.disposeViews();
78
79
  }).then(() => { });
79
80
  await assembling;
80
81
  },
@@ -94,7 +95,17 @@ export function createDevtoolsBackend(config = {}) {
94
95
  // not a reason to skip disposing whatever DID get constructed.
95
96
  onShutdown: async () => {
96
97
  await assembling?.catch(() => { });
97
- await instance?.dispose();
98
+ // The workbench COI listener is deliberately kept alive across project
99
+ // windows (its port IS the workbench origin, see workbench-coi-host.ts),
100
+ // so no window teardown ever closes it. Process shutdown is the one place
101
+ // that must — after the windows above have released their routes, and
102
+ // even if one of their disposers threw on the way.
103
+ try {
104
+ await instance?.dispose();
105
+ }
106
+ finally {
107
+ await closeAllCoiHosts();
108
+ }
98
109
  },
99
110
  };
100
111
  }
@@ -0,0 +1,21 @@
1
+ declare const stubs: {
2
+ handlers: Map<string, (...args: unknown[]) => unknown>;
3
+ projectsJsonPath: string;
4
+ getProjectsJson(): string | null;
5
+ setProjectsJson(v: string | null): void;
6
+ projectsWithAppJson: Set<string>;
7
+ makeEmitter: () => {
8
+ listeners: Record<string, Set<(...args: unknown[]) => unknown>>;
9
+ on(event: string, fn: (...args: unknown[]) => unknown): /*elided*/ any;
10
+ once(event: string, fn: (...args: unknown[]) => unknown): /*elided*/ any;
11
+ off(event: string, fn: (...args: unknown[]) => unknown): /*elided*/ any;
12
+ removeListener(event: string, fn: (...args: unknown[]) => unknown): /*elided*/ any;
13
+ emit(event: string, ...args: unknown[]): void;
14
+ };
15
+ reset: () => void;
16
+ };
17
+ declare const devkitStubs: {
18
+ sessionClose: import("vitest").Mock<() => Promise<void>>;
19
+ };
20
+ export { stubs, devkitStubs };
21
+ //# sourceMappingURL=devtools-runtime-mock.harness.d.ts.map