@dimina-kit/devtools 0.4.0-dev.20260803105710 → 0.4.0-dev.20260828092243

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 (208) hide show
  1. package/dist/main/api.d.ts +1 -1
  2. package/dist/main/app/app.js +66 -2
  3. package/dist/main/index.bundle.js +1454 -540
  4. package/dist/main/ipc/index.d.ts +3 -0
  5. package/dist/main/ipc/index.js +3 -0
  6. package/dist/main/ipc/popover.js +1 -1
  7. package/dist/main/ipc/project-create.d.ts +15 -0
  8. package/dist/main/ipc/project-create.js +26 -0
  9. package/dist/main/ipc/projects.d.ts +1 -1
  10. package/dist/main/ipc/projects.js +11 -0
  11. package/dist/main/ipc/session.js +11 -0
  12. package/dist/main/ipc/settings.js +2 -1
  13. package/dist/main/ipc/simulator-module.d.ts +4 -3
  14. package/dist/main/ipc/simulator-module.js +4 -5
  15. package/dist/main/ipc/tooltip.d.ts +13 -0
  16. package/dist/main/ipc/tooltip.js +28 -0
  17. package/dist/main/ipc/views.d.ts +15 -1
  18. package/dist/main/ipc/views.js +61 -4
  19. package/dist/main/runtime/miniapp-runtime.d.ts +87 -19
  20. package/dist/main/services/layout/index.d.ts +11 -0
  21. package/dist/main/services/layout/index.js +23 -0
  22. package/dist/main/services/network-forward/frontend-dispatch.js +2 -1
  23. package/dist/main/services/notifications/renderer-notifier.d.ts +32 -1
  24. package/dist/main/services/notifications/renderer-notifier.js +29 -1
  25. package/dist/main/services/projects/project-repository.d.ts +4 -1
  26. package/dist/main/services/projects/project-repository.js +63 -5
  27. package/dist/main/services/simulator-current-page/index.d.ts +5 -3
  28. package/dist/main/services/simulator-current-page/index.js +8 -1
  29. package/dist/main/services/update/update-manager.d.ts +17 -3
  30. package/dist/main/services/update/update-manager.js +25 -6
  31. package/dist/main/services/views/clear-console-filter.d.ts +44 -0
  32. package/dist/main/services/views/clear-console-filter.js +86 -0
  33. package/dist/main/services/views/console-filter-test-fixtures.d.ts +94 -0
  34. package/dist/main/services/views/console-filter-test-fixtures.js +82 -0
  35. package/dist/main/services/views/console-filter.d.ts +79 -130
  36. package/dist/main/services/views/console-filter.js +140 -183
  37. package/dist/main/services/views/devtools-tabs.d.ts +24 -4
  38. package/dist/main/services/views/devtools-tabs.js +40 -21
  39. package/dist/main/services/views/host-dialog-port-channel.d.ts +18 -0
  40. package/dist/main/services/views/host-dialog-port-channel.js +15 -0
  41. package/dist/main/services/views/host-dialog-session-runtime.d.ts +10 -0
  42. package/dist/main/services/views/host-dialog-session-runtime.js +17 -0
  43. package/dist/main/services/views/host-dialog-view.d.ts +95 -0
  44. package/dist/main/services/views/host-dialog-view.js +147 -0
  45. package/dist/main/services/views/host-sidebar-port-channel.d.ts +18 -0
  46. package/dist/main/services/views/host-sidebar-port-channel.js +15 -0
  47. package/dist/main/services/views/host-sidebar-session-runtime.d.ts +10 -0
  48. package/dist/main/services/views/host-sidebar-session-runtime.js +17 -0
  49. package/dist/main/services/views/host-sidebar-view.d.ts +59 -0
  50. package/dist/main/services/views/host-sidebar-view.js +44 -0
  51. package/dist/main/services/views/host-slot-port-channel.d.ts +107 -0
  52. package/dist/main/services/views/host-slot-port-channel.js +261 -0
  53. package/dist/main/services/views/host-slot-session-runtime.d.ts +40 -0
  54. package/dist/main/services/views/host-slot-session-runtime.js +50 -0
  55. package/dist/main/services/views/host-slot-view.d.ts +109 -0
  56. package/dist/main/services/views/host-slot-view.js +147 -0
  57. package/dist/main/services/views/host-toolbar-port-channel.d.ts +6 -91
  58. package/dist/main/services/views/host-toolbar-port-channel.js +10 -243
  59. package/dist/main/services/views/host-toolbar-session-runtime.d.ts +5 -30
  60. package/dist/main/services/views/host-toolbar-session-runtime.js +9 -47
  61. package/dist/main/services/views/host-toolbar-view.d.ts +34 -7
  62. package/dist/main/services/views/host-toolbar-view.js +30 -237
  63. package/dist/main/services/views/managed-web-contents-view.d.ts +48 -0
  64. package/dist/main/services/views/managed-web-contents-view.js +123 -0
  65. package/dist/main/services/views/native-simulator-devtools-host.js +64 -45
  66. package/dist/main/services/views/native-simulator-view.js +6 -24
  67. package/dist/main/services/views/native-view-tree.d.ts +25 -0
  68. package/dist/main/services/views/native-view-tree.js +69 -0
  69. package/dist/main/services/views/overlay-panels-view.d.ts +50 -4
  70. package/dist/main/services/views/overlay-panels-view.js +226 -108
  71. package/dist/main/services/views/placement-reconciler.d.ts +18 -18
  72. package/dist/main/services/views/placement-reconciler.js +91 -29
  73. package/dist/main/services/views/placement-test-driver.d.ts +27 -0
  74. package/dist/main/services/views/placement-test-driver.js +29 -0
  75. package/dist/main/services/views/view-manager-devtools-host-test-fixtures.js +3 -1
  76. package/dist/main/services/views/view-manager.d.ts +14 -86
  77. package/dist/main/services/views/view-manager.js +41 -4
  78. package/dist/main/services/views/workbench-view.js +27 -20
  79. package/dist/main/services/workbench-coi-server.d.ts +11 -0
  80. package/dist/main/services/workbench-coi-server.js +32 -0
  81. package/dist/main/services/workspace/rebuild-status.d.ts +21 -8
  82. package/dist/main/services/workspace/rebuild-status.js +24 -8
  83. package/dist/main/utils/paths.d.ts +4 -0
  84. package/dist/main/utils/paths.js +4 -0
  85. package/dist/main/utils/sender-policy.d.ts +1 -1
  86. package/dist/main/utils/sender-policy.js +16 -1
  87. package/dist/main/utils/theme.d.ts +7 -2
  88. package/dist/main/utils/theme.js +8 -3
  89. package/dist/native-host/common/common.js +65 -62
  90. package/dist/native-host/container/pageFrame.css +1 -1
  91. package/dist/native-host/render/render.js +3226 -2898
  92. package/dist/native-host/service/service.js +2 -2
  93. package/dist/preload/runtime/host-dialog-advertiser.d.ts +22 -0
  94. package/dist/preload/runtime/host-dialog-advertiser.js +37 -0
  95. package/dist/preload/runtime/host-dialog-port.d.ts +44 -0
  96. package/dist/preload/runtime/host-dialog-port.js +53 -0
  97. package/dist/preload/runtime/host-dialog-runtime.d.ts +28 -0
  98. package/dist/preload/runtime/host-dialog-runtime.js +36 -0
  99. package/dist/preload/runtime/host-sidebar-advertiser.d.ts +19 -0
  100. package/dist/preload/runtime/host-sidebar-advertiser.js +35 -0
  101. package/dist/preload/runtime/host-sidebar-port.d.ts +44 -0
  102. package/dist/preload/runtime/host-sidebar-port.js +53 -0
  103. package/dist/preload/runtime/host-sidebar-runtime.d.ts +28 -0
  104. package/dist/preload/runtime/host-sidebar-runtime.js +36 -0
  105. package/dist/preload/runtime/host-slot-port-bridge.d.ts +18 -0
  106. package/dist/preload/runtime/host-slot-port-bridge.js +112 -0
  107. package/dist/preload/runtime/host-toolbar-advertiser.d.ts +5 -13
  108. package/dist/preload/runtime/host-toolbar-advertiser.js +18 -38
  109. package/dist/preload/runtime/host-toolbar-port.d.ts +9 -0
  110. package/dist/preload/runtime/host-toolbar-port.js +11 -95
  111. package/dist/preload/runtime/wait-for-slot-root.d.ts +20 -0
  112. package/dist/preload/runtime/wait-for-slot-root.js +52 -0
  113. package/dist/preload/windows/host-dialog-runtime.cjs +353 -0
  114. package/dist/preload/windows/host-dialog-runtime.cjs.map +7 -0
  115. package/dist/preload/windows/host-dialog-runtime.d.ts +2 -0
  116. package/dist/preload/windows/host-dialog-runtime.js +13 -0
  117. package/dist/preload/windows/host-sidebar-runtime.cjs +354 -0
  118. package/dist/preload/windows/host-sidebar-runtime.cjs.map +7 -0
  119. package/dist/preload/windows/host-sidebar-runtime.d.ts +2 -0
  120. package/dist/preload/windows/host-sidebar-runtime.js +13 -0
  121. package/dist/preload/windows/host-toolbar-runtime.cjs +134 -51
  122. package/dist/preload/windows/host-toolbar-runtime.cjs.map +3 -3
  123. package/dist/preload/windows/main.cjs +3176 -14
  124. package/dist/preload/windows/main.cjs.map +4 -4
  125. package/dist/preload/windows/main.css +428 -0
  126. package/dist/preload/windows/main.css.map +7 -0
  127. package/dist/preload/windows/simulator.cjs +5 -2
  128. package/dist/preload/windows/simulator.cjs.map +2 -2
  129. package/dist/preload/windows/simulator.js +5 -2
  130. package/dist/renderer/assets/button-DsNqZm7o.js +2 -0
  131. package/dist/renderer/assets/constants-D7DfVqMp.js +2 -0
  132. package/dist/renderer/assets/constants-D8zsejFq.js +2 -0
  133. package/dist/renderer/assets/createLucideIcon-CYJeT1ji.js +2 -0
  134. package/dist/renderer/assets/dialog-pT4qWmka.js +46 -0
  135. package/dist/renderer/assets/dist-o70xmpc1.js +2 -0
  136. package/dist/renderer/assets/hostSidebarDefault-NvGZlE9O.js +2 -0
  137. package/dist/renderer/assets/index-zErhG3ta.js +5 -0
  138. package/dist/renderer/assets/input-4QxTXMZN.js +2 -0
  139. package/dist/renderer/assets/ipc-channels-overlays-Blr5TNoB.js +2 -0
  140. package/dist/renderer/assets/jsx-runtime-B-3rq1y5.css +1 -0
  141. package/dist/renderer/assets/jsx-runtime-CqVdW3eg.js +9 -0
  142. package/dist/renderer/assets/popover-CJiSWwuE.js +2 -0
  143. package/dist/renderer/assets/project-api-DZ1Zi6EC.js +2 -0
  144. package/dist/renderer/assets/projectCreateDialog-DMWNhw_1.js +2 -0
  145. package/dist/renderer/assets/select-C86pNcsu.js +2 -0
  146. package/dist/renderer/assets/settings-BoI8mLT1.js +2 -0
  147. package/dist/renderer/assets/settings-api-Bs_g4NHs.js +2 -0
  148. package/dist/renderer/assets/settings-tab-bar-DHLLygqv.js +2 -0
  149. package/dist/renderer/assets/tooltip-BhAyY0T4.js +2 -0
  150. package/dist/renderer/assets/types-YYjkvane.js +2 -0
  151. package/dist/renderer/assets/updateDialog-DPum3wx1.js +2 -0
  152. package/dist/renderer/assets/utils-kfQov6Pa.js +2 -0
  153. package/dist/renderer/assets/view-api-DFhb2R8-.js +2 -0
  154. package/dist/renderer/assets/workbenchSettings-DrajRQUk.js +8 -0
  155. package/dist/renderer/entries/host-sidebar-default/index.html +21 -0
  156. package/dist/renderer/entries/main/index.html +15 -7
  157. package/dist/renderer/entries/popover/index.html +10 -6
  158. package/dist/renderer/entries/project-create-dialog/index.html +27 -0
  159. package/dist/renderer/entries/settings/index.html +10 -5
  160. package/dist/renderer/entries/tooltip/index.html +21 -0
  161. package/dist/renderer/entries/update-dialog/index.html +25 -0
  162. package/dist/renderer/entries/workbench-settings/index.html +11 -5
  163. package/dist/service-host/preload.cjs +10 -0
  164. package/dist/service-host/sync-impls/menu-button-geometry.js +1 -0
  165. package/dist/shared/constants.d.ts +22 -0
  166. package/dist/shared/constants.js +22 -0
  167. package/dist/shared/ipc-channels-overlays.d.ts +156 -0
  168. package/dist/shared/ipc-channels-overlays.js +186 -0
  169. package/dist/shared/ipc-channels.d.ts +1 -67
  170. package/dist/shared/ipc-channels.js +9 -81
  171. package/dist/shared/ipc-schemas.d.ts +52 -0
  172. package/dist/shared/ipc-schemas.js +64 -0
  173. package/dist/shared/simulator-route.d.ts +8 -0
  174. package/dist/shared/simulator-route.js +15 -0
  175. package/dist/shared/types.d.ts +17 -0
  176. package/dist/shared/view-ids.d.ts +9 -0
  177. package/dist/shared/view-ids.js +21 -0
  178. package/dist/simulator/assets/device-shell-CmtM1QxP.js +2 -0
  179. package/dist/simulator/assets/device-shell-iFZo1igL.css +1 -0
  180. package/dist/simulator/assets/{simulator-COIE6R49.js → simulator-CIobn3Mh.js} +6 -6
  181. package/dist/simulator/assets/{simulator-mini-app-BLn7XV8e.js → simulator-mini-app-CRe6n9br.js} +2 -2
  182. package/dist/simulator/assets/simulator-ui-BupATgKo.css +1 -0
  183. package/dist/simulator/assets/simulator-ui-C_cP602X.js +2 -0
  184. package/dist/simulator/simulator.html +3 -2
  185. package/dist/vscode-workbench/assets/__vite-browser-external-Bc1vizTf.js +1 -0
  186. package/dist/vscode-workbench/assets/{dist-oHcwN53f.js → dist-CMfmHflW.js} +3 -3
  187. package/dist/vscode-workbench/assets/{iconv-lite-umd-CLMLpdGm.js → iconv-lite-umd-Bx8CgaZq.js} +1 -1
  188. package/dist/vscode-workbench/assets/{index-BE3UJdoH.js → index-CdG6YWhW.js} +436 -436
  189. package/dist/vscode-workbench/assets/{jschardet-BICW8PLJ.js → jschardet-M0qgd2lN.js} +1 -1
  190. package/dist/vscode-workbench/index.html +21 -1
  191. package/package.json +9 -8
  192. package/dist/main/services/views/destroy-child-view.d.ts +0 -9
  193. package/dist/main/services/views/destroy-child-view.js +0 -23
  194. package/dist/renderer/assets/constants-EAMiwL9_.js +0 -2
  195. package/dist/renderer/assets/index-BBg3YI5b.js +0 -49
  196. package/dist/renderer/assets/input-xdmfv-eH.js +0 -2
  197. package/dist/renderer/assets/ipc-transport-B3EpmfNS.js +0 -9
  198. package/dist/renderer/assets/ipc-transport-Blac3sOj.css +0 -1
  199. package/dist/renderer/assets/popover-B88e2hkg.js +0 -2
  200. package/dist/renderer/assets/select-CD9CJyhI.js +0 -2
  201. package/dist/renderer/assets/settings-44hf0QtO.js +0 -2
  202. package/dist/renderer/assets/settings-api-pJKPuP1M.js +0 -2
  203. package/dist/renderer/assets/workbenchSettings-DKD5U1Ql.js +0 -8
  204. package/dist/simulator/assets/device-shell-Cw7c-IkG.js +0 -2
  205. package/dist/simulator/assets/device-shell-DbC5ccs8.css +0 -1
  206. package/dist/simulator/assets/jsx-runtime-DkKmJyBb.js +0 -2
  207. package/dist/simulator/device-shell/menu-button-geometry.js +0 -18
  208. package/dist/vscode-workbench/assets/__vite-browser-external-BON7qP59.js +0 -1
@@ -1,4 +1,5 @@
1
- import { ProjectChannel, SessionChannel, WindowChannel, SettingsChannel, PopoverChannel, WorkbenchSettingsChannel, EditorChannel, ViewChannel, } from '../../../shared/ipc-channels.js';
1
+ import { ProjectChannel, SessionChannel, WindowChannel, WorkbenchSettingsChannel, EditorChannel, } from '../../../shared/ipc-channels.js';
2
+ import { SettingsChannel, PopoverChannel, TooltipChannel, ProjectCreateChannel, UpdateChannel, ViewChannel, } from '../../../shared/ipc-channels-overlays.js';
2
3
  /** Safely resolve a WebContents, skipping destroyed / missing targets. */
3
4
  function liveWebContents(wc) {
4
5
  if (!wc)
@@ -45,15 +46,42 @@ export function createRendererNotifier(ctx) {
45
46
  hostToolbarHeightChanged(height) {
46
47
  sendToMain(ViewChannel.HostToolbarHeightChanged, height);
47
48
  },
49
+ hostSidebarWidthChanged(width) {
50
+ sendToMain(ViewChannel.HostSidebarWidthChanged, width);
51
+ },
52
+ hostSidebarCategorySelected(category) {
53
+ sendToMain(ViewChannel.HostSidebarCategorySelected, category);
54
+ },
48
55
  editorOpenFile(payload) {
49
56
  sendToMain(EditorChannel.OpenFile, payload);
50
57
  },
58
+ projectCreateSubmitted(payload) {
59
+ sendToMain(ProjectCreateChannel.Submitted, payload);
60
+ },
51
61
  popoverInit(popoverView, payload) {
52
62
  const wc = liveWebContents(popoverView.webContents);
53
63
  if (!wc)
54
64
  return;
55
65
  wc.send(PopoverChannel.Init, payload);
56
66
  },
67
+ tooltipInit(tooltipView, payload) {
68
+ const wc = liveWebContents(tooltipView.webContents);
69
+ if (!wc)
70
+ return;
71
+ wc.send(TooltipChannel.Init, payload);
72
+ },
73
+ projectCreateInit(dialogView, payload) {
74
+ const wc = liveWebContents(dialogView.webContents);
75
+ if (!wc)
76
+ return;
77
+ wc.send(ProjectCreateChannel.Init, payload);
78
+ },
79
+ updateAvailable(dialogView, payload) {
80
+ const wc = liveWebContents(dialogView.webContents);
81
+ if (!wc)
82
+ return;
83
+ wc.send(UpdateChannel.Available, payload);
84
+ },
57
85
  settingsInit(payload) {
58
86
  const wc = liveWebContents(ctx.views.getSettingsWebContents());
59
87
  if (!wc)
@@ -1,9 +1,12 @@
1
- import type { CompileConfig } from '../../../shared/types.js';
1
+ import type { CompileConfig, ProjectType } from '../../../shared/types.js';
2
+ export type { ProjectType };
2
3
  export interface Project {
3
4
  name: string;
4
5
  path: string;
5
6
  lastOpened?: string | null;
6
7
  compileConfig?: CompileConfig;
8
+ /** Absent on projects added before mini-game support — treat as 'miniprogram'. */
9
+ type?: ProjectType;
7
10
  }
8
11
  export interface ProjectPages {
9
12
  pages: string[];
@@ -4,6 +4,44 @@ import fs from 'fs';
4
4
  import { DEFAULT_SCENE } from '../../../shared/constants.js';
5
5
  import { createLogger } from '../../utils/logger.js';
6
6
  const log = createLogger('projects');
7
+ /**
8
+ * Merge project.config.json + project.private.config.json (private wins),
9
+ * mirroring `dimina/fe/packages/compiler/src/env.js`'s `storeInfo`.
10
+ */
11
+ function readProjectConfig(dirPath) {
12
+ let merged = {};
13
+ for (const fileName of ['project.config.json', 'project.private.config.json']) {
14
+ const configPath = path.join(dirPath, fileName);
15
+ if (!fs.existsSync(configPath))
16
+ continue;
17
+ try {
18
+ merged = { ...merged, ...JSON.parse(fs.readFileSync(configPath, 'utf-8')) };
19
+ }
20
+ catch (err) {
21
+ log.warn(`Failed to parse ${configPath}`, err);
22
+ }
23
+ }
24
+ return merged;
25
+ }
26
+ /**
27
+ * Mirrors `dimina/fe/packages/compiler/src/env.js`'s `detectRuntimeType` —
28
+ * an explicit `compileType` wins, else a mini-game is inferred from
29
+ * game.json + game.js/.ts with no app.json present.
30
+ */
31
+ function detectRuntimeType(dirPath) {
32
+ const compileType = readProjectConfig(dirPath).compileType;
33
+ if (compileType === 'game')
34
+ return 'minigame';
35
+ if (compileType === 'miniprogram')
36
+ return 'miniprogram';
37
+ const hasMiniProgramConfig = fs.existsSync(path.join(dirPath, 'app.json'));
38
+ const hasMiniGameConfig = fs.existsSync(path.join(dirPath, 'game.json'));
39
+ const hasMiniGameEntry = ['game.js', 'game.ts']
40
+ .some((fileName) => fs.existsSync(path.join(dirPath, fileName)));
41
+ if (!hasMiniProgramConfig && hasMiniGameConfig && hasMiniGameEntry)
42
+ return 'minigame';
43
+ return 'miniprogram';
44
+ }
7
45
  function getProjectsFile() {
8
46
  return path.join(app.getPath('userData'), 'dimina-projects.json');
9
47
  }
@@ -28,6 +66,12 @@ export function validateProjectDir(dirPath) {
28
66
  if (!fs.existsSync(dirPath)) {
29
67
  return `小程序目录不存在:${dirPath}`;
30
68
  }
69
+ if (detectRuntimeType(dirPath) === 'minigame') {
70
+ if (!fs.existsSync(path.join(dirPath, 'game.json'))) {
71
+ return '该目录缺少 game.json,请选择包含小游戏源码的目录';
72
+ }
73
+ return null;
74
+ }
31
75
  if (!fs.existsSync(path.join(dirPath, 'app.json'))) {
32
76
  const configPath = path.join(dirPath, 'project.config.json');
33
77
  if (fs.existsSync(configPath)) {
@@ -63,10 +107,11 @@ export function addProject(dirPath) {
63
107
  catch (err) {
64
108
  log.warn('Failed to read project name from config', err);
65
109
  }
66
- const project = { name, path: dirPath, lastOpened: null };
110
+ const type = detectRuntimeType(dirPath);
111
+ const project = { name, path: dirPath, lastOpened: null, type };
67
112
  const idx = projects.findIndex((p) => p.path === dirPath);
68
113
  if (idx >= 0) {
69
- projects[idx] = { ...projects[idx], name };
114
+ projects[idx] = { ...projects[idx], name, type };
70
115
  }
71
116
  else {
72
117
  projects.unshift(project);
@@ -88,13 +133,26 @@ export function updateLastOpened(dirPath) {
88
133
  export function getCompileConfig(dirPath) {
89
134
  const projects = load();
90
135
  const project = projects.find((p) => p.path === dirPath);
91
- return (project?.compileConfig ?? {
92
- startPage: '',
136
+ if (project?.compileConfig)
137
+ return project.compileConfig;
138
+ // Default startPage to the project's real entry page (mirrors
139
+ // getProjectPages: 'game' for mini-games, app.json's entryPagePath for
140
+ // mini-programs) rather than a mini-program-only literal — the simulator
141
+ // URL builders' own 'pages/index/index' fallback only fires when this is
142
+ // still empty (unreadable/malformed manifest).
143
+ return {
144
+ startPage: getProjectPages(dirPath).entryPagePath,
93
145
  scene: DEFAULT_SCENE,
94
146
  queryParams: [],
95
- });
147
+ };
96
148
  }
97
149
  export function getProjectPages(dirPath) {
150
+ if (detectRuntimeType(dirPath) === 'minigame') {
151
+ // Mini-games have no page router — the compiler always emits a single
152
+ // synthetic 'game' entry (dimina/fe/packages/compiler/src/env.js
153
+ // storeAppConfig), mirrored here rather than reading a nonexistent app.json.
154
+ return { pages: ['game'], entryPagePath: 'game' };
155
+ }
98
156
  const appJsonPath = path.join(dirPath, 'app.json');
99
157
  try {
100
158
  const appJson = JSON.parse(fs.readFileSync(appJsonPath, 'utf-8'));
@@ -6,9 +6,11 @@
6
6
  * page a nested render-host `<webview>`), not a renderer `<webview>` the main
7
7
  * window can observe — so in-app navigation (navigateTo / switchTab / back)
8
8
  * never reaches the renderer's `<webview>` did-navigate events. This service
9
- * taps the bridge's active-page signal and pushes the new route to the
10
- * main-window renderer (`SimulatorChannel.CurrentPage`), keeping the toolbar in
11
- * sync without polling.
9
+ * taps the bridge's active-page signal and pushes the route page path plus
10
+ * its launch query, so the simulator's page-path bar shows params just like
11
+ * WeChat DevTools and a recompile can restore them — to the main-window
12
+ * renderer (`SimulatorChannel.CurrentPage`), keeping the toolbar in sync
13
+ * without polling.
12
14
  *
13
15
  * Inert on the default dimina-fe path (which derives the current page from the
14
16
  * simulator `<webview>`'s navigation events); app.ts gates the call on
@@ -1,4 +1,5 @@
1
1
  import { SimulatorChannel } from '../../../shared/ipc-channels.js';
2
+ import { encodePageSpec } from '../../../shared/simulator-route.js';
2
3
  import { DisposableRegistry } from '@dimina-kit/electron-deck/main';
3
4
  export function setupSimulatorCurrentPage(host, options) {
4
5
  const registry = new DisposableRegistry();
@@ -11,7 +12,13 @@ export function setupSimulatorCurrentPage(host, options) {
11
12
  return;
12
13
  if (host.isDestroyed())
13
14
  return;
14
- host.send(SimulatorChannel.CurrentPage, ev.pagePath);
15
+ // Bridge queries are `Record<string, unknown>` (they may hold numbers from
16
+ // the URL); the route format wants strings. encodePageSpec re-encodes with
17
+ // `?k=v&…` so the renderer can decode it back into { pagePath, query }.
18
+ const query = {};
19
+ for (const [k, v] of Object.entries(ev.query ?? {}))
20
+ query[k] = String(v);
21
+ host.send(SimulatorChannel.CurrentPage, encodePageSpec({ pagePath: ev.pagePath, query }));
15
22
  });
16
23
  registry.add(off);
17
24
  return registry;
@@ -1,9 +1,13 @@
1
- import { BrowserWindow } from 'electron';
2
1
  import type { UpdateChecker, UpdateInfo } from '../../../shared/types.js';
3
2
  import { type SenderPolicy } from '../../utils/ipc-registry.js';
4
3
  export interface UpdateManagerOptions {
5
4
  checker: UpdateChecker;
6
- mainWindow: BrowserWindow;
5
+ /** Show the update-available overlay panel, fed the discovered update's info. */
6
+ showUpdatePanel: (info: UpdateInfo) => void;
7
+ /** Forward a download-progress tick into the (already-shown) update overlay. */
8
+ notifyDownloadProgress: (percent: number) => void;
9
+ /** Hide the update overlay panel — the renderer's close (any path) forwards here. */
10
+ hideUpdatePanel: () => void;
7
11
  /** Check interval in milliseconds. Default: 1 hour */
8
12
  checkInterval?: number;
9
13
  /** Delay before the first check after startup in ms. Default: 5000 */
@@ -20,7 +24,9 @@ export interface UpdateManagerOptions {
20
24
  }
21
25
  export declare class UpdateManager {
22
26
  private checker;
23
- private mainWindow;
27
+ private showUpdatePanel;
28
+ private notifyDownloadProgress;
29
+ private hideUpdatePanel;
24
30
  private getCurrentVersion;
25
31
  private latestUpdate;
26
32
  private downloadedPath;
@@ -37,6 +43,14 @@ export declare class UpdateManager {
37
43
  private timer;
38
44
  private initialTimer;
39
45
  private ipc;
46
+ /**
47
+ * Set by `dispose()`. Clearing the timers only stops FUTURE ticks — an
48
+ * in-flight `checkAndNotify()` invocation (already past its `await
49
+ * this.check()`) has no timer left to cancel it, and would otherwise call
50
+ * `showUpdatePanel` after dispose has torn down the overlay panel that
51
+ * owns (e.g. `views.disposeAll()` destroying its WebContentsView).
52
+ */
53
+ private disposed;
40
54
  constructor(opts: UpdateManagerOptions);
41
55
  private registerIpc;
42
56
  check(): Promise<{
@@ -1,9 +1,11 @@
1
1
  import { app, shell } from 'electron';
2
- import { UpdateChannel } from '../../../shared/ipc-channels.js';
2
+ import { UpdateChannel } from '../../../shared/ipc-channels-overlays.js';
3
3
  import { IpcRegistry } from '../../utils/ipc-registry.js';
4
4
  export class UpdateManager {
5
5
  checker;
6
- mainWindow;
6
+ showUpdatePanel;
7
+ notifyDownloadProgress;
8
+ hideUpdatePanel;
7
9
  getCurrentVersion;
8
10
  latestUpdate = null;
9
11
  downloadedPath = null;
@@ -20,9 +22,19 @@ export class UpdateManager {
20
22
  timer = null;
21
23
  initialTimer = null;
22
24
  ipc;
25
+ /**
26
+ * Set by `dispose()`. Clearing the timers only stops FUTURE ticks — an
27
+ * in-flight `checkAndNotify()` invocation (already past its `await
28
+ * this.check()`) has no timer left to cancel it, and would otherwise call
29
+ * `showUpdatePanel` after dispose has torn down the overlay panel that
30
+ * owns (e.g. `views.disposeAll()` destroying its WebContentsView).
31
+ */
32
+ disposed = false;
23
33
  constructor(opts) {
24
34
  this.checker = opts.checker;
25
- this.mainWindow = opts.mainWindow;
35
+ this.showUpdatePanel = opts.showUpdatePanel;
36
+ this.notifyDownloadProgress = opts.notifyDownloadProgress;
37
+ this.hideUpdatePanel = opts.hideUpdatePanel;
26
38
  this.getCurrentVersion = opts.getCurrentVersion ?? (() => app.getVersion());
27
39
  this.ipc = new IpcRegistry(opts.senderPolicy);
28
40
  this.registerIpc();
@@ -32,7 +44,8 @@ export class UpdateManager {
32
44
  this.ipc
33
45
  .handle(UpdateChannel.Check, async () => this.check())
34
46
  .handle(UpdateChannel.Download, async () => this.download())
35
- .handle(UpdateChannel.Install, async () => this.install());
47
+ .handle(UpdateChannel.Install, async () => this.install())
48
+ .on(UpdateChannel.Close, () => this.hideUpdatePanel());
36
49
  }
37
50
  async check() {
38
51
  try {
@@ -69,7 +82,7 @@ export class UpdateManager {
69
82
  }
70
83
  try {
71
84
  const filePath = await this.checker.downloadUpdate(this.latestUpdate, (percent) => {
72
- this.mainWindow.webContents.send(UpdateChannel.DownloadProgress, { percent });
85
+ this.notifyDownloadProgress(percent);
73
86
  });
74
87
  this.downloadedPath = filePath;
75
88
  return { success: true, filePath };
@@ -104,6 +117,7 @@ export class UpdateManager {
104
117
  * the timer clears + handler removals are scheduled synchronously.
105
118
  */
106
119
  dispose() {
120
+ this.disposed = true;
107
121
  if (this.timer) {
108
122
  clearInterval(this.timer);
109
123
  this.timer = null;
@@ -120,12 +134,17 @@ export class UpdateManager {
120
134
  }
121
135
  async checkAndNotify() {
122
136
  const result = await this.check();
137
+ // dispose() only cancels the timers that SCHEDULE future ticks — a tick
138
+ // already in flight (past this await) has nothing left to cancel it, and
139
+ // must not call into a torn-down panel/registry after the fact.
140
+ if (this.disposed)
141
+ return;
123
142
  if (!result.hasUpdate || !result.info)
124
143
  return;
125
144
  if (this.hasNotified)
126
145
  return;
127
146
  this.hasNotified = true;
128
- this.mainWindow.webContents.send(UpdateChannel.Available, result.info);
147
+ this.showUpdatePanel(result.info);
129
148
  }
130
149
  }
131
150
  //# sourceMappingURL=update-manager.js.map
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Clears the right-panel Console panel's text-filter box on a FRESH project
3
+ * open, together with the stale persisted keys behind it.
4
+ *
5
+ * ── Why this exists ──────────────────────────────────────────────────────
6
+ * The Console filter text is a DevTools-owned setting that DevTools itself
7
+ * persists: it lives on the `devtools://` origin's localStorage, backed by the
8
+ * default session's on-disk storage (verified on disk:
9
+ * `~/Library/Application Support/Dimina DevTools/Local Storage/leveldb` holds a
10
+ * `console.textFilter` entry). An earlier implementation of the internal-log
11
+ * hiding wrote `-/^\[service\]/`-style negative filters straight into the box
12
+ * (see console-filter.ts's header for that history); that value still sits in
13
+ * localStorage and is restored on every project reopen / app restart. We do NOT
14
+ * fight DevTools' persistence mechanism here — instead, on each fresh project
15
+ * open we remove the stale keys and reset the visible box, so a project starts
16
+ * with the developer's own filter surface genuinely empty.
17
+ *
18
+ * ── When it runs ─────────────────────────────────────────────────────────
19
+ * Only the PROJECT-OPEN path arms this (see native-simulator-devtools-host.ts:
20
+ * `attach()` sets the flag; the injection consumes it once). Service-host pool
21
+ * swaps (hot-reload respawn) rebuild the front-end host too, but deliberately do
22
+ * NOT clear — the developer may legitimately have typed a filter during the
23
+ * session and a respawn must not drop in-flight work.
24
+ *
25
+ * ── Discipline (mirrors console-filter.ts) ────────────────────────────────
26
+ * In-realm bootstrap probe before touching `Console.ConsoleView.instance()` (an
27
+ * early construction transitively creates IssuesManager and permanently kills
28
+ * the front-end's own bootstrap — see frontend-bootstrap-gate.ts); bounded
29
+ * retry; silent degradation on any failure. The main process additionally holds
30
+ * this whole injection behind `whenFrontendBootstrapped`.
31
+ */
32
+ /**
33
+ * Build the `executeJavaScript` source that clears the Console filter box.
34
+ *
35
+ * Two levers, belt-and-suspenders:
36
+ * 1. remove the stale persisted keys (`console.textFilter` — the on-disk
37
+ * leftover we actually observed, and its kebab-case sibling) so a Console
38
+ * view constructed after this script reads an empty setting;
39
+ * 2. reset the already-constructed panel's visible box via
40
+ * `filter.textFilterUI.setValue('')`, which persists the empty value back
41
+ * through the panel's own setting path.
42
+ */
43
+ export declare function buildClearConsoleFilterScript(): string;
44
+ //# sourceMappingURL=clear-console-filter.d.ts.map
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Clears the right-panel Console panel's text-filter box on a FRESH project
3
+ * open, together with the stale persisted keys behind it.
4
+ *
5
+ * ── Why this exists ──────────────────────────────────────────────────────
6
+ * The Console filter text is a DevTools-owned setting that DevTools itself
7
+ * persists: it lives on the `devtools://` origin's localStorage, backed by the
8
+ * default session's on-disk storage (verified on disk:
9
+ * `~/Library/Application Support/Dimina DevTools/Local Storage/leveldb` holds a
10
+ * `console.textFilter` entry). An earlier implementation of the internal-log
11
+ * hiding wrote `-/^\[service\]/`-style negative filters straight into the box
12
+ * (see console-filter.ts's header for that history); that value still sits in
13
+ * localStorage and is restored on every project reopen / app restart. We do NOT
14
+ * fight DevTools' persistence mechanism here — instead, on each fresh project
15
+ * open we remove the stale keys and reset the visible box, so a project starts
16
+ * with the developer's own filter surface genuinely empty.
17
+ *
18
+ * ── When it runs ─────────────────────────────────────────────────────────
19
+ * Only the PROJECT-OPEN path arms this (see native-simulator-devtools-host.ts:
20
+ * `attach()` sets the flag; the injection consumes it once). Service-host pool
21
+ * swaps (hot-reload respawn) rebuild the front-end host too, but deliberately do
22
+ * NOT clear — the developer may legitimately have typed a filter during the
23
+ * session and a respawn must not drop in-flight work.
24
+ *
25
+ * ── Discipline (mirrors console-filter.ts) ────────────────────────────────
26
+ * In-realm bootstrap probe before touching `Console.ConsoleView.instance()` (an
27
+ * early construction transitively creates IssuesManager and permanently kills
28
+ * the front-end's own bootstrap — see frontend-bootstrap-gate.ts); bounded
29
+ * retry; silent degradation on any failure. The main process additionally holds
30
+ * this whole injection behind `whenFrontendBootstrapped`.
31
+ */
32
+ /**
33
+ * Build the `executeJavaScript` source that clears the Console filter box.
34
+ *
35
+ * Two levers, belt-and-suspenders:
36
+ * 1. remove the stale persisted keys (`console.textFilter` — the on-disk
37
+ * leftover we actually observed, and its kebab-case sibling) so a Console
38
+ * view constructed after this script reads an empty setting;
39
+ * 2. reset the already-constructed panel's visible box via
40
+ * `filter.textFilterUI.setValue('')`, which persists the empty value back
41
+ * through the panel's own setting path.
42
+ */
43
+ export function buildClearConsoleFilterScript() {
44
+ return `(function(){
45
+ var attempts = 0;
46
+ var MAX = 100;
47
+ function bootstrapReady() {
48
+ try {
49
+ var eui = globalThis.EUI;
50
+ if (!eui || !eui.ShortcutRegistry || !eui.ShortcutRegistry.ShortcutRegistry) return false;
51
+ eui.ShortcutRegistry.ShortcutRegistry.instance();
52
+ return true;
53
+ } catch (_) { return false; }
54
+ }
55
+ function tryClear() {
56
+ attempts++;
57
+ var scheduleRetry = attempts < MAX;
58
+ if (!bootstrapReady()) {
59
+ if (scheduleRetry) { setTimeout(tryClear, 100); return; }
60
+ return;
61
+ }
62
+ try {
63
+ try { localStorage.removeItem('console.textFilter'); } catch(_) {}
64
+ try { localStorage.removeItem('console.text-filter'); } catch(_) {}
65
+ var ConsoleNS = globalThis.Console;
66
+ var view = ConsoleNS && ConsoleNS.ConsoleView ? ConsoleNS.ConsoleView.instance() : null;
67
+ var f = view ? view.filter : null;
68
+ var box = f && f.textFilterUI;
69
+ if (!box || typeof box.setValue !== 'function' || typeof box.value !== 'function') {
70
+ if (scheduleRetry) { setTimeout(tryClear, 100); return; }
71
+ return;
72
+ }
73
+ var current = box.value();
74
+ if (current) {
75
+ box.setValue('');
76
+ if (typeof f.updateCurrentFilter === 'function') f.updateCurrentFilter();
77
+ if (typeof f.onFilterChanged === 'function') f.onFilterChanged();
78
+ }
79
+ } catch(_) {
80
+ if (scheduleRetry) setTimeout(tryClear, 100);
81
+ }
82
+ }
83
+ tryClear();
84
+ })()`;
85
+ }
86
+ //# sourceMappingURL=clear-console-filter.js.map
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Fakes shaped like the Chrome DevTools front-end objects
3
+ * `buildInternalLogHideScript()`'s generated source talks to, shared by
4
+ * console-filter.test.ts (what the hook does) and
5
+ * console-filter-degradation.test.ts (what happens when the panel is not there
6
+ * or the front-end API has moved).
7
+ *
8
+ * These are STUBS OF A FOREIGN API, not a second implementation: every test
9
+ * runs the real generated script string through `new Function`, so the fakes
10
+ * only have to expose the handful of members the script reaches for. What they
11
+ * cannot prove is that the real front-end still has those members — that is
12
+ * e2e/console-filter-live.spec.ts's job.
13
+ */
14
+ import { type Mock } from 'vitest';
15
+ export interface FakeViewMessage {
16
+ consoleMessage: () => {
17
+ messageText: string;
18
+ };
19
+ }
20
+ export type ShouldBeVisible = (this: unknown, viewMessage: FakeViewMessage) => boolean;
21
+ export interface FakeConsoleFilterClass {
22
+ original: Mock<ShouldBeVisible>;
23
+ prototype: {
24
+ shouldBeVisible?: ShouldBeVisible;
25
+ };
26
+ newInstance: () => {
27
+ shouldBeVisible: ShouldBeVisible;
28
+ };
29
+ }
30
+ export interface FakeConsoleView {
31
+ view: {
32
+ filter: {
33
+ currentFilter: object;
34
+ textFilterUI: {
35
+ value: () => string;
36
+ setValue: Mock<(next: string) => void>;
37
+ };
38
+ };
39
+ onFilterChanged: Mock<() => void>;
40
+ };
41
+ setValue: Mock<(next: string) => void>;
42
+ onFilterChanged: Mock<() => void>;
43
+ filterText: () => string;
44
+ }
45
+ /** A ConsoleViewMessage stub exposing the single field the hook inspects. */
46
+ export declare function createViewMessage(messageText: string): FakeViewMessage;
47
+ /**
48
+ * A ConsoleFilter "class": one shared prototype carrying `shouldBeVisible`,
49
+ * plus a factory for further instances off that same prototype — what
50
+ * `ConsoleFilter.clone()` produces. `original` is the pre-existing
51
+ * implementation the hook must delegate to.
52
+ */
53
+ export declare function createConsoleFilterClass(verdict?: boolean | ShouldBeVisible): FakeConsoleFilterClass;
54
+ /** A ConsoleFilter whose prototype chain carries no `shouldBeVisible` at all. */
55
+ export declare function createConsoleFilterClassWithoutHook(): {
56
+ prototype: Record<string, unknown>;
57
+ newInstance: () => object;
58
+ };
59
+ /** The ConsoleView surface the script reaches through: filter + refresh entry point. */
60
+ export declare function createConsoleView(currentFilter: object, initialFilterText?: string): FakeConsoleView;
61
+ /** A front end whose bootstrap has finished: the probe returns instead of throwing. */
62
+ export declare function createReadyEui(): {
63
+ ShortcutRegistry: {
64
+ ShortcutRegistry: {
65
+ instance: () => {};
66
+ };
67
+ };
68
+ };
69
+ export declare function createGlobalThis(view: unknown): {
70
+ EUI: {
71
+ ShortcutRegistry: {
72
+ ShortcutRegistry: {
73
+ instance: () => {};
74
+ };
75
+ };
76
+ };
77
+ Console: {
78
+ ConsoleView: {
79
+ instance: () => unknown;
80
+ };
81
+ };
82
+ };
83
+ export declare function run(script: string, fakeGlobalThis: object): void;
84
+ /**
85
+ * Collect `console.warn` output as plain strings for the whole test file.
86
+ *
87
+ * Reading `warnSpy.mock.calls` instead would hand every assertion an untyped
88
+ * `any[]`; the degradation tests care about WHICH warning was emitted, so the
89
+ * text has to survive into the assertion with its type intact.
90
+ */
91
+ export declare function recordWarnings(): {
92
+ messages: string[];
93
+ };
94
+ //# sourceMappingURL=console-filter-test-fixtures.d.ts.map
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Fakes shaped like the Chrome DevTools front-end objects
3
+ * `buildInternalLogHideScript()`'s generated source talks to, shared by
4
+ * console-filter.test.ts (what the hook does) and
5
+ * console-filter-degradation.test.ts (what happens when the panel is not there
6
+ * or the front-end API has moved).
7
+ *
8
+ * These are STUBS OF A FOREIGN API, not a second implementation: every test
9
+ * runs the real generated script string through `new Function`, so the fakes
10
+ * only have to expose the handful of members the script reaches for. What they
11
+ * cannot prove is that the real front-end still has those members — that is
12
+ * e2e/console-filter-live.spec.ts's job.
13
+ */
14
+ import { vi } from 'vitest';
15
+ /** A ConsoleViewMessage stub exposing the single field the hook inspects. */
16
+ export function createViewMessage(messageText) {
17
+ return { consoleMessage: () => ({ messageText }) };
18
+ }
19
+ /**
20
+ * A ConsoleFilter "class": one shared prototype carrying `shouldBeVisible`,
21
+ * plus a factory for further instances off that same prototype — what
22
+ * `ConsoleFilter.clone()` produces. `original` is the pre-existing
23
+ * implementation the hook must delegate to.
24
+ */
25
+ export function createConsoleFilterClass(verdict = true) {
26
+ const impl = typeof verdict === 'function' ? verdict : () => verdict;
27
+ const original = vi.fn(impl);
28
+ const prototype = { shouldBeVisible: original };
29
+ return {
30
+ original,
31
+ prototype,
32
+ newInstance: () => Object.create(prototype),
33
+ };
34
+ }
35
+ /** A ConsoleFilter whose prototype chain carries no `shouldBeVisible` at all. */
36
+ export function createConsoleFilterClassWithoutHook() {
37
+ const prototype = Object.create(null);
38
+ return { prototype, newInstance: () => Object.create(prototype) };
39
+ }
40
+ /** The ConsoleView surface the script reaches through: filter + refresh entry point. */
41
+ export function createConsoleView(currentFilter, initialFilterText = '') {
42
+ let filterText = initialFilterText;
43
+ const setValue = vi.fn((next) => { filterText = next; });
44
+ const onFilterChanged = vi.fn();
45
+ return {
46
+ view: {
47
+ filter: {
48
+ currentFilter,
49
+ textFilterUI: { value: () => filterText, setValue },
50
+ },
51
+ onFilterChanged,
52
+ },
53
+ setValue,
54
+ onFilterChanged,
55
+ filterText: () => filterText,
56
+ };
57
+ }
58
+ /** A front end whose bootstrap has finished: the probe returns instead of throwing. */
59
+ export function createReadyEui() {
60
+ return { ShortcutRegistry: { ShortcutRegistry: { instance: () => ({}) } } };
61
+ }
62
+ export function createGlobalThis(view) {
63
+ return { EUI: createReadyEui(), Console: { ConsoleView: { instance: () => view } } };
64
+ }
65
+ export function run(script, fakeGlobalThis) {
66
+ new Function('globalThis', script)(fakeGlobalThis);
67
+ }
68
+ /**
69
+ * Collect `console.warn` output as plain strings for the whole test file.
70
+ *
71
+ * Reading `warnSpy.mock.calls` instead would hand every assertion an untyped
72
+ * `any[]`; the degradation tests care about WHICH warning was emitted, so the
73
+ * text has to survive into the assertion with its type intact.
74
+ */
75
+ export function recordWarnings() {
76
+ const record = { messages: [] };
77
+ vi.spyOn(console, 'warn').mockImplementation((...args) => {
78
+ record.messages.push(args.map((arg) => String(arg)).join(' '));
79
+ });
80
+ return record;
81
+ }
82
+ //# sourceMappingURL=console-filter-test-fixtures.js.map