@dimina-kit/devtools 0.3.1-dev.20260518114324 → 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 (89) hide show
  1. package/README.md +33 -71
  2. package/dist/main/app/app.js +5 -0
  3. package/dist/main/app/bootstrap.js +2 -1
  4. package/dist/main/app/launch.d.ts +1 -1
  5. package/dist/main/app/launch.js +6 -7
  6. package/dist/main/index.bundle.js +306 -317
  7. package/dist/main/ipc/panels.js +3 -5
  8. package/dist/main/ipc/projects.d.ts +1 -1
  9. package/dist/main/ipc/projects.js +5 -5
  10. package/dist/main/ipc/settings.d.ts +1 -1
  11. package/dist/main/ipc/settings.js +14 -1
  12. package/dist/main/ipc/simulator.d.ts +1 -1
  13. package/dist/main/ipc/simulator.js +1 -10
  14. package/dist/main/services/automation/exec.d.ts +2 -0
  15. package/dist/main/services/automation/exec.js +7 -9
  16. package/dist/main/services/automation/handlers/app.js +37 -51
  17. package/dist/main/services/automation/handlers/element.js +27 -41
  18. package/dist/main/services/default-adapter.js +3 -3
  19. package/dist/main/services/mcp/index.d.ts +1 -0
  20. package/dist/main/services/mcp/index.js +1 -0
  21. package/dist/main/services/mcp/server.js +5 -0
  22. package/dist/main/services/mcp/status.d.ts +10 -0
  23. package/dist/main/services/mcp/status.js +14 -0
  24. package/dist/main/services/mcp/target-manager.js +2 -1
  25. package/dist/main/services/notifications/renderer-notifier.d.ts +3 -3
  26. package/dist/main/services/notifications/renderer-notifier.js +3 -6
  27. package/dist/main/services/projects/local-provider.js +3 -3
  28. package/dist/main/services/projects/project-repository.d.ts +0 -1
  29. package/dist/main/services/settings/index.js +2 -1
  30. package/dist/main/services/simulator-storage/index.js +47 -77
  31. package/dist/main/services/views/view-manager.d.ts +3 -7
  32. package/dist/main/services/views/view-manager.js +20 -27
  33. package/dist/main/services/window-service.d.ts +3 -3
  34. package/dist/main/services/workbench-context.d.ts +3 -6
  35. package/dist/main/services/workbench-context.js +1 -3
  36. package/dist/main/services/workspace/workspace-service.js +8 -24
  37. package/dist/main/utils/theme.d.ts +24 -0
  38. package/dist/main/utils/theme.js +38 -1
  39. package/dist/preload/index.d.ts +5 -2
  40. package/dist/preload/index.js +3 -2
  41. package/dist/preload/instrumentation/app-data.d.ts +32 -2
  42. package/dist/preload/instrumentation/app-data.js +187 -172
  43. package/dist/preload/instrumentation/index.d.ts +2 -2
  44. package/dist/preload/instrumentation/index.js +2 -2
  45. package/dist/preload/instrumentation/wxml.d.ts +16 -4
  46. package/dist/preload/instrumentation/wxml.js +188 -178
  47. package/dist/preload/miniapp-snapshot/host.d.ts +12 -0
  48. package/dist/preload/miniapp-snapshot/host.js +117 -0
  49. package/dist/preload/miniapp-snapshot/types.d.ts +62 -0
  50. package/dist/preload/miniapp-snapshot/types.js +15 -0
  51. package/dist/preload/runtime/bridge.js +5 -24
  52. package/dist/preload/runtime/custom-apis.d.ts +1 -1
  53. package/dist/preload/runtime/custom-apis.js +3 -7
  54. package/dist/preload/shared/expose.d.ts +15 -0
  55. package/dist/preload/shared/expose.js +33 -0
  56. package/dist/preload/shared/page-iframe.d.ts +3 -0
  57. package/dist/preload/shared/page-iframe.js +6 -0
  58. package/dist/preload/shared/types.d.ts +2 -0
  59. package/dist/preload/windows/simulator.js +400 -348
  60. package/dist/renderer/assets/constants-DI382mTP.js +2 -0
  61. package/dist/renderer/assets/index-D8VFYBh-.js +46 -0
  62. package/dist/renderer/assets/{input-DqVQNCx_.js → input-CoWcfa8u.js} +2 -2
  63. package/dist/renderer/assets/ipc-transport-Cd2xPrsa.js +9 -0
  64. package/dist/renderer/assets/popover-Nq5gT9DO.js +2 -0
  65. package/dist/renderer/assets/select-By5KH-UG.js +2 -0
  66. package/dist/renderer/assets/{settings-BFNfnYvU.js → settings-Dj_N70qR.js} +2 -2
  67. package/dist/renderer/assets/settings-api-Do0_Smq1.js +2 -0
  68. package/dist/renderer/assets/workbenchSettings-CazSLGYt.js +8 -0
  69. package/dist/renderer/entries/main/index.html +5 -4
  70. package/dist/renderer/entries/popover/index.html +5 -4
  71. package/dist/renderer/entries/settings/index.html +4 -4
  72. package/dist/renderer/entries/workbench-settings/index.html +4 -3
  73. package/dist/shared/ipc-channels.d.ts +4 -12
  74. package/dist/shared/ipc-channels.js +10 -14
  75. package/dist/shared/simulator-route.d.ts +72 -0
  76. package/dist/shared/simulator-route.js +169 -0
  77. package/dist/shared/types.d.ts +2 -10
  78. package/dist/simulator/assets/simulator-DJCozrU5.js +9 -0
  79. package/dist/simulator/simulator.html +6 -43
  80. package/package.json +4 -4
  81. package/dist/preload/instrumentation/disposable.d.ts +0 -11
  82. package/dist/preload/instrumentation/disposable.js +0 -15
  83. package/dist/renderer/assets/index-Czz_bp6b.js +0 -46
  84. package/dist/renderer/assets/ipc-transport-CCHrCtDr.js +0 -9
  85. package/dist/renderer/assets/popover-BRg4XI_w.js +0 -2
  86. package/dist/renderer/assets/select-CvILHHZU.js +0 -2
  87. package/dist/renderer/assets/settings-api-DOAgmBst.js +0 -2
  88. package/dist/renderer/assets/workbenchSettings-DjVMgMMH.js +0 -8
  89. package/dist/simulator/assets/simulator-DL6kOCq-.js +0 -9
@@ -1,10 +1,11 @@
1
1
  import { app, nativeTheme } from 'electron';
2
2
  import fs from 'fs';
3
3
  import path from 'path';
4
+ import { DEFAULT_CDP_PORT } from '../../../shared/constants.js';
4
5
  const DEFAULTS = {
5
6
  cdp: {
6
7
  enabled: false,
7
- port: 9222,
8
+ port: DEFAULT_CDP_PORT,
8
9
  },
9
10
  mcp: {
10
11
  enabled: false,
@@ -204,6 +204,35 @@ export function setupSimulatorStorage(host, options) {
204
204
  }
205
205
  return { securityOrigin: cachedOrigin, isLocalStorage: true };
206
206
  }
207
+ async function withStorageWrite(fn) {
208
+ await ensureAttached();
209
+ if (!attachedWc || attachedWc.isDestroyed()) {
210
+ return { ok: false, error: 'simulator not attached' };
211
+ }
212
+ const storageId = await getStorageId();
213
+ if (!storageId)
214
+ return { ok: false, error: 'failed to resolve simulator origin' };
215
+ try {
216
+ return await fn({ wc: attachedWc, storageId });
217
+ }
218
+ catch (e) {
219
+ return { ok: false, error: e.message };
220
+ }
221
+ }
222
+ async function withStorageRead(fallback, fn) {
223
+ await ensureAttached();
224
+ if (!attachedWc || attachedWc.isDestroyed())
225
+ return fallback;
226
+ try {
227
+ const storageId = await getStorageId();
228
+ if (!storageId)
229
+ return fallback;
230
+ return await fn({ wc: attachedWc, storageId });
231
+ }
232
+ catch {
233
+ return fallback;
234
+ }
235
+ }
207
236
  /**
208
237
  * Push a storage event synthesised from the write path itself, in addition
209
238
  * to whatever CDP forwards via `DOMStorage.domStorageItem*`. The CDP
@@ -228,109 +257,53 @@ export function setupSimulatorStorage(host, options) {
228
257
  host.send(SimulatorStorageChannel.Event, evt);
229
258
  }
230
259
  async function setItem(key, value) {
231
- await ensureAttached();
232
- if (!attachedWc || attachedWc.isDestroyed()) {
233
- return { ok: false, error: 'simulator not attached' };
234
- }
235
- const storageId = await getStorageId();
236
- if (!storageId)
237
- return { ok: false, error: 'failed to resolve simulator origin' };
238
- try {
239
- await attachedWc.debugger.sendCommand('DOMStorage.setDOMStorageItem', {
240
- storageId,
241
- key,
242
- value,
243
- });
260
+ return withStorageWrite(async ({ wc, storageId }) => {
261
+ await wc.debugger.sendCommand('DOMStorage.setDOMStorageItem', { storageId, key, value });
244
262
  pushSyntheticEvent({ type: 'added', key, newValue: value });
245
263
  return { ok: true };
246
- }
247
- catch (e) {
248
- return { ok: false, error: e.message };
249
- }
264
+ });
250
265
  }
251
266
  async function removeItem(key) {
252
- await ensureAttached();
253
- if (!attachedWc || attachedWc.isDestroyed()) {
254
- return { ok: false, error: 'simulator not attached' };
255
- }
256
- const storageId = await getStorageId();
257
- if (!storageId)
258
- return { ok: false, error: 'failed to resolve simulator origin' };
259
- try {
260
- await attachedWc.debugger.sendCommand('DOMStorage.removeDOMStorageItem', {
261
- storageId,
262
- key,
263
- });
267
+ return withStorageWrite(async ({ wc, storageId }) => {
268
+ await wc.debugger.sendCommand('DOMStorage.removeDOMStorageItem', { storageId, key });
264
269
  pushSyntheticEvent({ type: 'removed', key });
265
270
  return { ok: true };
266
- }
267
- catch (e) {
268
- return { ok: false, error: e.message };
269
- }
271
+ });
270
272
  }
271
273
  // Scoped clear: when an appId is active, removes only its prefixed keys so
272
274
  // we don't nuke other projects' state sharing the simulator partition.
273
275
  // Falls back to origin-wide `DOMStorage.clear` only when no active appId is
274
276
  // set (matches the snapshot filter's documented null-fallback).
275
277
  async function clearScoped() {
276
- await ensureAttached();
277
- if (!attachedWc || attachedWc.isDestroyed()) {
278
- return { ok: false, error: 'simulator not attached' };
279
- }
280
- const storageId = await getStorageId();
281
- if (!storageId)
282
- return { ok: false, error: 'failed to resolve simulator origin' };
283
- const prefix = activePrefix();
284
- try {
278
+ return withStorageWrite(async ({ wc, storageId }) => {
279
+ const prefix = activePrefix();
285
280
  if (!prefix) {
286
- await attachedWc.debugger.sendCommand('DOMStorage.clear', { storageId });
281
+ await wc.debugger.sendCommand('DOMStorage.clear', { storageId });
287
282
  return { ok: true };
288
283
  }
289
- const result = (await attachedWc.debugger.sendCommand('DOMStorage.getDOMStorageItems', {
284
+ const result = (await wc.debugger.sendCommand('DOMStorage.getDOMStorageItems', {
290
285
  storageId,
291
286
  }));
292
287
  for (const [key] of result.entries) {
293
288
  if (!key.startsWith(prefix))
294
289
  continue;
295
- await attachedWc.debugger.sendCommand('DOMStorage.removeDOMStorageItem', {
296
- storageId,
297
- key,
298
- });
290
+ await wc.debugger.sendCommand('DOMStorage.removeDOMStorageItem', { storageId, key });
299
291
  }
300
292
  return { ok: true };
301
- }
302
- catch (e) {
303
- return { ok: false, error: e.message };
304
- }
293
+ });
305
294
  }
306
295
  // Origin-wide clear regardless of the active appId — wipes every project's
307
296
  // state in the shared simulator partition. The renderer guards this with a
308
297
  // confirm dialog; we don't second-guess here.
309
298
  async function clearAll() {
310
- await ensureAttached();
311
- if (!attachedWc || attachedWc.isDestroyed()) {
312
- return { ok: false, error: 'simulator not attached' };
313
- }
314
- const storageId = await getStorageId();
315
- if (!storageId)
316
- return { ok: false, error: 'failed to resolve simulator origin' };
317
- try {
318
- await attachedWc.debugger.sendCommand('DOMStorage.clear', { storageId });
299
+ return withStorageWrite(async ({ wc, storageId }) => {
300
+ await wc.debugger.sendCommand('DOMStorage.clear', { storageId });
319
301
  return { ok: true };
320
- }
321
- catch (e) {
322
- return { ok: false, error: e.message };
323
- }
302
+ });
324
303
  }
325
304
  async function getSnapshot() {
326
- await ensureAttached();
327
- if (!attachedWc || attachedWc.isDestroyed())
328
- return [];
329
- try {
330
- const storageId = await getStorageId();
331
- if (!storageId)
332
- return [];
333
- const result = (await attachedWc.debugger.sendCommand('DOMStorage.getDOMStorageItems', {
305
+ return withStorageRead([], async ({ wc, storageId }) => {
306
+ const result = (await wc.debugger.sendCommand('DOMStorage.getDOMStorageItems', {
334
307
  storageId,
335
308
  }));
336
309
  const prefix = activePrefix();
@@ -340,10 +313,7 @@ export function setupSimulatorStorage(host, options) {
340
313
  // Keys are returned with their `${appId}_` prefix intact; stripping is
341
314
  // a follow-up so the panel UI can stay compatible with the raw keys.
342
315
  return filtered.map(([key, value]) => ({ key, value }));
343
- }
344
- catch {
345
- return [];
346
- }
316
+ });
347
317
  }
348
318
  // Attach to any simulator webview that already exists (project may have
349
319
  // been opened before this function runs).
@@ -5,7 +5,7 @@ import { type WorkbenchContext } from '../workbench-context.js';
5
5
  * full WorkbenchContext here; typing it this way documents the actual dependency.
6
6
  */
7
7
  export interface ViewManagerContext {
8
- mainWindow: WorkbenchContext['mainWindow'];
8
+ windows: WorkbenchContext['windows'];
9
9
  rendererDir: string;
10
10
  panels: string[];
11
11
  notify: WorkbenchContext['notify'];
@@ -52,14 +52,10 @@ export interface ViewManager {
52
52
  repositionAll(): void;
53
53
  /** Destroy all overlay webContents and null out the cached views. */
54
54
  disposeAll(): void;
55
- /** Log current child-view count of the main contentView. */
56
- logChildViews(label: string): void;
57
- /** Reposition only the simulator overlay (for simulator width changes). */
58
- positionSimulator(simWidth: number): void;
59
- /** Reposition only the settings overlay. */
60
- positionSettings(): void;
61
55
  /** Return the webContents ID of the currently attached simulator. */
62
56
  getSimulatorWebContentsId(): number | null;
57
+ /** Return the live webContents of the currently attached simulator, or null. */
58
+ getSimulatorWebContents(): WebContents | null;
63
59
  /** Return the last known simulator width. */
64
60
  getLastSimWidth(): number;
65
61
  /** Whether the simulator overlay is currently added to the contentView. */
@@ -24,9 +24,9 @@ export function createViewManager(ctx) {
24
24
  function destroyViewInternal(view) {
25
25
  if (!view)
26
26
  return;
27
- if (!ctx.mainWindow.isDestroyed()) {
27
+ if (!ctx.windows.mainWindow.isDestroyed()) {
28
28
  try {
29
- ctx.mainWindow.contentView.removeChildView(view);
29
+ ctx.windows.mainWindow.contentView.removeChildView(view);
30
30
  }
31
31
  catch { /* already removed */ }
32
32
  }
@@ -38,21 +38,21 @@ export function createViewManager(ctx) {
38
38
  catch { /* ignore */ }
39
39
  }
40
40
  function applySimulatorBounds(simWidth) {
41
- if (!simulatorView || ctx.mainWindow.isDestroyed())
41
+ if (!simulatorView || ctx.windows.mainWindow.isDestroyed())
42
42
  return;
43
- const [w = 0, h = 0] = ctx.mainWindow.getContentSize();
43
+ const [w = 0, h = 0] = ctx.windows.mainWindow.getContentSize();
44
44
  simulatorView.setBounds(layout.computeSimulatorBounds(w, h, simWidth));
45
45
  }
46
46
  function applySettingsBounds() {
47
- if (!settingsView || ctx.mainWindow.isDestroyed())
47
+ if (!settingsView || ctx.windows.mainWindow.isDestroyed())
48
48
  return;
49
- const [w = 0, h = 0] = ctx.mainWindow.getContentSize();
49
+ const [w = 0, h = 0] = ctx.windows.mainWindow.getContentSize();
50
50
  settingsView.setBounds(layout.computeSettingsBounds(w, h));
51
51
  }
52
52
  function applyPopoverBounds() {
53
- if (!popoverView || ctx.mainWindow.isDestroyed())
53
+ if (!popoverView || ctx.windows.mainWindow.isDestroyed())
54
54
  return;
55
- const [w = 0, h = 0] = ctx.mainWindow.getContentSize();
55
+ const [w = 0, h = 0] = ctx.windows.mainWindow.getContentSize();
56
56
  popoverView.setBounds(layout.computePopoverBounds(w, h));
57
57
  }
58
58
  // ── ViewManager methods ─────────────────────────────────────────────────
@@ -105,7 +105,7 @@ export function createViewManager(ctx) {
105
105
  `).catch(() => { });
106
106
  });
107
107
  if (getDefaultTab(ctx) === 'simulator') {
108
- ctx.mainWindow.contentView.addChildView(simulatorView);
108
+ ctx.windows.mainWindow.contentView.addChildView(simulatorView);
109
109
  simulatorViewAdded = true;
110
110
  applySimulatorBounds(simWidth);
111
111
  }
@@ -126,7 +126,7 @@ export function createViewManager(ctx) {
126
126
  if (!simulatorView)
127
127
  return;
128
128
  if (!simulatorViewAdded) {
129
- ctx.mainWindow.contentView.addChildView(simulatorView);
129
+ ctx.windows.mainWindow.contentView.addChildView(simulatorView);
130
130
  simulatorViewAdded = true;
131
131
  }
132
132
  applySimulatorBounds(simWidth);
@@ -134,7 +134,7 @@ export function createViewManager(ctx) {
134
134
  function hideSimulator() {
135
135
  if (simulatorView && simulatorViewAdded) {
136
136
  try {
137
- ctx.mainWindow.contentView.removeChildView(simulatorView);
137
+ ctx.windows.mainWindow.contentView.removeChildView(simulatorView);
138
138
  }
139
139
  catch (e) {
140
140
  console.error('[workbench] hideSimulator error', e);
@@ -158,7 +158,7 @@ export function createViewManager(ctx) {
158
158
  await settingsView.webContents.loadFile(path.join(ctx.rendererDir, 'entries/settings/index.html'));
159
159
  }
160
160
  if (!settingsViewAdded) {
161
- ctx.mainWindow.contentView.addChildView(settingsView);
161
+ ctx.windows.mainWindow.contentView.addChildView(settingsView);
162
162
  settingsViewAdded = true;
163
163
  }
164
164
  applySettingsBounds();
@@ -166,7 +166,7 @@ export function createViewManager(ctx) {
166
166
  function hideSettings() {
167
167
  if (settingsView && settingsViewAdded) {
168
168
  try {
169
- ctx.mainWindow.contentView.removeChildView(settingsView);
169
+ ctx.windows.mainWindow.contentView.removeChildView(settingsView);
170
170
  }
171
171
  catch { /* ignore */ }
172
172
  settingsViewAdded = false;
@@ -186,7 +186,7 @@ export function createViewManager(ctx) {
186
186
  applyNavigationHardening(popover.webContents, ctx.rendererDir);
187
187
  popoverView = popover;
188
188
  popover.setBackgroundColor('#00000000');
189
- ctx.mainWindow.contentView.addChildView(popover);
189
+ ctx.windows.mainWindow.contentView.addChildView(popover);
190
190
  applyPopoverBounds();
191
191
  popover.webContents.once('did-finish-load', () => {
192
192
  ctx.notify.popoverInit(popover, data);
@@ -211,16 +211,6 @@ export function createViewManager(ctx) {
211
211
  function disposeAll() {
212
212
  detachSimulator();
213
213
  }
214
- function logChildViews(_label) {
215
- // Debug helper — intentionally a no-op in production. Kept on the
216
- // ViewManager interface so call sites and tests stay stable.
217
- }
218
- function positionSimulator(simWidth) {
219
- applySimulatorBounds(simWidth);
220
- }
221
- function positionSettings() {
222
- applySettingsBounds();
223
- }
224
214
  function resize(simWidth) {
225
215
  lastSimWidth = simWidth;
226
216
  if (simulatorViewAdded)
@@ -250,10 +240,13 @@ export function createViewManager(ctx) {
250
240
  hidePopover,
251
241
  repositionAll,
252
242
  disposeAll,
253
- logChildViews,
254
- positionSimulator,
255
- positionSettings,
256
243
  getSimulatorWebContentsId: () => simulatorWebContentsId,
244
+ getSimulatorWebContents: () => {
245
+ if (simulatorWebContentsId == null)
246
+ return null;
247
+ const wc = webContents.fromId(simulatorWebContentsId);
248
+ return wc && !wc.isDestroyed() ? wc : null;
249
+ },
257
250
  getLastSimWidth: () => lastSimWidth,
258
251
  isSimulatorAdded: () => simulatorViewAdded,
259
252
  hasSimulatorView: () => simulatorView !== null,
@@ -2,9 +2,9 @@ import type { BrowserWindow } from 'electron';
2
2
  /**
3
3
  * Owns every top-level BrowserWindow the workbench is responsible for.
4
4
  *
5
- * Callers should prefer this service over reading bare `mainWindow` /
6
- * `workbenchSettingsWindow` fields off `WorkbenchContext` — the latter
7
- * remain as @deprecated synchronized mirrors during the migration window.
5
+ * This service is the single source of truth for the main and settings
6
+ * windows; callers reach them via `ctx.windows.mainWindow` /
7
+ * `ctx.windows.settingsWindow`.
8
8
  */
9
9
  export interface WindowService {
10
10
  /** The primary devtools window. Created during app bootstrap. */
@@ -7,21 +7,18 @@ import { type ViewManager } from './views/view-manager.js';
7
7
  import { type WindowService } from './window-service.js';
8
8
  import { type WorkspaceService } from './workspace/workspace-service.js';
9
9
  import { sanitizeTemplates } from './projects/templates.js';
10
- import type { CreateProjectInput, ProjectsProvider, ProjectTemplate } from './projects/types.js';
10
+ import type { ProjectsProvider, ProjectTemplate } from './projects/types.js';
11
+ import type { CustomCreateProjectDialogResult } from '../../shared/types.js';
11
12
  /**
12
13
  * Shared mutable state for the workbench application.
13
14
  * Passed to each IPC module so they can read/write shared state without closures.
14
15
  */
15
16
  export interface WorkbenchContext {
16
- /** @deprecated use ctx.windows.mainWindow */
17
- mainWindow: BrowserWindow;
18
17
  adapter: CompilationAdapter;
19
18
  /** Absolute path to the preload script loaded into the simulator webview */
20
19
  preloadPath: string;
21
20
  /** Absolute path to the renderer dist directory */
22
21
  rendererDir: string;
23
- /** @deprecated use ctx.windows.settingsWindow / setSettingsWindow / closeSettingsWindow */
24
- workbenchSettingsWindow: BrowserWindow | null;
25
22
  /** Built-in panel IDs to display (default: all) */
26
23
  panels: string[];
27
24
  /** Custom API namespace names (e.g. ['qd']) passed to the simulator */
@@ -73,7 +70,7 @@ export interface WorkbenchContext {
73
70
  customCreateProjectDialog?: (ctx: {
74
71
  parentWindow: BrowserWindow;
75
72
  templates: ProjectTemplate[];
76
- }) => Promise<CreateProjectInput | null>;
73
+ }) => Promise<CustomCreateProjectDialogResult>;
77
74
  /**
78
75
  * Trust predicate consulted by `IpcRegistry` for every incoming IPC.
79
76
  * Resolves the currently-trusted senders (main renderer + overlays)
@@ -20,7 +20,6 @@ export function getDefaultTab(ctx) {
20
20
  }
21
21
  export function createWorkbenchContext(opts) {
22
22
  const ctx = {
23
- mainWindow: opts.mainWindow,
24
23
  adapter: opts.adapter ?? defaultAdapter,
25
24
  preloadPath: opts.preloadPath,
26
25
  rendererDir: opts.rendererDir,
@@ -29,10 +28,9 @@ export function createWorkbenchContext(opts) {
29
28
  appName: opts.appName ?? 'Dimina DevTools',
30
29
  toolbarActions: opts.toolbarActions,
31
30
  brandingProvider: opts.brandingProvider,
32
- workbenchSettingsWindow: null,
33
31
  };
34
32
  ctx.registry = new DisposableRegistry();
35
- ctx.windows = createWindowService(ctx.mainWindow);
33
+ ctx.windows = createWindowService(opts.mainWindow);
36
34
  ctx.views = createViewManager(ctx);
37
35
  ctx.notify = createRendererNotifier(ctx);
38
36
  ctx.projectsProvider = opts.projectsProvider ?? createLocalProjectsProvider();
@@ -1,4 +1,3 @@
1
- import { webContents } from 'electron';
2
1
  import * as repo from '../projects/project-repository.js';
3
2
  import { DEFAULT_COMPILE_CONFIG } from '../projects/types.js';
4
3
  import { clearSimulatorServicewechatReferer, setSimulatorServicewechatReferer, } from '../simulator/referer.js';
@@ -39,24 +38,12 @@ export function createWorkspaceService(ctx) {
39
38
  setSimulatorServicewechatReferer(appInfo.appId, typeof appInfo.version === 'string' ? appInfo.version : undefined);
40
39
  }
41
40
  }
42
- // Delegate to the host-injected (or default) ProjectsProvider on the
43
- // context. When the host omits an optional method, we apply a safe
44
- // documented default — never silently fall back to `repo.*`, because a
45
- // remote provider's project paths are not on the local filesystem.
46
- //
47
- // The `??` here is a back-compat path for hand-rolled WorkbenchContext
48
- // values (used in a couple of legacy tests). createWorkbenchContext
49
- // always installs LocalProjectsProvider, so production never enters this
50
- // branch.
51
- const provider = ctx.projectsProvider ?? {
52
- listProjects: () => repo.listProjects(),
53
- addProject: (p) => repo.addProject(p),
54
- removeProject: (p) => repo.removeProject(p),
55
- validateProjectDir: (p) => repo.validateProjectDir(p),
56
- updateLastOpened: (p) => repo.updateLastOpened(p),
57
- getCompileConfig: (p) => repo.getCompileConfig(p),
58
- saveCompileConfig: (p, c) => repo.saveCompileConfig(p, c),
59
- };
41
+ // Delegate to the host-injected (or default LocalProjectsProvider)
42
+ // ProjectsProvider on the context. When the host omits an optional method,
43
+ // we apply a safe documented default — never silently fall back to
44
+ // `repo.*`, because a remote provider's project paths are not on the local
45
+ // filesystem.
46
+ const provider = ctx.projectsProvider;
60
47
  return {
61
48
  listProjects: async () => provider.listProjects(),
62
49
  addProject: async (dirPath) => provider.addProject(dirPath),
@@ -129,11 +116,8 @@ export function createWorkspaceService(ctx) {
129
116
  getProjectPath: () => currentProjectPath,
130
117
  hasActiveSession: () => currentSession !== null,
131
118
  async captureThumbnail(projectPath) {
132
- const simWcId = ctx.views.getSimulatorWebContentsId();
133
- if (!simWcId)
134
- return null;
135
- const wc = webContents.fromId(simWcId);
136
- if (!wc || wc.isDestroyed())
119
+ const wc = ctx.views.getSimulatorWebContents();
120
+ if (!wc)
137
121
  return null;
138
122
  try {
139
123
  const image = await wc.capturePage();
@@ -1,3 +1,4 @@
1
+ import { type Disposable } from './disposable.js';
1
2
  /**
2
3
  * Background color that matches the current system color scheme.
3
4
  * Pass as `backgroundColor` when creating BrowserWindows to prevent
@@ -7,4 +8,27 @@
7
8
  * Light: hsl(0 0% 98%) ≈ #fafafa (--color-bg)
8
9
  */
9
10
  export declare function themeBg(): string;
11
+ /**
12
+ * Install a single process-wide listener that keeps every window's native
13
+ * `backgroundColor` in sync with the active color scheme.
14
+ *
15
+ * A window's `backgroundColor` is otherwise frozen at the value passed to its
16
+ * constructor: after a theme switch the stale color bleeds through wherever
17
+ * native chrome and the WebContents meet. On Windows/Linux (in-window menu
18
+ * bar) it shows as a light hairline between the menu bar and the page; on
19
+ * macOS (global menu bar) it is latent — only a wrong-color flash on resize.
20
+ * The defect is platform-agnostic, so the fix is too: one `nativeTheme`
21
+ * `updated` listener re-syncs every current and future BrowserWindow.
22
+ *
23
+ * Known limitation: on Linux the `updated` event does not fire for OS-level
24
+ * system theme changes (electron/electron#25925) — only for explicit
25
+ * `nativeTheme.themeSource` assignments. In-app theme switches go through
26
+ * `applyTheme()` and are unaffected on every platform; the gap is limited to
27
+ * Linux + `theme: 'system'` + an OS theme change, an upstream Electron
28
+ * limitation that also leaves the renderer's `prefers-color-scheme` stale.
29
+ *
30
+ * Returns a Disposable that detaches the listener. Install it once during
31
+ * app setup and hand the Disposable to the workbench registry.
32
+ */
33
+ export declare function installThemeBackgroundSync(): Disposable;
10
34
  //# sourceMappingURL=theme.d.ts.map
@@ -1,4 +1,5 @@
1
- import { nativeTheme } from 'electron';
1
+ import { BrowserWindow, nativeTheme } from 'electron';
2
+ import { toDisposable } from './disposable.js';
2
3
  /**
3
4
  * Background color that matches the current system color scheme.
4
5
  * Pass as `backgroundColor` when creating BrowserWindows to prevent
@@ -10,4 +11,40 @@ import { nativeTheme } from 'electron';
10
11
  export function themeBg() {
11
12
  return nativeTheme.shouldUseDarkColors ? '#1a1a1a' : '#fafafa';
12
13
  }
14
+ /**
15
+ * Install a single process-wide listener that keeps every window's native
16
+ * `backgroundColor` in sync with the active color scheme.
17
+ *
18
+ * A window's `backgroundColor` is otherwise frozen at the value passed to its
19
+ * constructor: after a theme switch the stale color bleeds through wherever
20
+ * native chrome and the WebContents meet. On Windows/Linux (in-window menu
21
+ * bar) it shows as a light hairline between the menu bar and the page; on
22
+ * macOS (global menu bar) it is latent — only a wrong-color flash on resize.
23
+ * The defect is platform-agnostic, so the fix is too: one `nativeTheme`
24
+ * `updated` listener re-syncs every current and future BrowserWindow.
25
+ *
26
+ * Known limitation: on Linux the `updated` event does not fire for OS-level
27
+ * system theme changes (electron/electron#25925) — only for explicit
28
+ * `nativeTheme.themeSource` assignments. In-app theme switches go through
29
+ * `applyTheme()` and are unaffected on every platform; the gap is limited to
30
+ * Linux + `theme: 'system'` + an OS theme change, an upstream Electron
31
+ * limitation that also leaves the renderer's `prefers-color-scheme` stale.
32
+ *
33
+ * Returns a Disposable that detaches the listener. Install it once during
34
+ * app setup and hand the Disposable to the workbench registry.
35
+ */
36
+ export function installThemeBackgroundSync() {
37
+ const apply = () => {
38
+ const bg = themeBg();
39
+ for (const win of BrowserWindow.getAllWindows()) {
40
+ if (!win.isDestroyed()) {
41
+ win.setBackgroundColor(bg);
42
+ }
43
+ }
44
+ };
45
+ nativeTheme.on('updated', apply);
46
+ return toDisposable(() => {
47
+ nativeTheme.removeListener('updated', apply);
48
+ });
49
+ }
13
50
  //# sourceMappingURL=theme.js.map
@@ -10,8 +10,11 @@
10
10
  * bundled by esbuild, never re-exported through this barrel.
11
11
  */
12
12
  export { installConsoleInstrumentation } from './instrumentation/console.js';
13
- export { installAppDataInstrumentation, sendAllAppData } from './instrumentation/app-data.js';
14
- export { installWxmlInstrumentation, sendWxmlTree, setupWxmlObserver } from './instrumentation/wxml.js';
13
+ export { createAppDataSource } from './instrumentation/app-data.js';
14
+ export type { AppDataSnapshot } from './instrumentation/app-data.js';
15
+ export { createWxmlSource } from './instrumentation/wxml.js';
16
+ export { createMiniappSnapshotHost } from './miniapp-snapshot/host.js';
17
+ export type { MiniappSnapshotHost, MiniappSnapshotSource, SnapshotEnvelope, SnapshotSourceId, } from './miniapp-snapshot/types.js';
15
18
  export { installSimulatorBridge } from './runtime/bridge.js';
16
19
  export { installCustomApisBridge } from './runtime/custom-apis.js';
17
20
  export type { DiminaCustomApisBridge } from './runtime/custom-apis.js';
@@ -10,8 +10,9 @@
10
10
  * bundled by esbuild, never re-exported through this barrel.
11
11
  */
12
12
  export { installConsoleInstrumentation } from './instrumentation/console.js';
13
- export { installAppDataInstrumentation, sendAllAppData } from './instrumentation/app-data.js';
14
- export { installWxmlInstrumentation, sendWxmlTree, setupWxmlObserver } from './instrumentation/wxml.js';
13
+ export { createAppDataSource } from './instrumentation/app-data.js';
14
+ export { createWxmlSource } from './instrumentation/wxml.js';
15
+ export { createMiniappSnapshotHost } from './miniapp-snapshot/host.js';
15
16
  export { installSimulatorBridge } from './runtime/bridge.js';
16
17
  export { installCustomApisBridge } from './runtime/custom-apis.js';
17
18
  export { setupApiCompatHook } from './shared/api-compat.js';
@@ -1,3 +1,33 @@
1
- export declare function installAppDataInstrumentation(): () => void;
2
- export declare function sendAllAppData(): void;
1
+ import type { MiniappSnapshotSource } from '../miniapp-snapshot/types.js';
2
+ /**
3
+ * The AppData snapshot — the full, cumulative panel state.
4
+ *
5
+ * - `bridges` lists every page bridge in chronological (insertion) order, each
6
+ * carrying its page route (`pagePath`), so renderer tabs render in a stable
7
+ * sequence.
8
+ * - `entries` maps `bridgeId → (componentPath | moduleId) → setData state`.
9
+ */
10
+ export interface AppDataSnapshot {
11
+ bridges: Array<{
12
+ id: string;
13
+ pagePath: string | null;
14
+ }>;
15
+ entries: Record<string, Record<string, unknown>>;
16
+ }
17
+ /**
18
+ * The AppData snapshot data source.
19
+ *
20
+ * Instruments `window.Worker` (incoming `message` decoding + outgoing
21
+ * `postMessage` interception) and installs `window.__simulatorHook.appData`,
22
+ * accumulating per-(bridgeId, moduleId) setData state in an internal cache.
23
+ * Every cache mutation — an accepted `ub`/`page_*` worker message, or a
24
+ * `pageUnload` evicting a bridge — calls `emit()` so the `miniappSnapshot`
25
+ * host republishes the full snapshot. The source itself never touches IPC:
26
+ * the host owns push, pull and the install-time publish.
27
+ *
28
+ * It keeps the `__simulatorData.getAppdata()` automation surface working by
29
+ * mirroring the flat cache into the simulator bridge via `setAppDataSnapshot`
30
+ * / `clearAppDataSnapshot`.
31
+ */
32
+ export declare function createAppDataSource(): MiniappSnapshotSource<AppDataSnapshot>;
3
33
  //# sourceMappingURL=app-data.d.ts.map