@dimina-kit/devtools 0.4.0-dev.20260801163345 → 0.4.0-dev.20260824071518

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 (113) hide show
  1. package/dist/main/app/app.js +12 -1
  2. package/dist/main/index.bundle.js +584 -323
  3. package/dist/main/ipc/index.d.ts +1 -0
  4. package/dist/main/ipc/index.js +1 -0
  5. package/dist/main/ipc/session.js +11 -0
  6. package/dist/main/ipc/tooltip.d.ts +13 -0
  7. package/dist/main/ipc/tooltip.js +28 -0
  8. package/dist/main/services/layout/index.d.ts +11 -0
  9. package/dist/main/services/layout/index.js +23 -0
  10. package/dist/main/services/network-forward/frontend-dispatch.js +2 -1
  11. package/dist/main/services/notifications/renderer-notifier.d.ts +2 -0
  12. package/dist/main/services/notifications/renderer-notifier.js +7 -1
  13. package/dist/main/services/simulator-current-page/index.d.ts +5 -3
  14. package/dist/main/services/simulator-current-page/index.js +8 -1
  15. package/dist/main/services/views/clear-console-filter.d.ts +44 -0
  16. package/dist/main/services/views/clear-console-filter.js +86 -0
  17. package/dist/main/services/views/console-filter-test-fixtures.d.ts +94 -0
  18. package/dist/main/services/views/console-filter-test-fixtures.js +82 -0
  19. package/dist/main/services/views/console-filter.d.ts +79 -130
  20. package/dist/main/services/views/console-filter.js +140 -183
  21. package/dist/main/services/views/devtools-tabs.d.ts +24 -4
  22. package/dist/main/services/views/devtools-tabs.js +40 -21
  23. package/dist/main/services/views/host-toolbar-view.js +5 -18
  24. package/dist/main/services/views/native-simulator-devtools-host.js +64 -45
  25. package/dist/main/services/views/native-simulator-view.js +6 -24
  26. package/dist/main/services/views/native-view-tree.d.ts +25 -0
  27. package/dist/main/services/views/native-view-tree.js +69 -0
  28. package/dist/main/services/views/overlay-panels-view.d.ts +27 -4
  29. package/dist/main/services/views/overlay-panels-view.js +138 -109
  30. package/dist/main/services/views/placement-reconciler.d.ts +4 -16
  31. package/dist/main/services/views/placement-reconciler.js +64 -29
  32. package/dist/main/services/views/placement-test-driver.d.ts +26 -0
  33. package/dist/main/services/views/placement-test-driver.js +26 -0
  34. package/dist/main/services/views/view-manager.d.ts +5 -9
  35. package/dist/main/services/views/view-manager.js +7 -1
  36. package/dist/main/services/views/workbench-view.js +27 -20
  37. package/dist/main/services/workbench-coi-server.d.ts +11 -0
  38. package/dist/main/services/workbench-coi-server.js +32 -0
  39. package/dist/main/services/workspace/rebuild-status.d.ts +21 -8
  40. package/dist/main/services/workspace/rebuild-status.js +24 -8
  41. package/dist/main/utils/sender-policy.d.ts +1 -1
  42. package/dist/main/utils/sender-policy.js +6 -1
  43. package/dist/main/utils/theme.d.ts +7 -2
  44. package/dist/main/utils/theme.js +8 -3
  45. package/dist/native-host/container/pageFrame.css +1 -1
  46. package/dist/native-host/render/render.js +1966 -1816
  47. package/dist/native-host/service/service.js +1 -1
  48. package/dist/preload/windows/host-toolbar-runtime.cjs.map +2 -2
  49. package/dist/preload/windows/main.cjs +3176 -14
  50. package/dist/preload/windows/main.cjs.map +4 -4
  51. package/dist/preload/windows/main.css +428 -0
  52. package/dist/preload/windows/main.css.map +7 -0
  53. package/dist/preload/windows/simulator.cjs +5 -2
  54. package/dist/preload/windows/simulator.cjs.map +2 -2
  55. package/dist/preload/windows/simulator.js +5 -2
  56. package/dist/renderer/assets/constants-Bdz0LHdy.js +2 -0
  57. package/dist/renderer/assets/index-CtznrmHR.js +49 -0
  58. package/dist/renderer/assets/{input-xdmfv-eH.js → input-Dmm6nob5.js} +2 -2
  59. package/dist/renderer/assets/ipc-transport-BOg0gR9W.js +9 -0
  60. package/dist/renderer/assets/ipc-transport-DgQhZaE9.css +1 -0
  61. package/dist/renderer/assets/popover-Cd1FEGOX.js +2 -0
  62. package/dist/renderer/assets/select-BaYox7If.js +2 -0
  63. package/dist/renderer/assets/settings-BXvwuFaz.js +2 -0
  64. package/dist/renderer/assets/settings-api-Bo9GbYqs.js +2 -0
  65. package/dist/renderer/assets/settings-tab-bar-Beia6lMr.js +2 -0
  66. package/dist/renderer/assets/tooltip-DfQqK3Sk.js +2 -0
  67. package/dist/renderer/assets/view-api-nn69je7A.js +2 -0
  68. package/dist/renderer/assets/workbenchSettings-oq_EyfKf.js +8 -0
  69. package/dist/renderer/entries/main/index.html +8 -7
  70. package/dist/renderer/entries/popover/index.html +7 -6
  71. package/dist/renderer/entries/settings/index.html +7 -5
  72. package/dist/renderer/entries/tooltip/index.html +20 -0
  73. package/dist/renderer/entries/workbench-settings/index.html +7 -5
  74. package/dist/service-host/sync-impls/menu-button-geometry.js +1 -0
  75. package/dist/shared/ipc-channels.d.ts +11 -0
  76. package/dist/shared/ipc-channels.js +28 -2
  77. package/dist/shared/ipc-schemas.d.ts +19 -0
  78. package/dist/shared/ipc-schemas.js +23 -0
  79. package/dist/shared/simulator-route.d.ts +8 -0
  80. package/dist/shared/simulator-route.js +15 -0
  81. package/dist/shared/types.d.ts +7 -0
  82. package/dist/shared/view-ids.d.ts +2 -0
  83. package/dist/shared/view-ids.js +11 -0
  84. package/dist/simulator/assets/device-shell-CmtM1QxP.js +2 -0
  85. package/dist/simulator/assets/device-shell-iFZo1igL.css +1 -0
  86. package/dist/simulator/assets/{simulator-COIE6R49.js → simulator-CIobn3Mh.js} +6 -6
  87. package/dist/simulator/assets/{simulator-mini-app-BLn7XV8e.js → simulator-mini-app-CRe6n9br.js} +2 -2
  88. package/dist/simulator/assets/simulator-ui-BupATgKo.css +1 -0
  89. package/dist/simulator/assets/simulator-ui-C_cP602X.js +2 -0
  90. package/dist/simulator/simulator.html +3 -2
  91. package/dist/vscode-workbench/assets/__vite-browser-external-Bc1vizTf.js +1 -0
  92. package/dist/vscode-workbench/assets/{dist-oHcwN53f.js → dist-CMfmHflW.js} +3 -3
  93. package/dist/vscode-workbench/assets/{iconv-lite-umd-CLMLpdGm.js → iconv-lite-umd-Bx8CgaZq.js} +1 -1
  94. package/dist/vscode-workbench/assets/{index-BE3UJdoH.js → index-CdG6YWhW.js} +436 -436
  95. package/dist/vscode-workbench/assets/{jschardet-BICW8PLJ.js → jschardet-M0qgd2lN.js} +1 -1
  96. package/dist/vscode-workbench/index.html +21 -1
  97. package/package.json +7 -6
  98. package/dist/main/services/views/destroy-child-view.d.ts +0 -9
  99. package/dist/main/services/views/destroy-child-view.js +0 -23
  100. package/dist/renderer/assets/constants-EAMiwL9_.js +0 -2
  101. package/dist/renderer/assets/index-BBg3YI5b.js +0 -49
  102. package/dist/renderer/assets/ipc-transport-B3EpmfNS.js +0 -9
  103. package/dist/renderer/assets/ipc-transport-Blac3sOj.css +0 -1
  104. package/dist/renderer/assets/popover-B88e2hkg.js +0 -2
  105. package/dist/renderer/assets/select-CD9CJyhI.js +0 -2
  106. package/dist/renderer/assets/settings-44hf0QtO.js +0 -2
  107. package/dist/renderer/assets/settings-api-pJKPuP1M.js +0 -2
  108. package/dist/renderer/assets/workbenchSettings-DKD5U1Ql.js +0 -8
  109. package/dist/simulator/assets/device-shell-Cw7c-IkG.js +0 -2
  110. package/dist/simulator/assets/device-shell-DbC5ccs8.css +0 -1
  111. package/dist/simulator/assets/jsx-runtime-DkKmJyBb.js +0 -2
  112. package/dist/simulator/device-shell/menu-button-geometry.js +0 -18
  113. package/dist/vscode-workbench/assets/__vite-browser-external-BON7qP59.js +0 -1
@@ -368,8 +368,11 @@ var SimulatorChannel = {
368
368
  Detach: "simulator:detach",
369
369
  Console: "simulator:console",
370
370
  // Main → renderer push of the visible top-of-stack page route whenever the
371
- // mini-app navigates (navigateTo / switchTab / back). Payload: the page path
372
- // string (same bare format as `getCurrentPagePath`), or '' when unknown.
371
+ // mini-app navigates (navigateTo / switchTab / back). Payload: the page
372
+ // route string (`pagePath` + `?k=v&…` query, same format as
373
+ // `encodePageSpec`/`decodePageSpec`), or '' when unknown. The query lets the
374
+ // page-path bar show params (WeChat DevTools parity) and a recompile restore
375
+ // the current page's params.
373
376
  CurrentPage: "simulator:current-page"
374
377
  };
375
378
  var ServiceHostChannel = {
@@ -439,6 +442,10 @@ var WorkbenchSettingsChannel = {
439
442
  var ProjectChannel = {
440
443
  Open: "project:open",
441
444
  Close: "project:close",
445
+ // Renderer → main invoke: run one real recompile of the active session
446
+ // (the popover 重新编译 button). Resolves `{ supported: boolean }`; rejects
447
+ // on build failure or when no session is active.
448
+ Rebuild: "project:rebuild",
442
449
  GetPages: "project:getPages",
443
450
  GetCompileConfig: "project:getCompileConfig",
444
451
  SaveCompileConfig: "project:saveCompileConfig",
@@ -535,6 +542,16 @@ var PopoverChannel = {
535
542
  Closed: "popover:closed",
536
543
  Init: "popover:init"
537
544
  };
545
+ var OverlayChannel = {
546
+ Ready: "overlay:ready"
547
+ };
548
+ var TooltipChannel = {
549
+ Prepare: "tooltip:prepare",
550
+ Show: "tooltip:show",
551
+ Hide: "tooltip:hide",
552
+ Init: "tooltip:init",
553
+ Measured: "tooltip:measured"
554
+ };
538
555
  var WindowChannel = {
539
556
  NavigateBack: "window:navigateBack",
540
557
  OpenProject: "window:openProject",
@@ -906,7 +923,7 @@ function registerProjectFsIpc(ctx) {
906
923
  // src/main/app/app.ts
907
924
  import { app as app13, BrowserWindow as BrowserWindow6, nativeImage, session as session2 } from "electron";
908
925
  import fs10 from "fs";
909
- import path20 from "path";
926
+ import path19 from "path";
910
927
 
911
928
  // src/main/utils/paths.ts
912
929
  import fs3 from "fs";
@@ -958,7 +975,7 @@ function themeBg() {
958
975
  return nativeTheme2.shouldUseDarkColors ? "#1a1a1a" : "#fafafa";
959
976
  }
960
977
  function simDeskBg() {
961
- return nativeTheme2.shouldUseDarkColors ? "#121212" : "#e8e8e8";
978
+ return nativeTheme2.shouldUseDarkColors ? "#282828" : "#f7f7f9";
962
979
  }
963
980
  function installThemeBackgroundSync() {
964
981
  const apply = () => {
@@ -1576,6 +1593,8 @@ function createWorkbenchSenderPolicy(ctx) {
1576
1593
  if (settingsViewId != null && sender.id === settingsViewId) return true;
1577
1594
  const popoverViewId = ctx.views.getPopoverWebContentsId();
1578
1595
  if (popoverViewId != null && sender.id === popoverViewId) return true;
1596
+ const tooltipViewId = ctx.views.getTooltipWebContentsId();
1597
+ if (tooltipViewId != null && sender.id === tooltipViewId) return true;
1579
1598
  return false;
1580
1599
  };
1581
1600
  }
@@ -1641,6 +1660,11 @@ function createRendererNotifier(ctx) {
1641
1660
  if (!wc) return;
1642
1661
  wc.send(PopoverChannel.Init, payload);
1643
1662
  },
1663
+ tooltipInit(tooltipView, payload) {
1664
+ const wc = liveWebContents(tooltipView.webContents);
1665
+ if (!wc) return;
1666
+ wc.send(TooltipChannel.Init, payload);
1667
+ },
1644
1668
  settingsInit(payload) {
1645
1669
  const wc = liveWebContents(ctx.views.getSettingsWebContents());
1646
1670
  if (!wc) return;
@@ -1842,14 +1866,78 @@ function applyViewOps(ops, target) {
1842
1866
  }
1843
1867
  }
1844
1868
 
1869
+ // src/main/services/views/native-view-tree.ts
1870
+ function createNativeViewTreeHost(ctx, slots) {
1871
+ const order = [];
1872
+ const mounted = /* @__PURE__ */ new Map();
1873
+ function resolve(id) {
1874
+ return slots.get(id)?.getView() ?? null;
1875
+ }
1876
+ return {
1877
+ addChildView(ref) {
1878
+ const view = resolve(ref.id);
1879
+ if (!view || view.webContents.isDestroyed() || ctx.windows.mainWindow.isDestroyed()) return false;
1880
+ try {
1881
+ ctx.windows.mainWindow.contentView.addChildView(view);
1882
+ } catch {
1883
+ return false;
1884
+ }
1885
+ const i = order.indexOf(ref.id);
1886
+ if (i >= 0) order.splice(i, 1);
1887
+ order.push(ref.id);
1888
+ mounted.set(ref.id, view);
1889
+ return true;
1890
+ },
1891
+ removeChildView(ref) {
1892
+ const view = mounted.get(ref.id) ?? null;
1893
+ if (!view || ctx.windows.mainWindow.isDestroyed()) return false;
1894
+ try {
1895
+ ctx.windows.mainWindow.contentView.removeChildView(view);
1896
+ } catch {
1897
+ return false;
1898
+ }
1899
+ const i = order.indexOf(ref.id);
1900
+ if (i >= 0) order.splice(i, 1);
1901
+ mounted.delete(ref.id);
1902
+ return true;
1903
+ },
1904
+ get isDestroyed() {
1905
+ return ctx.windows.mainWindow.isDestroyed();
1906
+ },
1907
+ children: () => order.map((id) => ({ id })),
1908
+ destroyView(viewId, view) {
1909
+ const isMountedInstance = view !== null && mounted.get(viewId) === view;
1910
+ if (view && !ctx.windows.mainWindow.isDestroyed()) {
1911
+ try {
1912
+ ctx.windows.mainWindow.contentView.removeChildView(view);
1913
+ } catch {
1914
+ }
1915
+ }
1916
+ if (isMountedInstance) {
1917
+ const i = order.indexOf(viewId);
1918
+ if (i >= 0) order.splice(i, 1);
1919
+ mounted.delete(viewId);
1920
+ }
1921
+ if (view) {
1922
+ try {
1923
+ if (!view.webContents.isDestroyed()) view.webContents.close();
1924
+ } catch {
1925
+ }
1926
+ }
1927
+ }
1928
+ };
1929
+ }
1930
+
1845
1931
  // src/main/services/views/placement-reconciler.ts
1846
1932
  function createPlacementReconciler(ctx) {
1847
1933
  let placementState = createInitialState();
1848
1934
  let epochCounter = 0;
1849
1935
  let rendererGeneration = 0;
1936
+ const appliedActual = /* @__PURE__ */ new Map();
1850
1937
  const baseDesired = /* @__PURE__ */ new Map();
1851
1938
  const overlayDesired = /* @__PURE__ */ new Map();
1852
1939
  const slots = /* @__PURE__ */ new Map();
1940
+ const contentViewHost = createNativeViewTreeHost(ctx, slots);
1853
1941
  function gateReadiness(v) {
1854
1942
  const slot = slots.get(v.viewId);
1855
1943
  if (slot?.gateHidden?.()) return { ...v, placement: { visible: false } };
@@ -1860,53 +1948,54 @@ function createPlacementReconciler(ctx) {
1860
1948
  if (ctx.windows.mainWindow.isDestroyed()) return;
1861
1949
  const slot = slots.get(viewId);
1862
1950
  if (!slot) return;
1863
- if (slot.beforeAttach?.()) return;
1864
1951
  const view = slot.ensureView ? slot.ensureView() : slot.getView();
1865
1952
  if (!view) return;
1866
- ctx.windows.mainWindow.contentView.addChildView(view);
1867
- slot.setAdded?.(true);
1953
+ if (!contentViewHost.addChildView({ id: viewId })) return;
1954
+ const previous = appliedActual.get(viewId);
1955
+ appliedActual.set(viewId, {
1956
+ attached: true,
1957
+ visible: true,
1958
+ bounds: previous?.bounds,
1959
+ extra: previous?.extra
1960
+ });
1868
1961
  },
1869
1962
  detach(viewId) {
1870
- const slot = slots.get(viewId);
1871
- const view = slot?.getView() ?? null;
1872
- if (view && !ctx.windows.mainWindow.isDestroyed()) {
1873
- try {
1874
- ctx.windows.mainWindow.contentView.removeChildView(view);
1875
- } catch {
1876
- }
1877
- }
1878
- slot?.setAdded?.(false);
1963
+ if (!contentViewHost.removeChildView({ id: viewId })) return;
1964
+ appliedActual.delete(viewId);
1879
1965
  },
1880
1966
  setBounds(viewId, bounds, extra) {
1881
1967
  const slot = slots.get(viewId);
1882
1968
  const view = slot?.getView() ?? null;
1883
1969
  if (!view || view.webContents.isDestroyed()) return;
1884
- if (slot?.applyBounds) {
1885
- slot.applyBounds(view, bounds, extra);
1970
+ try {
1971
+ if (slot?.applyBounds) slot.applyBounds(view, bounds, extra);
1972
+ else view.setBounds(bounds);
1973
+ } catch {
1886
1974
  return;
1887
1975
  }
1888
- view.setBounds(bounds);
1976
+ const previous = appliedActual.get(viewId);
1977
+ appliedActual.set(viewId, {
1978
+ attached: previous?.attached ?? false,
1979
+ visible: previous?.visible ?? false,
1980
+ bounds,
1981
+ extra
1982
+ });
1889
1983
  },
1890
1984
  setVisible(viewId, visible) {
1891
1985
  const view = slots.get(viewId)?.getView() ?? null;
1892
- if (!view) return;
1986
+ if (!view || view.webContents.isDestroyed()) return;
1893
1987
  try {
1894
1988
  view.setVisible(visible);
1895
1989
  } catch {
1990
+ return;
1896
1991
  }
1992
+ const previous = appliedActual.get(viewId);
1993
+ if (!previous) return;
1994
+ appliedActual.set(viewId, { ...previous, visible });
1897
1995
  },
1898
1996
  reorder(order) {
1899
1997
  if (order.length <= 1 || ctx.windows.mainWindow.isDestroyed()) return;
1900
- const cv = ctx.windows.mainWindow.contentView;
1901
- for (const viewId of order) {
1902
- const view = slots.get(viewId)?.getView() ?? null;
1903
- if (view) {
1904
- try {
1905
- cv.addChildView(view);
1906
- } catch {
1907
- }
1908
- }
1909
- }
1998
+ for (const viewId of order) contentViewHost.addChildView({ id: viewId });
1910
1999
  }
1911
2000
  };
1912
2001
  function ensureLazyViews() {
@@ -1914,11 +2003,15 @@ function createPlacementReconciler(ctx) {
1914
2003
  slot.ensureLazy?.(baseDesired.get(viewId));
1915
2004
  }
1916
2005
  }
2006
+ function cloneAppliedActual() {
2007
+ return new Map([...appliedActual].map(([viewId, actual]) => [viewId, { ...actual }]));
2008
+ }
1917
2009
  function reconcileNow() {
1918
2010
  ensureLazyViews();
1919
2011
  const views = [];
1920
2012
  for (const v of baseDesired.values()) views.push(gateReadiness(v));
1921
2013
  for (const v of overlayDesired.values()) views.push(v);
2014
+ placementState = { ...placementState, actual: cloneAppliedActual() };
1922
2015
  const result = reconcile(placementState, {
1923
2016
  generation: rendererGeneration,
1924
2017
  epoch: ++epochCounter,
@@ -1926,6 +2019,7 @@ function createPlacementReconciler(ctx) {
1926
2019
  });
1927
2020
  placementState = result.state;
1928
2021
  applyViewOps(result.ops, viewTarget);
2022
+ placementState = { ...placementState, actual: cloneAppliedActual() };
1929
2023
  }
1930
2024
  function setPlacementSnapshot(snapshot) {
1931
2025
  rendererGeneration = snapshot.generation;
@@ -1939,7 +2033,18 @@ function createPlacementReconciler(ctx) {
1939
2033
  },
1940
2034
  reconcileNow,
1941
2035
  setPlacementSnapshot,
1942
- forgetActual: (viewId) => {
2036
+ prepareView: (viewId, view, bounds) => {
2037
+ if (slots.get(viewId)?.getView() !== view || view.webContents.isDestroyed()) return;
2038
+ try {
2039
+ view.setBounds(bounds);
2040
+ } catch {
2041
+ return;
2042
+ }
2043
+ appliedActual.set(viewId, { attached: false, visible: false, bounds });
2044
+ },
2045
+ destroyView: (viewId, view) => {
2046
+ contentViewHost.destroyView(viewId, view);
2047
+ appliedActual.delete(viewId);
1943
2048
  placementState.actual.delete(viewId);
1944
2049
  },
1945
2050
  setBaseDesired: (viewId, desired) => {
@@ -1968,32 +2073,17 @@ var VIEW_ID = {
1968
2073
  workbench: "workbench",
1969
2074
  hostToolbar: "host-toolbar",
1970
2075
  settings: "settings",
1971
- popover: "popover"
2076
+ popover: "popover",
2077
+ tooltip: "tooltip"
1972
2078
  };
1973
2079
  var VIEW_LAYER = {
1974
2080
  base: 0,
1975
2081
  hostToolbar: 5,
1976
2082
  settings: 10,
1977
- popover: 20
2083
+ popover: 20,
2084
+ tooltip: 30
1978
2085
  };
1979
2086
 
1980
- // src/main/services/views/destroy-child-view.ts
1981
- function destroyChildView(mainWindow, view) {
1982
- if (!view) return;
1983
- if (!mainWindow.isDestroyed()) {
1984
- try {
1985
- mainWindow.contentView.removeChildView(view);
1986
- } catch {
1987
- }
1988
- }
1989
- try {
1990
- if (!view.webContents.isDestroyed()) {
1991
- view.webContents.close();
1992
- }
1993
- } catch {
1994
- }
1995
- }
1996
-
1997
2087
  // src/main/services/views/workbench-view.ts
1998
2088
  var ATTACH_HOLD_CAP_MS = 3e3;
1999
2089
  function createWorkbenchView(ctx, reconciler) {
@@ -2009,6 +2099,10 @@ function createWorkbenchView(ctx, reconciler) {
2009
2099
  function pushWorkbenchTheme() {
2010
2100
  if (!workbenchView || workbenchView.webContents.isDestroyed()) return;
2011
2101
  const wc = workbenchView.webContents;
2102
+ try {
2103
+ if (typeof workbenchView.setBackgroundColor === "function") workbenchView.setBackgroundColor(themeBg());
2104
+ } catch {
2105
+ }
2012
2106
  if (typeof wc.executeJavaScript !== "function") return;
2013
2107
  const script = `window.__WB_SET_THEME && window.__WB_SET_THEME(${JSON.stringify(workbenchThemeScheme())})`;
2014
2108
  wc.executeJavaScript(script, true).catch(() => {
@@ -2024,6 +2118,10 @@ function createWorkbenchView(ctx, reconciler) {
2024
2118
  }
2025
2119
  });
2026
2120
  workbenchView = view;
2121
+ try {
2122
+ view.setBackgroundColor(themeBg());
2123
+ } catch {
2124
+ }
2027
2125
  if (!workbenchThemeSyncBound) {
2028
2126
  nativeTheme3.on("updated", pushWorkbenchTheme);
2029
2127
  workbenchThemeSyncBound = true;
@@ -2032,7 +2130,6 @@ function createWorkbenchView(ctx, reconciler) {
2032
2130
  view.webContents.setWindowOpenHandler(({ url: target }) => handleWindowOpenExternal(target));
2033
2131
  } catch {
2034
2132
  }
2035
- ctx.windows.mainWindow.contentView.addChildView(view);
2036
2133
  const loadUrl = `${url}index.html?theme=${workbenchThemeScheme()}`;
2037
2134
  await view.webContents.loadURL(loadUrl).catch((err2) => {
2038
2135
  console.error("[workbench] attachWorkbench \u2014 loadURL failed", err2);
@@ -2076,11 +2173,9 @@ function createWorkbenchView(ctx, reconciler) {
2076
2173
  nativeTheme3.removeListener("updated", pushWorkbenchTheme);
2077
2174
  workbenchThemeSyncBound = false;
2078
2175
  }
2079
- destroyChildView(ctx.windows.mainWindow, workbenchView);
2176
+ reconciler.destroyView(VIEW_ID.workbench, workbenchView);
2080
2177
  workbenchView = null;
2081
- if (attachHeld) {
2082
- reconciler.forgetActual(VIEW_ID.workbench);
2083
- } else {
2178
+ if (!attachHeld) {
2084
2179
  reconciler.deleteBaseDesired(VIEW_ID.workbench);
2085
2180
  }
2086
2181
  reconciler.reconcileNow();
@@ -2125,13 +2220,6 @@ function createWorkbenchView(ctx, reconciler) {
2125
2220
  reconciler.registerView(VIEW_ID.workbench, {
2126
2221
  getView: () => workbenchView,
2127
2222
  gateHidden: () => !workbenchView && (!workbenchUrl || attachHeld),
2128
- beforeAttach: () => {
2129
- if (!workbenchView && workbenchUrl && !attachHeld) {
2130
- void attachWorkbench(workbenchUrl);
2131
- return true;
2132
- }
2133
- return false;
2134
- },
2135
2223
  ensureLazy: (desired) => {
2136
2224
  if (desired?.placement.visible && !workbenchView && workbenchUrl && !attachHeld) void attachWorkbench(workbenchUrl);
2137
2225
  }
@@ -2535,25 +2623,20 @@ function buildDevtoolsProjectSourceLinksScript(context) {
2535
2623
  }
2536
2624
 
2537
2625
  // src/main/services/views/devtools-tabs.ts
2538
- var DEVTOOLS_KEPT_VIEW_IDS = ["elements", "console", "network", "sources"];
2626
+ var DEVTOOLS_KEPT_VIEW_IDS = ["elements", "console", "sources", "network"];
2539
2627
  function buildCustomizeTabsScript(keptIds = DEVTOOLS_KEPT_VIEW_IDS) {
2540
2628
  const NAME_MAP = {
2541
2629
  elements: ["Elements", "\u5143\u7D20"],
2542
2630
  console: ["Console", "\u63A7\u5236\u53F0"],
2543
- network: ["Network", "\u7F51\u7EDC"],
2544
- sources: ["Sources", "\u6765\u6E90", "\u6E90\u4EE3\u7801"]
2631
+ sources: ["Sources", "\u6765\u6E90", "\u6E90\u4EE3\u7801"],
2632
+ network: ["Network", "\u7F51\u7EDC"]
2545
2633
  };
2546
2634
  const keepNames = keptIds.flatMap((id) => NAME_MAP[id] ?? [id]);
2547
2635
  const keepIdsJson = JSON.stringify(JSON.stringify([...keptIds]));
2548
2636
  const keepNamesJson = JSON.stringify(JSON.stringify(keepNames));
2549
- const srcNamesJson = JSON.stringify(JSON.stringify(NAME_MAP.sources));
2550
- const netNamesJson = JSON.stringify(JSON.stringify(NAME_MAP.network));
2551
2637
  return `(function(){try{
2552
2638
  var KEEPID = new Set(JSON.parse(${keepIdsJson}));
2553
2639
  var KEEPNAME = new Set(JSON.parse(${keepNamesJson}));
2554
- var SRCNAME = new Set(JSON.parse(${srcNamesJson}));
2555
- var NETNAME = new Set(JSON.parse(${netNamesJson}));
2556
- var WANT_SOURCES_LAST = KEEPID.has('sources');
2557
2640
  // (1) Locale infobar \u2014 official host-preference suppression (NOT localStorage).
2558
2641
  try { var IFH=globalThis.InspectorFrontendHost; if(IFH&&typeof IFH.setPreference==='function'){ IFH.setPreference('disable-locale-info-bar','true'); } }catch(_){}
2559
2642
  function deepCollect(sel,cap){ var out=[],seen=0,stack=[document]; while(stack.length&&seen<(cap||40000)){ var root=stack.pop(); try{var m=root.querySelectorAll?root.querySelectorAll(sel):[];for(var i=0;i<m.length;i++)out.push(m[i]);}catch(_){} try{var all=root.querySelectorAll?root.querySelectorAll('*'):[];for(var j=0;j<all.length;j++){seen++;if(all[j].shadowRoot)stack.push(all[j].shadowRoot);}}catch(_){} } return out; }
@@ -2584,15 +2667,6 @@ function buildCustomizeTabsScript(keptIds = DEVTOOLS_KEPT_VIEW_IDS) {
2584
2667
  if(!handled){ var FALL=['timeline','resources','heap-profiler','security','lighthouse','chrome-recorder','coverage','linear-memory-inspector','sensors','rendering','animations','autofill-view','medias','issues-pane']; for(var fr=0;fr<FALL.length;fr++){ try{ if(!KEEPID.has(FALL[fr])) maybeRemove(FALL[fr]); }catch(_){} } }
2585
2668
  } else { domFallback(); }
2586
2669
  })();
2587
- // Keep Sources LAST in the bar (after Network). Default DevTools order puts
2588
- // Sources between Console and Network; nudge it to just after Network. Runs in
2589
- // BOTH paths (registry removal leaves the kept tabs in default order). Self-
2590
- // stable: once Sources follows Network the condition no longer holds.
2591
- if(WANT_SOURCES_LAST){ var ro=0,rt=setInterval(function(){ ro++; try{
2592
- var tabs=deepCollect('[role="tab"]'),src=null,net=null;
2593
- for(var i=0;i<tabs.length;i++){ var n=txt(tabs[i]); if(SRCNAME.has(n))src=tabs[i]; else if(NETNAME.has(n))net=tabs[i]; }
2594
- if(src&&net&&src.parentElement&&src.parentElement===net.parentElement&&(src.compareDocumentPosition(net)&Node.DOCUMENT_POSITION_FOLLOWING)){ net.parentElement.insertBefore(src,net.nextSibling); }
2595
- }catch(_){} if(ro>120)clearInterval(rt); },60); }
2596
2670
  // DOM fallback: only if the ESM module couldn't be resolved at all.
2597
2671
  function domFallback(){ var cachedBar=null;
2598
2672
  function findBar(){ if(cachedBar&&cachedBar.isConnected)return cachedBar; cachedBar=null; var tabs=deepCollect('[role="tab"]'); var a=null; for(var i=0;i<tabs.length;i++){if(KEEPNAME.has(txt(tabs[i]))){a=tabs[i];break;}} if(!a)return null; var p=a.parentElement; while(p){try{if(p.querySelectorAll('[role="tab"]').length>1){cachedBar=p;return p;}}catch(_){} p=p.parentElement;} cachedBar=a.parentElement; return cachedBar; }
@@ -2600,41 +2674,34 @@ function buildCustomizeTabsScript(keptIds = DEVTOOLS_KEPT_VIEW_IDS) {
2600
2674
  var tr=0,t=setInterval(function(){tr++;try{apply();}catch(_){}if(tr>120)clearInterval(t);},60); try{apply();}catch(_){} }
2601
2675
  }catch(_){}})()`;
2602
2676
  }
2677
+ function buildDevtoolsSoftMenuScript() {
2678
+ return `(function(){
2679
+ try {
2680
+ var C = globalThis.EUI && globalThis.EUI.ContextMenu && globalThis.EUI.ContextMenu.ContextMenu;
2681
+ if (C && C.prototype && typeof C.prototype.show === 'function') {
2682
+ var origShow = C.prototype.show;
2683
+ C.prototype.show = function() {
2684
+ this.useSoftMenu = true;
2685
+ return origShow.apply(this, arguments);
2686
+ };
2687
+ }
2688
+ } catch (_) {}
2689
+ })()`;
2690
+ }
2603
2691
 
2604
2692
  // src/main/services/views/console-filter.ts
2605
- var DEFAULT_INTERNAL_LOG_FILTER = "-/^\\[service\\]/";
2606
- function buildConsoleFilterScript(negativeFilter = DEFAULT_INTERNAL_LOG_FILTER) {
2607
- const keyJson = JSON.stringify("console.text-filter");
2608
- const markKeyJson = JSON.stringify("console.text-filter.dimina-default");
2609
- const valueJsonLiteral = JSON.stringify(JSON.stringify(negativeFilter));
2610
- return `(function(){try{
2611
- var IFH = globalThis.InspectorFrontendHost;
2612
- if (!IFH || typeof IFH.getPreferences !== 'function' || typeof IFH.setPreference !== 'function') return;
2613
- IFH.getPreferences(function(prefs){
2614
- try {
2615
- var KEY = ${keyJson};
2616
- var MARK_KEY = ${markKeyJson};
2617
- var VALUE = ${valueJsonLiteral};
2618
- var existing = prefs ? prefs[KEY] : undefined;
2619
- var mark = prefs ? prefs[MARK_KEY] : undefined;
2620
- var isUnset = existing === undefined || existing === null || existing === '' || existing === '""';
2621
- var isOurStaleDefault = !isUnset && mark !== undefined && mark !== null && existing === mark;
2622
- if (isUnset || isOurStaleDefault) {
2623
- IFH.setPreference(KEY, VALUE);
2624
- IFH.setPreference(MARK_KEY, VALUE);
2625
- }
2626
- } catch(_){}
2627
- });
2628
- }catch(_){}})()`;
2629
- }
2693
+ var INTERNAL_LOG_HIDDEN_PREFIX = "[service]";
2694
+ var INTERNAL_LOG_WRAPPER_MARK = "__diminaInternalLogHidden";
2630
2695
  var LIVE_FILTER_POLL_MAX_ATTEMPTS = 100;
2631
2696
  var LIVE_FILTER_POLL_INTERVAL_MS = 100;
2632
- function buildLiveConsoleFilterScript(negativeFilter = DEFAULT_INTERNAL_LOG_FILTER) {
2633
- const filterJson = JSON.stringify(negativeFilter);
2697
+ function buildInternalLogHideScript(hiddenPrefix = INTERNAL_LOG_HIDDEN_PREFIX) {
2698
+ const prefixJson = JSON.stringify(hiddenPrefix);
2699
+ const markJson = JSON.stringify(INTERNAL_LOG_WRAPPER_MARK);
2634
2700
  const maxAttempts = JSON.stringify(LIVE_FILTER_POLL_MAX_ATTEMPTS);
2635
2701
  const intervalMs = JSON.stringify(LIVE_FILTER_POLL_INTERVAL_MS);
2636
2702
  return `(function(){
2637
- var VALUE = ${filterJson};
2703
+ var PREFIX = ${prefixJson};
2704
+ var MARK = ${markJson};
2638
2705
  var attempts = 0;
2639
2706
  function bootstrapReady() {
2640
2707
  try {
@@ -2644,45 +2711,124 @@ function buildLiveConsoleFilterScript(negativeFilter = DEFAULT_INTERNAL_LOG_FILT
2644
2711
  return true;
2645
2712
  } catch (_) { return false; }
2646
2713
  }
2714
+ function isInternalLog(viewMessage) {
2715
+ try {
2716
+ var msg = viewMessage && typeof viewMessage.consoleMessage === 'function' ? viewMessage.consoleMessage() : null;
2717
+ var text = msg ? String(msg.messageText == null ? '' : msg.messageText) : '';
2718
+ // Exact tag (the rest of the line is in later arguments), or the tag
2719
+ // followed by a space \u2014 same shape as main's isInternalLogMessage. A
2720
+ // bare prefix test would also swallow '[service]\u4E1A\u52A1\u72B6\u6001', an ordinary
2721
+ // business log the panel must keep showing.
2722
+ return text === PREFIX || text.indexOf(PREFIX + ' ') === 0;
2723
+ } catch (_) { return false; }
2724
+ }
2647
2725
  function tryApply() {
2648
2726
  attempts++;
2649
2727
  var scheduleRetry = attempts < ${maxAttempts};
2728
+ // Distinguishes the two halves of this script when the tail throws:
2729
+ // future messages are already handled once the wrapper is on the
2730
+ // prototype, even if re-judging the rows already on screen keeps failing.
2731
+ var wrapperInstalled = false;
2650
2732
  // In-realm bootstrap probe FIRST (defense in depth on top of the
2651
2733
  // main-process whenFrontendBootstrapped gate): touching
2652
- // Console.ConsoleView.instance() before the front-end's own
2653
- // MainImpl bootstrap completes constructs IssuesManager early and
2654
- // permanently kills that bootstrap (ensureFirst conflict) \u2014 the probe
2655
- // throws BEFORE constructing anything, so a not-ready tick costs
2656
- // nothing and never touches ConsoleView.
2734
+ // Console.ConsoleView.instance() before the front-end's own MainImpl
2735
+ // bootstrap completes constructs IssuesManager early and permanently
2736
+ // kills that bootstrap (ensureFirst conflict) \u2014 the probe throws BEFORE
2737
+ // constructing anything, so a not-ready tick costs nothing.
2657
2738
  if (!bootstrapReady()) {
2658
2739
  if (scheduleRetry) { setTimeout(tryApply, ${intervalMs}); return; }
2659
- console.warn('[console-filter] gave up applying the live Console filter after ' + attempts + ' attempts \u2014 the front-end bootstrap never completed');
2740
+ console.warn('[console-filter] gave up hiding internal logs after ' + attempts + ' attempts \u2014 the front-end bootstrap never completed');
2660
2741
  return;
2661
2742
  }
2662
2743
  try {
2663
2744
  var ConsoleNS = globalThis.Console;
2664
2745
  var view = ConsoleNS && ConsoleNS.ConsoleView ? ConsoleNS.ConsoleView.instance() : null;
2665
2746
  var f = view ? view.filter : null;
2666
- if (!f || !f.textFilterUI || typeof f.textFilterUI.setValue !== 'function' || typeof f.textFilterUI.value !== 'function') {
2747
+ var currentFilter = f ? f.currentFilter : null;
2748
+ if (!currentFilter) {
2667
2749
  if (scheduleRetry) { setTimeout(tryApply, ${intervalMs}); return; }
2668
- console.warn('[console-filter] gave up applying the live Console filter after ' + attempts + ' attempts \u2014 Console.ConsoleView never became usable');
2750
+ console.warn('[console-filter] gave up hiding internal logs after ' + attempts + ' attempts \u2014 Console.ConsoleView never became usable');
2751
+ return;
2752
+ }
2753
+ // The prototype, NOT the instance: clone() mints further ConsoleFilters
2754
+ // that judge the same messages, and they all share this one.
2755
+ var proto = Object.getPrototypeOf(currentFilter);
2756
+ if (!proto || typeof proto.shouldBeVisible !== 'function') {
2757
+ console.warn('[console-filter] cannot hide internal logs \u2014 ConsoleFilter has no shouldBeVisible to wrap; framework log lines will show in the right panel');
2758
+ return;
2759
+ }
2760
+ if (!proto[MARK]) {
2761
+ var original = proto.shouldBeVisible;
2762
+ proto.shouldBeVisible = function(viewMessage) {
2763
+ if (isInternalLog(viewMessage)) return false;
2764
+ return original.apply(this, arguments);
2765
+ };
2766
+ proto[MARK] = true;
2767
+ }
2768
+ wrapperInstalled = true;
2769
+ // Re-run the panel's visibility pass so lines already on screen when
2770
+ // the wrapper lands are re-judged, not just future ones.
2771
+ if (view && typeof view.onFilterChanged === 'function') view.onFilterChanged();
2772
+ } catch(err) {
2773
+ if (scheduleRetry) { setTimeout(tryApply, ${intervalMs}); return; }
2774
+ // Name which half survived: a wrapper that installed but could never
2775
+ // refresh still hides everything logged from now on, and the panel is
2776
+ // left holding the internal lines printed before it landed. Reporting
2777
+ // that as plain "gave up" would send the next reader looking for a
2778
+ // filter that is in fact working.
2779
+ if (wrapperInstalled) {
2780
+ console.warn('[console-filter] internal logs are hidden from here on, but the rows already on screen could not be re-judged:', err);
2781
+ } else {
2782
+ console.warn('[console-filter] gave up hiding internal logs after ' + attempts + ' attempts:', err);
2783
+ }
2784
+ }
2785
+ }
2786
+ tryApply();
2787
+ })()`;
2788
+ }
2789
+
2790
+ // src/main/services/views/clear-console-filter.ts
2791
+ function buildClearConsoleFilterScript() {
2792
+ return `(function(){
2793
+ var attempts = 0;
2794
+ var MAX = 100;
2795
+ function bootstrapReady() {
2796
+ try {
2797
+ var eui = globalThis.EUI;
2798
+ if (!eui || !eui.ShortcutRegistry || !eui.ShortcutRegistry.ShortcutRegistry) return false;
2799
+ eui.ShortcutRegistry.ShortcutRegistry.instance();
2800
+ return true;
2801
+ } catch (_) { return false; }
2802
+ }
2803
+ function tryClear() {
2804
+ attempts++;
2805
+ var scheduleRetry = attempts < MAX;
2806
+ if (!bootstrapReady()) {
2807
+ if (scheduleRetry) { setTimeout(tryClear, 100); return; }
2808
+ return;
2809
+ }
2810
+ try {
2811
+ try { localStorage.removeItem('console.textFilter'); } catch(_) {}
2812
+ try { localStorage.removeItem('console.text-filter'); } catch(_) {}
2813
+ var ConsoleNS = globalThis.Console;
2814
+ var view = ConsoleNS && ConsoleNS.ConsoleView ? ConsoleNS.ConsoleView.instance() : null;
2815
+ var f = view ? view.filter : null;
2816
+ var box = f && f.textFilterUI;
2817
+ if (!box || typeof box.setValue !== 'function' || typeof box.value !== 'function') {
2818
+ if (scheduleRetry) { setTimeout(tryClear, 100); return; }
2669
2819
  return;
2670
2820
  }
2671
- var current = f.textFilterUI.value();
2672
- var isUnset = current === undefined || current === null || current === '';
2673
- var isOurDefault = current === VALUE;
2674
- if (isUnset || isOurDefault) {
2675
- f.textFilterUI.setValue(VALUE);
2821
+ var current = box.value();
2822
+ if (current) {
2823
+ box.setValue('');
2676
2824
  if (typeof f.updateCurrentFilter === 'function') f.updateCurrentFilter();
2677
2825
  if (typeof f.onFilterChanged === 'function') f.onFilterChanged();
2678
2826
  }
2679
- // Either applied, or a real user customization was detected \u2014 both
2680
- // are terminal: nothing left for a later retry to accomplish.
2681
2827
  } catch(_) {
2682
- if (scheduleRetry) setTimeout(tryApply, ${intervalMs});
2828
+ if (scheduleRetry) setTimeout(tryClear, 100);
2683
2829
  }
2684
2830
  }
2685
- tryApply();
2831
+ tryClear();
2686
2832
  })()`;
2687
2833
  }
2688
2834
 
@@ -2948,7 +3094,8 @@ function createFrontendReplyChannel(hostWc, isDisposed) {
2948
3094
  }
2949
3095
  function drainOutboundBatch(batch, handle) {
2950
3096
  if (!Array.isArray(batch)) return;
2951
- for (const raw of batch) {
3097
+ const entries = batch;
3098
+ for (const raw of entries) {
2952
3099
  if (!raw || typeof raw !== "object") continue;
2953
3100
  const cmd = raw;
2954
3101
  if (typeof cmd.method !== "string") continue;
@@ -4396,7 +4543,6 @@ function raiseExecuteJavaScriptListenerCeiling(wc) {
4396
4543
  }
4397
4544
  function createDevtoolsHost(ctx, reconciler, deps) {
4398
4545
  let simulatorView = null;
4399
- let simulatorViewAdded = false;
4400
4546
  let nativeDevtoolsSourceWc = null;
4401
4547
  let devtoolsHostUsed = false;
4402
4548
  let unsubscribeNativeRenderEvents = null;
@@ -4405,6 +4551,7 @@ function createDevtoolsHost(ctx, reconciler, deps) {
4405
4551
  let stopServiceConsole = null;
4406
4552
  let nativeDevtoolsRetryTimer = null;
4407
4553
  let nativeDevtoolsRetryToken = 0;
4554
+ let clearFilterOnNextHostBuild = false;
4408
4555
  const injectWhenReady = createLoadDeferredInjector();
4409
4556
  const openInEditorWiredWcIds = /* @__PURE__ */ new Set();
4410
4557
  function clearNativeDevtoolsRetry() {
@@ -4483,9 +4630,7 @@ function createDevtoolsHost(ctx, reconciler, deps) {
4483
4630
  void whenFrontendBootstrapped(devtoolsWc).then((ready) => {
4484
4631
  if (!ready || devtoolsWc.isDestroyed()) return;
4485
4632
  try {
4486
- void devtoolsWc.executeJavaScript(buildConsoleFilterScript()).catch(() => {
4487
- });
4488
- void devtoolsWc.executeJavaScript(buildLiveConsoleFilterScript()).catch(() => {
4633
+ void devtoolsWc.executeJavaScript(buildInternalLogHideScript()).catch(() => {
4489
4634
  });
4490
4635
  } catch {
4491
4636
  }
@@ -4525,6 +4670,7 @@ function createDevtoolsHost(ctx, reconciler, deps) {
4525
4670
  }
4526
4671
  function pointNativeDevtoolsAtServiceWc(next) {
4527
4672
  if (!simulatorView || simulatorView.webContents.isDestroyed()) return true;
4673
+ clearFilterOnNextHostBuild = false;
4528
4674
  if (nativeDevtoolsSourceWc?.id === next.id && !nativeDevtoolsSourceWc.isDestroyed()) {
4529
4675
  return true;
4530
4676
  }
@@ -4604,18 +4750,19 @@ function createDevtoolsHost(ctx, reconciler, deps) {
4604
4750
  }
4605
4751
  function rebuildDevtoolsHostView() {
4606
4752
  if (simulatorView) {
4607
- removeSimulatorDevtoolsView();
4608
- try {
4609
- if (!simulatorView.webContents.isDestroyed()) {
4610
- simulatorView.webContents.close();
4611
- }
4612
- } catch {
4613
- }
4753
+ reconciler.destroyView(VIEW_ID.simulatorDevtools, simulatorView);
4614
4754
  simulatorView = null;
4615
4755
  }
4616
4756
  simulatorView = new WebContentsView4();
4617
4757
  const devtoolsWc = simulatorView.webContents;
4618
4758
  raiseExecuteJavaScriptListenerCeiling(devtoolsWc);
4759
+ injectWhenReady(devtoolsWc, "soft-menu", () => {
4760
+ void whenFrontendBootstrapped(devtoolsWc).then((ready) => {
4761
+ if (!ready || devtoolsWc.isDestroyed()) return;
4762
+ devtoolsWc.executeJavaScript(buildDevtoolsSoftMenuScript()).catch(() => {
4763
+ });
4764
+ });
4765
+ });
4619
4766
  ctx.networkForward?.setDevtoolsHost(devtoolsWc);
4620
4767
  if (ctx.bridge) {
4621
4768
  try {
@@ -4661,10 +4808,23 @@ function createDevtoolsHost(ctx, reconciler, deps) {
4661
4808
  });
4662
4809
  });
4663
4810
  });
4811
+ const clearStaleFilter = clearFilterOnNextHostBuild;
4812
+ injectWhenReady(devtoolsWc, "clear-console-filter", () => {
4813
+ if (!clearStaleFilter) return;
4814
+ void whenFrontendBootstrapped(devtoolsWc).then((ready) => {
4815
+ if (!ready || devtoolsWc.isDestroyed()) return;
4816
+ try {
4817
+ void devtoolsWc.executeJavaScript(buildClearConsoleFilterScript()).catch(() => {
4818
+ });
4819
+ } catch {
4820
+ }
4821
+ });
4822
+ });
4664
4823
  reconciler.reconcileNow();
4665
4824
  devtoolsHostUsed = false;
4666
4825
  }
4667
4826
  function attachNativeSimulatorDevtoolsHost() {
4827
+ clearFilterOnNextHostBuild = true;
4668
4828
  stopFollowingNativeServiceHost();
4669
4829
  rebuildDevtoolsHostView();
4670
4830
  if (ctx.bridge?.isNativeHost()) {
@@ -4673,22 +4833,8 @@ function createDevtoolsHost(ctx, reconciler, deps) {
4673
4833
  followNativeDevtoolsServiceHost();
4674
4834
  }
4675
4835
  }
4676
- function removeSimulatorDevtoolsView() {
4677
- if (simulatorView && simulatorViewAdded) {
4678
- try {
4679
- ctx.windows.mainWindow.contentView.removeChildView(simulatorView);
4680
- } catch (e) {
4681
- console.error("[workbench] removeSimulatorDevtoolsView error", e);
4682
- }
4683
- simulatorViewAdded = false;
4684
- }
4685
- reconciler.forgetActual(VIEW_ID.simulatorDevtools);
4686
- }
4687
4836
  reconciler.registerView(VIEW_ID.simulatorDevtools, {
4688
4837
  getView: () => simulatorView,
4689
- setAdded: (added) => {
4690
- simulatorViewAdded = added;
4691
- },
4692
4838
  gateHidden: () => !simulatorView
4693
4839
  });
4694
4840
  return {
@@ -4703,9 +4849,8 @@ function createDevtoolsHost(ctx, reconciler, deps) {
4703
4849
  stopElementsForward = null;
4704
4850
  },
4705
4851
  destroyHostView: () => {
4706
- destroyChildView(ctx.windows.mainWindow, simulatorView);
4852
+ reconciler.destroyView(VIEW_ID.simulatorDevtools, simulatorView);
4707
4853
  simulatorView = null;
4708
- simulatorViewAdded = false;
4709
4854
  }
4710
4855
  };
4711
4856
  }
@@ -4870,7 +5015,6 @@ function createHostToolbarPortChannel(opts) {
4870
5015
  function createHostToolbarView(ctx, reconciler, deps) {
4871
5016
  let hostToolbarView = null;
4872
5017
  let hostToolbarPreloadOverride = null;
4873
- let hostToolbarViewAdded = false;
4874
5018
  let hostToolbarRuntimeAcquired = false;
4875
5019
  let hostToolbarHeightMode = "auto";
4876
5020
  let hostToolbarLastHeight = 0;
@@ -4886,14 +5030,9 @@ function createHostToolbarView(ctx, reconciler, deps) {
4886
5030
  if (hostToolbarView && liveHostToolbarWebContents()) {
4887
5031
  return hostToolbarView;
4888
5032
  }
4889
- if (hostToolbarView && hostToolbarViewAdded) {
4890
- try {
4891
- ctx.windows.mainWindow.contentView.removeChildView(hostToolbarView);
4892
- } catch {
4893
- }
4894
- hostToolbarViewAdded = false;
5033
+ if (hostToolbarView) {
5034
+ reconciler.destroyView(VIEW_ID.hostToolbar, hostToolbarView);
4895
5035
  }
4896
- reconciler.forgetActual(VIEW_ID.hostToolbar);
4897
5036
  if (!hostToolbarRuntimeAcquired) {
4898
5037
  acquireHostToolbarSessionRuntime();
4899
5038
  hostToolbarRuntimeAcquired = true;
@@ -4955,8 +5094,8 @@ function createHostToolbarView(ctx, reconciler, deps) {
4955
5094
  hide() {
4956
5095
  hideHostToolbar();
4957
5096
  },
4958
- setPreloadPath(path21) {
4959
- hostToolbarPreloadOverride = path21;
5097
+ setPreloadPath(path20) {
5098
+ hostToolbarPreloadOverride = path20;
4960
5099
  },
4961
5100
  setHeightMode(mode) {
4962
5101
  if (mode !== "auto" && !(Number.isFinite(mode.fixed) && mode.fixed >= 0)) {
@@ -4982,18 +5121,14 @@ function createHostToolbarView(ctx, reconciler, deps) {
4982
5121
  reconciler.registerView(VIEW_ID.hostToolbar, {
4983
5122
  getView: () => hostToolbarView,
4984
5123
  ensureView: () => ensureHostToolbarView(),
4985
- setAdded: (added) => {
4986
- hostToolbarViewAdded = added;
4987
- },
4988
5124
  ensureLazy: (desired) => {
4989
5125
  if (desired?.placement.visible && !liveHostToolbarWebContents()) ensureHostToolbarView();
4990
5126
  }
4991
5127
  });
4992
5128
  function dispose() {
4993
5129
  hostToolbarPort.dispose();
4994
- destroyChildView(ctx.windows.mainWindow, hostToolbarView);
5130
+ reconciler.destroyView(VIEW_ID.hostToolbar, hostToolbarView);
4995
5131
  hostToolbarView = null;
4996
- hostToolbarViewAdded = false;
4997
5132
  if (hostToolbarRuntimeAcquired) {
4998
5133
  releaseHostToolbarSessionRuntime();
4999
5134
  hostToolbarRuntimeAcquired = false;
@@ -5010,7 +5145,7 @@ function createHostToolbarView(ctx, reconciler, deps) {
5010
5145
 
5011
5146
  // src/main/services/views/overlay-panels-view.ts
5012
5147
  import { WebContentsView as WebContentsView6 } from "electron";
5013
- import path8 from "path";
5148
+ import { createOverlayPanel } from "@dimina-kit/electron-deck/main";
5014
5149
 
5015
5150
  // src/main/services/layout/index.ts
5016
5151
  function computeNativeSimulatorViewParams(rect, zoomPercent) {
@@ -5041,127 +5176,185 @@ function computePopoverBounds(contentWidth, contentHeight, headerHeight) {
5041
5176
  height: contentHeight - headerHeight
5042
5177
  };
5043
5178
  }
5179
+ var TOOLTIP_GAP = 6;
5180
+ var TOOLTIP_EDGE_MARGIN = 4;
5181
+ function computeTooltipMaxWidth(contentWidth) {
5182
+ return Math.max(1, contentWidth - TOOLTIP_EDGE_MARGIN * 2);
5183
+ }
5184
+ function computeTooltipBounds(anchor, contentWidth, contentHeight, measured) {
5185
+ const availableWidth = computeTooltipMaxWidth(contentWidth);
5186
+ const width = Math.min(availableWidth, Math.max(1, Math.ceil(measured.width)));
5187
+ const height = Math.max(1, Math.ceil(measured.height));
5188
+ const below = anchor.y + anchor.height + TOOLTIP_GAP;
5189
+ const fitsBelow = below + height <= contentHeight;
5190
+ const y = fitsBelow ? below : Math.max(0, anchor.y - TOOLTIP_GAP - height);
5191
+ const centeredX = anchor.x + anchor.width / 2 - width / 2;
5192
+ const maxX = Math.max(TOOLTIP_EDGE_MARGIN, contentWidth - width - TOOLTIP_EDGE_MARGIN);
5193
+ const x = Math.min(maxX, Math.max(TOOLTIP_EDGE_MARGIN, centeredX));
5194
+ return { x, y, width, height };
5195
+ }
5044
5196
 
5045
5197
  // src/main/services/views/overlay-panels-view.ts
5046
5198
  function createOverlayPanelsView(ctx, reconciler, deps) {
5047
- let settingsView = null;
5048
- let popoverView = null;
5049
5199
  function overlayHeaderHeight() {
5050
5200
  return HEADER_H + deps.getHostToolbarHeight();
5051
5201
  }
5052
- function applySettingsBounds() {
5053
- if (!settingsView || ctx.windows.mainWindow.isDestroyed()) return;
5054
- const [w = 0, h = 0] = ctx.windows.mainWindow.getContentSize();
5055
- reconciler.setOverlayDesired(VIEW_ID.settings, {
5056
- viewId: VIEW_ID.settings,
5057
- placement: {
5058
- visible: true,
5059
- bounds: computeSettingsBounds(w, h, overlayHeaderHeight())
5060
- },
5061
- layer: VIEW_LAYER.settings
5062
- });
5063
- reconciler.reconcileNow();
5064
- }
5065
- function applyPopoverBounds() {
5066
- if (!popoverView || ctx.windows.mainWindow.isDestroyed()) return;
5067
- const [w = 0, h = 0] = ctx.windows.mainWindow.getContentSize();
5068
- reconciler.setOverlayDesired(VIEW_ID.popover, {
5069
- viewId: VIEW_ID.popover,
5070
- placement: {
5071
- visible: true,
5072
- bounds: computePopoverBounds(w, h, overlayHeaderHeight())
5073
- },
5074
- layer: VIEW_LAYER.popover
5075
- });
5076
- reconciler.reconcileNow();
5202
+ function overlayDesiredSetter(viewId, layer) {
5203
+ return (bounds) => {
5204
+ if (bounds === null) {
5205
+ reconciler.deleteOverlayDesired(viewId);
5206
+ } else {
5207
+ reconciler.setOverlayDesired(viewId, {
5208
+ viewId,
5209
+ placement: { visible: true, bounds },
5210
+ layer
5211
+ });
5212
+ }
5213
+ reconciler.reconcileNow();
5214
+ };
5077
5215
  }
5078
- async function showSettings() {
5079
- if (!settingsView) {
5080
- settingsView = new WebContentsView6({
5081
- webPreferences: {
5082
- nodeIntegration: false,
5083
- contextIsolation: true,
5084
- sandbox: false,
5085
- preload: mainPreloadPath
5086
- }
5216
+ const settingsPanel = createOverlayPanel({
5217
+ electron: { createWebContentsView: (opts) => new WebContentsView6(opts) },
5218
+ rendererDir: ctx.rendererDir,
5219
+ entry: "entries/settings/index.html",
5220
+ webPreferences: {
5221
+ nodeIntegration: false,
5222
+ contextIsolation: true,
5223
+ sandbox: false,
5224
+ preload: mainPreloadPath
5225
+ },
5226
+ hardenNavigation: (wc) => applyNavigationHardening(wc, ctx.rendererDir),
5227
+ setDesired: overlayDesiredSetter(VIEW_ID.settings, VIEW_LAYER.settings),
5228
+ registerView: (getView) => reconciler.registerView(VIEW_ID.settings, { getView }),
5229
+ destroyView: (view) => reconciler.destroyView(VIEW_ID.settings, view),
5230
+ readyMode: "manual"
5231
+ });
5232
+ const popoverPanel = createOverlayPanel({
5233
+ electron: { createWebContentsView: (opts) => new WebContentsView6(opts) },
5234
+ rendererDir: ctx.rendererDir,
5235
+ entry: "entries/popover/index.html",
5236
+ webPreferences: {
5237
+ nodeIntegration: false,
5238
+ contextIsolation: true,
5239
+ sandbox: false,
5240
+ preload: mainPreloadPath
5241
+ },
5242
+ hardenNavigation: (wc) => applyNavigationHardening(wc, ctx.rendererDir),
5243
+ setDesired: overlayDesiredSetter(VIEW_ID.popover, VIEW_LAYER.popover),
5244
+ registerView: (getView) => reconciler.registerView(VIEW_ID.popover, { getView }),
5245
+ destroyView: (view) => reconciler.destroyView(VIEW_ID.popover, view),
5246
+ pushData: (view, data) => ctx.notify.popoverInit(view, data),
5247
+ readyMode: "manual"
5248
+ });
5249
+ const tooltipPanel = createOverlayPanel({
5250
+ electron: { createWebContentsView: (opts) => new WebContentsView6(opts) },
5251
+ rendererDir: ctx.rendererDir,
5252
+ entry: "entries/tooltip/index.html",
5253
+ webPreferences: {
5254
+ nodeIntegration: false,
5255
+ contextIsolation: true,
5256
+ sandbox: false,
5257
+ preload: mainPreloadPath
5258
+ },
5259
+ hardenNavigation: (wc) => applyNavigationHardening(wc, ctx.rendererDir),
5260
+ setDesired: overlayDesiredSetter(VIEW_ID.tooltip, VIEW_LAYER.tooltip),
5261
+ registerView: (getView) => reconciler.registerView(VIEW_ID.tooltip, { getView }),
5262
+ prepareView: (view) => {
5263
+ const [width = 0, height = 0] = ctx.windows.mainWindow.getContentSize();
5264
+ reconciler.prepareView(VIEW_ID.tooltip, view, {
5265
+ x: 0,
5266
+ y: 0,
5267
+ width: Math.max(1, width),
5268
+ height: Math.max(1, height)
5087
5269
  });
5088
- applyNavigationHardening(settingsView.webContents, ctx.rendererDir);
5089
- settingsView.setBackgroundColor("#00000000");
5090
- await settingsView.webContents.loadFile(
5091
- path8.join(ctx.rendererDir, "entries/settings/index.html")
5092
- );
5093
- }
5094
- applySettingsBounds();
5270
+ },
5271
+ destroyView: (view) => reconciler.destroyView(VIEW_ID.tooltip, view),
5272
+ pushData: (view, data) => ctx.notify.tooltipInit(view, data),
5273
+ readyMode: "manual"
5274
+ });
5275
+ let tooltipRequestId = 0;
5276
+ let activeTooltip = null;
5277
+ async function showSettings() {
5278
+ const [w = 0, h = 0] = ctx.windows.mainWindow.getContentSize();
5279
+ settingsPanel.show(void 0, computeSettingsBounds(w, h, overlayHeaderHeight()));
5280
+ await settingsPanel.whenReady();
5095
5281
  }
5096
5282
  function hideSettings() {
5097
- reconciler.deleteOverlayDesired(VIEW_ID.settings);
5098
- reconciler.reconcileNow();
5283
+ settingsPanel.hide();
5099
5284
  }
5100
5285
  function showPopover(data) {
5101
5286
  hidePopover();
5102
- const popover = new WebContentsView6({
5103
- webPreferences: {
5104
- nodeIntegration: false,
5105
- contextIsolation: true,
5106
- sandbox: false,
5107
- preload: mainPreloadPath
5108
- }
5109
- });
5110
- applyNavigationHardening(popover.webContents, ctx.rendererDir);
5111
- popoverView = popover;
5112
- popover.setBackgroundColor("#00000000");
5113
- applyPopoverBounds();
5114
- popover.webContents.once("did-finish-load", () => {
5115
- ctx.notify.popoverInit(popover, data);
5116
- });
5117
- popover.webContents.loadFile(
5118
- path8.join(ctx.rendererDir, "entries/popover/index.html")
5119
- );
5287
+ const [w = 0, h = 0] = ctx.windows.mainWindow.getContentSize();
5288
+ popoverPanel.show(data, computePopoverBounds(w, h, overlayHeaderHeight()));
5120
5289
  }
5121
5290
  function hidePopover() {
5122
- if (!popoverView) return;
5291
+ if (!popoverPanel.isPresent()) return;
5292
+ popoverPanel.destroy();
5123
5293
  reconciler.deleteOverlayDesired(VIEW_ID.popover);
5124
- destroyChildView(ctx.windows.mainWindow, popoverView);
5125
- popoverView = null;
5126
5294
  reconciler.reconcileNow();
5127
5295
  ctx.notify.popoverClosed();
5128
5296
  }
5297
+ function prepareTooltip() {
5298
+ tooltipPanel.prepare();
5299
+ }
5300
+ function showTooltip(data) {
5301
+ const requestId = ++tooltipRequestId;
5302
+ activeTooltip = { requestId, anchor: data.anchor };
5303
+ const [contentWidth = 0] = ctx.windows.mainWindow.getContentSize();
5304
+ tooltipPanel.show({
5305
+ requestId,
5306
+ text: data.text,
5307
+ maxWidth: computeTooltipMaxWidth(contentWidth)
5308
+ }, null);
5309
+ }
5310
+ function hideTooltip() {
5311
+ activeTooltip = null;
5312
+ tooltipPanel.hide();
5313
+ }
5314
+ function markOverlayReady(webContentsId) {
5315
+ settingsPanel.markReady(webContentsId);
5316
+ popoverPanel.markReady(webContentsId);
5317
+ tooltipPanel.markReady(webContentsId);
5318
+ }
5319
+ function applyTooltipMeasurement(webContentsId, measurement) {
5320
+ const active = activeTooltip;
5321
+ if (!active || active.requestId !== measurement.requestId) return;
5322
+ if (tooltipPanel.getWebContentsId() !== webContentsId) return;
5323
+ const [w = 0, h = 0] = ctx.windows.mainWindow.getContentSize();
5324
+ tooltipPanel.reposition(computeTooltipBounds(active.anchor, w, h, measurement));
5325
+ }
5129
5326
  function reapplyPresentOverlays() {
5130
- if (reconciler.hasOverlayDesired(VIEW_ID.settings)) applySettingsBounds();
5131
- if (reconciler.hasOverlayDesired(VIEW_ID.popover)) applyPopoverBounds();
5327
+ if (settingsPanel.isPresent() && reconciler.hasOverlayDesired(VIEW_ID.settings)) void showSettings();
5328
+ if (popoverPanel.isPresent() && reconciler.hasOverlayDesired(VIEW_ID.popover)) {
5329
+ const [w = 0, h = 0] = ctx.windows.mainWindow.getContentSize();
5330
+ popoverPanel.reposition(computePopoverBounds(w, h, overlayHeaderHeight()));
5331
+ }
5132
5332
  }
5133
5333
  function applySettingsBoundsIfPresent() {
5134
- if (reconciler.hasOverlayDesired(VIEW_ID.settings)) applySettingsBounds();
5334
+ if (settingsPanel.isPresent() && reconciler.hasOverlayDesired(VIEW_ID.settings)) void showSettings();
5135
5335
  }
5136
5336
  function destroySettings() {
5137
- destroyChildView(ctx.windows.mainWindow, settingsView);
5138
- settingsView = null;
5337
+ activeTooltip = null;
5338
+ settingsPanel.destroy();
5339
+ tooltipPanel.destroy();
5139
5340
  }
5140
- reconciler.registerView(VIEW_ID.settings, { getView: () => settingsView });
5141
- reconciler.registerView(VIEW_ID.popover, { getView: () => popoverView });
5142
5341
  return {
5143
5342
  showSettings,
5144
5343
  hideSettings,
5145
5344
  showPopover,
5146
5345
  hidePopover,
5346
+ prepareTooltip,
5347
+ showTooltip,
5348
+ hideTooltip,
5349
+ markOverlayReady,
5350
+ applyTooltipMeasurement,
5147
5351
  reapplyPresentOverlays,
5148
5352
  applySettingsBoundsIfPresent,
5149
5353
  destroySettings,
5150
- getSettingsWebContents: () => {
5151
- if (!settingsView) return null;
5152
- if (settingsView.webContents.isDestroyed()) return null;
5153
- return settingsView.webContents;
5154
- },
5155
- getSettingsWebContentsId: () => {
5156
- if (!settingsView) return null;
5157
- if (settingsView.webContents.isDestroyed()) return null;
5158
- return settingsView.webContents.id;
5159
- },
5160
- getPopoverWebContentsId: () => {
5161
- if (!popoverView) return null;
5162
- if (popoverView.webContents.isDestroyed()) return null;
5163
- return popoverView.webContents.id;
5164
- }
5354
+ getSettingsWebContents: () => settingsPanel.getWebContents(),
5355
+ getSettingsWebContentsId: () => settingsPanel.getWebContentsId(),
5356
+ getPopoverWebContentsId: () => popoverPanel.getWebContentsId(),
5357
+ getTooltipWebContentsId: () => tooltipPanel.getWebContentsId()
5165
5358
  };
5166
5359
  }
5167
5360
 
@@ -5218,6 +5411,12 @@ function refreshGuestStylesheets(view) {
5218
5411
  }
5219
5412
 
5220
5413
  // src/shared/simulator-route.ts
5414
+ function encodePageSpec(spec) {
5415
+ const keys = Object.keys(spec.query);
5416
+ if (keys.length === 0) return spec.pagePath;
5417
+ const qs = keys.map((k) => `${encodeURIComponent(k)}=${encodeURIComponent(spec.query[k] ?? "")}`).join("&");
5418
+ return `${spec.pagePath}?${qs}`;
5419
+ }
5221
5420
  function decodePageSpec(value) {
5222
5421
  const qIdx = value.indexOf("?");
5223
5422
  if (qIdx < 0) return { pagePath: value, query: {} };
@@ -5261,7 +5460,6 @@ import * as bridge_channels_star from "@dimina-kit/electron-runtime/shared/bridg
5261
5460
  function createNativeSimulatorView(ctx, reconciler, deps) {
5262
5461
  const { safeArea, devtoolsHost, overlayPanels } = deps;
5263
5462
  let nativeSimulatorView = null;
5264
- let nativeSimulatorViewAdded = false;
5265
5463
  let nativeSimulatorProjectPath = null;
5266
5464
  let settleNativeSimulatorReady = null;
5267
5465
  let nativeSimulatorShellReady = false;
@@ -5283,25 +5481,18 @@ function createNativeSimulatorView(ctx, reconciler, deps) {
5283
5481
  }
5284
5482
  }
5285
5483
  function tearDownNativeSimulatorView(label) {
5286
- if (!nativeSimulatorView) return;
5287
- ctx.simulatorUiExtensions?.detach(nativeSimulatorView.webContents);
5288
- if (nativeSimulatorViewAdded && !ctx.windows.mainWindow.isDestroyed()) {
5289
- try {
5290
- ctx.windows.mainWindow.contentView.removeChildView(nativeSimulatorView);
5291
- } catch {
5292
- }
5293
- }
5484
+ const view = nativeSimulatorView;
5485
+ if (!view) return;
5486
+ ctx.simulatorUiExtensions?.detach(view.webContents);
5294
5487
  try {
5295
- if (!nativeSimulatorView.webContents.isDestroyed()) {
5296
- ctx.bridge?.disposeSessionsForSimulator?.(nativeSimulatorView.webContents.id)?.catch((err2) => console.warn(`[view-manager] dispose sessions (${label}) failed:`, err2));
5297
- nativeSimulatorView.webContents.close();
5488
+ if (!view.webContents.isDestroyed()) {
5489
+ ctx.bridge?.disposeSessionsForSimulator?.(view.webContents.id)?.catch((err2) => console.warn(`[view-manager] dispose sessions (${label}) failed:`, err2));
5298
5490
  }
5299
5491
  } catch {
5300
5492
  }
5493
+ reconciler.destroyView(VIEW_ID.simulator, view);
5301
5494
  nativeSimulatorView = null;
5302
- nativeSimulatorViewAdded = false;
5303
5495
  nativeSimulatorShellReady = false;
5304
- reconciler.forgetActual(VIEW_ID.simulator);
5305
5496
  reconciler.reconcileNow();
5306
5497
  }
5307
5498
  function detachNativeCustomApiBridge() {
@@ -5473,9 +5664,6 @@ function createNativeSimulatorView(ctx, reconciler, deps) {
5473
5664
  }
5474
5665
  reconciler.registerView(VIEW_ID.simulator, {
5475
5666
  getView: () => nativeSimulatorView,
5476
- setAdded: (added) => {
5477
- nativeSimulatorViewAdded = added;
5478
- },
5479
5667
  gateHidden: () => !nativeSimulatorView,
5480
5668
  applyBounds: (view, bounds, extra) => applyNativeSimulatorBounds(view, bounds, extra?.zoom ?? 1)
5481
5669
  });
@@ -5536,6 +5724,11 @@ function createViewManager(ctx) {
5536
5724
  hideSettings: overlayPanels.hideSettings,
5537
5725
  showPopover: overlayPanels.showPopover,
5538
5726
  hidePopover: overlayPanels.hidePopover,
5727
+ prepareTooltip: overlayPanels.prepareTooltip,
5728
+ showTooltip: overlayPanels.showTooltip,
5729
+ hideTooltip: overlayPanels.hideTooltip,
5730
+ markOverlayReady: overlayPanels.markOverlayReady,
5731
+ applyTooltipMeasurement: overlayPanels.applyTooltipMeasurement,
5539
5732
  repositionAll: () => overlayPanels.reapplyPresentOverlays(),
5540
5733
  disposeProjectViews,
5541
5734
  disposeAll,
@@ -5545,6 +5738,7 @@ function createViewManager(ctx) {
5545
5738
  getSettingsWebContents: overlayPanels.getSettingsWebContents,
5546
5739
  getSettingsWebContentsId: overlayPanels.getSettingsWebContentsId,
5547
5740
  getPopoverWebContentsId: overlayPanels.getPopoverWebContentsId,
5741
+ getTooltipWebContentsId: overlayPanels.getTooltipWebContentsId,
5548
5742
  getHostToolbarWebContentsId: hostToolbar.getHostToolbarWebContentsId,
5549
5743
  getHostToolbarHeight: hostToolbar.getHostToolbarHeight,
5550
5744
  resize: () => overlayPanels.applySettingsBoundsIfPresent(),
@@ -5588,7 +5782,7 @@ function createWindowService(mainWindow) {
5588
5782
 
5589
5783
  // src/main/windows/settings-window/create.ts
5590
5784
  import { BrowserWindow as BrowserWindow4 } from "electron";
5591
- import path9 from "path";
5785
+ import path8 from "path";
5592
5786
  async function createSettingsWindow(parent, rendererDir2) {
5593
5787
  const win = new BrowserWindow4({
5594
5788
  width: 420,
@@ -5606,7 +5800,7 @@ async function createSettingsWindow(parent, rendererDir2) {
5606
5800
  }
5607
5801
  });
5608
5802
  applyNavigationHardening(win.webContents, rendererDir2);
5609
- await win.loadFile(path9.join(rendererDir2, "entries/workbench-settings/index.html"));
5803
+ await win.loadFile(path8.join(rendererDir2, "entries/workbench-settings/index.html"));
5610
5804
  return win;
5611
5805
  }
5612
5806
 
@@ -5688,11 +5882,11 @@ __export(project_repository_exports, {
5688
5882
  validateProjectDir: () => validateProjectDir
5689
5883
  });
5690
5884
  import { app as app6 } from "electron";
5691
- import path10 from "path";
5885
+ import path9 from "path";
5692
5886
  import fs5 from "fs";
5693
5887
  var log2 = createLogger("projects");
5694
5888
  function getProjectsFile() {
5695
- return path10.join(app6.getPath("userData"), "dimina-projects.json");
5889
+ return path9.join(app6.getPath("userData"), "dimina-projects.json");
5696
5890
  }
5697
5891
  function load() {
5698
5892
  try {
@@ -5714,13 +5908,13 @@ function validateProjectDir(dirPath) {
5714
5908
  if (!fs5.existsSync(dirPath)) {
5715
5909
  return `\u5C0F\u7A0B\u5E8F\u76EE\u5F55\u4E0D\u5B58\u5728\uFF1A${dirPath}`;
5716
5910
  }
5717
- if (!fs5.existsSync(path10.join(dirPath, "app.json"))) {
5718
- const configPath = path10.join(dirPath, "project.config.json");
5911
+ if (!fs5.existsSync(path9.join(dirPath, "app.json"))) {
5912
+ const configPath = path9.join(dirPath, "project.config.json");
5719
5913
  if (fs5.existsSync(configPath)) {
5720
5914
  try {
5721
5915
  const cfg = JSON.parse(fs5.readFileSync(configPath, "utf-8"));
5722
5916
  if (cfg.miniprogramRoot) {
5723
- const resolvedRoot = path10.resolve(dirPath, cfg.miniprogramRoot);
5917
+ const resolvedRoot = path9.resolve(dirPath, cfg.miniprogramRoot);
5724
5918
  return `\u8BE5\u76EE\u5F55\u7F3A\u5C11 app.json\uFF0Cproject.config.json \u4E2D\u6307\u5B9A\u4E86 miniprogramRoot: "${cfg.miniprogramRoot}"\uFF0C\u8BF7\u5BFC\u5165 ${resolvedRoot}`;
5725
5919
  }
5726
5920
  } catch (err2) {
@@ -5736,9 +5930,9 @@ function hasProject(dirPath) {
5736
5930
  }
5737
5931
  function addProject(dirPath) {
5738
5932
  const projects = load();
5739
- let name = path10.basename(dirPath);
5933
+ let name = path9.basename(dirPath);
5740
5934
  try {
5741
- const configPath = path10.join(dirPath, "project.config.json");
5935
+ const configPath = path9.join(dirPath, "project.config.json");
5742
5936
  if (fs5.existsSync(configPath)) {
5743
5937
  const cfg = JSON.parse(fs5.readFileSync(configPath, "utf-8"));
5744
5938
  if (cfg.projectname) name = cfg.projectname;
@@ -5777,7 +5971,7 @@ function getCompileConfig(dirPath) {
5777
5971
  };
5778
5972
  }
5779
5973
  function getProjectPages(dirPath) {
5780
- const appJsonPath = path10.join(dirPath, "app.json");
5974
+ const appJsonPath = path9.join(dirPath, "app.json");
5781
5975
  try {
5782
5976
  const appJson = JSON.parse(
5783
5977
  fs5.readFileSync(appJsonPath, "utf-8")
@@ -5804,7 +5998,7 @@ function getProjectSettings(projectPath) {
5804
5998
  return { uploadWithSourceMap: false };
5805
5999
  }
5806
6000
  try {
5807
- const configPath = path10.join(projectPath, "project.config.json");
6001
+ const configPath = path9.join(projectPath, "project.config.json");
5808
6002
  const config = JSON.parse(fs5.readFileSync(configPath, "utf-8"));
5809
6003
  return {
5810
6004
  uploadWithSourceMap: !!config.setting?.uploadWithSourceMap
@@ -5815,7 +6009,7 @@ function getProjectSettings(projectPath) {
5815
6009
  }
5816
6010
  function updateProjectSettings(projectPath, patch) {
5817
6011
  if (!projectPath) return;
5818
- const configPath = path10.join(projectPath, "project.config.json");
6012
+ const configPath = path9.join(projectPath, "project.config.json");
5819
6013
  let config = {};
5820
6014
  try {
5821
6015
  config = JSON.parse(fs5.readFileSync(configPath, "utf-8"));
@@ -5835,6 +6029,10 @@ function updateProjectSettings(projectPath, patch) {
5835
6029
  function reportRebuildStatus(info, deps) {
5836
6030
  const { pages } = deps.repo.getProjectPages(deps.projectPath);
5837
6031
  const pageList = pages.length ? pages : void 0;
6032
+ if (info?.explicit) {
6033
+ deps.sendStatus("ready", "\u7F16\u8BD1\u5B8C\u6210", false, pageList);
6034
+ return;
6035
+ }
5838
6036
  if (info?.styleOnly && deps.autoReload && deps.refreshSimulatorStyles()) {
5839
6037
  deps.sendStatus("ready", "\u6837\u5F0F\u5DF2\u70ED\u66F4\u65B0", false, pageList);
5840
6038
  return;
@@ -6116,16 +6314,16 @@ function createWorkspaceService(ctx) {
6116
6314
  // src/main/services/projects/thumbnail.ts
6117
6315
  import { createHash } from "crypto";
6118
6316
  import fs6 from "fs";
6119
- import path11 from "path";
6317
+ import path10 from "path";
6120
6318
  import { app as app7 } from "electron";
6121
6319
  function getThumbnailDir() {
6122
- return path11.join(app7.getPath("userData"), "thumbnails");
6320
+ return path10.join(app7.getPath("userData"), "thumbnails");
6123
6321
  }
6124
6322
  function hashProjectPath(projectPath) {
6125
6323
  return createHash("sha256").update(projectPath).digest("hex").slice(0, 16);
6126
6324
  }
6127
6325
  function getThumbnailPath(projectPath) {
6128
- return path11.join(getThumbnailDir(), `${hashProjectPath(projectPath)}.png`);
6326
+ return path10.join(getThumbnailDir(), `${hashProjectPath(projectPath)}.png`);
6129
6327
  }
6130
6328
  var DATA_URL_PNG_PREFIX = "data:image/png;base64,";
6131
6329
  function saveThumbnailFromDataUrl(projectPath, imageDataUrl) {
@@ -6353,20 +6551,20 @@ function sanitizeTemplates(templates) {
6353
6551
  }
6354
6552
 
6355
6553
  // src/main/services/projects/builtin-templates.ts
6356
- import path12 from "node:path";
6357
- var TEMPLATES_DIR = path12.join(devtoolsPackageRoot, "templates");
6554
+ import path11 from "node:path";
6555
+ var TEMPLATES_DIR = path11.join(devtoolsPackageRoot, "templates");
6358
6556
  var BUILTIN_TEMPLATES = [
6359
6557
  {
6360
6558
  id: "blank",
6361
6559
  name: "Blank",
6362
6560
  description: "\u6700\u5C0F\u9AA8\u67B6\uFF1Aapp.* + \u4E00\u4E2A index \u9875\u9762",
6363
- source: { type: "directory", path: path12.join(TEMPLATES_DIR, "blank") }
6561
+ source: { type: "directory", path: path11.join(TEMPLATES_DIR, "blank") }
6364
6562
  },
6365
6563
  {
6366
6564
  id: "taro-todo",
6367
6565
  name: "Taro Todo",
6368
6566
  description: "Taro \u7F16\u8BD1\u4EA7\u7269\u7684 Todo \u793A\u4F8B",
6369
- source: { type: "directory", path: path12.join(TEMPLATES_DIR, "taro-todo") }
6567
+ source: { type: "directory", path: path11.join(TEMPLATES_DIR, "taro-todo") }
6370
6568
  }
6371
6569
  ];
6372
6570
 
@@ -6584,6 +6782,24 @@ var ProjectSaveCompileConfigSchema = z3.tuple([
6584
6782
  CompileConfigShape
6585
6783
  ]);
6586
6784
  var PopoverShowSchema = z3.tuple([z3.looseObject({})]);
6785
+ var TooltipShowSchema = z3.tuple([
6786
+ z3.object({
6787
+ anchor: z3.object({
6788
+ x: z3.number().finite(),
6789
+ y: z3.number().finite(),
6790
+ width: z3.number().finite().nonnegative(),
6791
+ height: z3.number().finite().nonnegative()
6792
+ }),
6793
+ text: z3.string().min(1).max(200)
6794
+ })
6795
+ ]);
6796
+ var TooltipMeasuredSchema = z3.tuple([
6797
+ z3.object({
6798
+ requestId: z3.number().int().positive(),
6799
+ width: z3.number().finite().positive(),
6800
+ height: z3.number().finite().positive()
6801
+ })
6802
+ ]);
6587
6803
  var SimWidth = z3.number().int().min(100).max(2e3);
6588
6804
  var SimulatorAttachNativeSchema = z3.tuple([
6589
6805
  z3.string().url().refine((u) => u.startsWith("http://") || u.startsWith("https://"), {
@@ -6731,13 +6947,34 @@ var popoverModule = {
6731
6947
  setup: (ctx) => registerPopoverIpc(ctx)
6732
6948
  };
6733
6949
 
6950
+ // src/main/ipc/tooltip.ts
6951
+ function registerTooltipIpc(ctx) {
6952
+ return new IpcRegistry(ctx.senderPolicy).on(TooltipChannel.Prepare, () => {
6953
+ ctx.views.prepareTooltip();
6954
+ }).on(TooltipChannel.Show, (_event, ...args) => {
6955
+ const [data] = validate(TooltipChannel.Show, TooltipShowSchema, args);
6956
+ ctx.views.showTooltip(data);
6957
+ }).on(TooltipChannel.Hide, () => {
6958
+ ctx.views.hideTooltip();
6959
+ }).on(OverlayChannel.Ready, (event) => {
6960
+ ctx.views.markOverlayReady(event.sender.id);
6961
+ }).on(TooltipChannel.Measured, (event, ...args) => {
6962
+ const [measurement] = validate(
6963
+ TooltipChannel.Measured,
6964
+ TooltipMeasuredSchema,
6965
+ args
6966
+ );
6967
+ ctx.views.applyTooltipMeasurement(event.sender.id, measurement);
6968
+ });
6969
+ }
6970
+
6734
6971
  // src/main/ipc/projects.ts
6735
6972
  import { app as app8, dialog } from "electron";
6736
- import path14 from "path";
6973
+ import path13 from "path";
6737
6974
 
6738
6975
  // src/main/services/projects/create-project-service.ts
6739
6976
  import fs7 from "node:fs";
6740
- import path13 from "node:path";
6977
+ import path12 from "node:path";
6741
6978
  var DEFAULT_TEMPLATE_ID = "blank";
6742
6979
  function resolveName(rawName) {
6743
6980
  const name = (rawName ?? "").trim();
@@ -6793,7 +7030,7 @@ async function materializeTemplate(target, template, name) {
6793
7030
  });
6794
7031
  }
6795
7032
  function writeProjectConfig(target, name) {
6796
- const cfgPath = path13.join(target, "project.config.json");
7033
+ const cfgPath = path12.join(target, "project.config.json");
6797
7034
  let cfg = {};
6798
7035
  if (fs7.existsSync(cfgPath)) {
6799
7036
  try {
@@ -6887,7 +7124,7 @@ function registerProjectsIpc(ctx) {
6887
7124
  }
6888
7125
  try {
6889
7126
  const settings = loadWorkbenchSettings();
6890
- const newBase = path14.dirname(input.path);
7127
+ const newBase = path13.dirname(input.path);
6891
7128
  if (newBase && settings.lastCreateBaseDir !== newBase) {
6892
7129
  saveWorkbenchSettings({ ...settings, lastCreateBaseDir: newBase });
6893
7130
  }
@@ -6936,6 +7173,12 @@ function registerSessionIpc(ctx) {
6936
7173
  return ctx.workspace.saveCompileConfig(projectPath, config);
6937
7174
  }).handle(ProjectChannel.Close, () => {
6938
7175
  return ctx.workspace.closeProject();
7176
+ }).handle(ProjectChannel.Rebuild, async () => {
7177
+ const session3 = ctx.workspace.getSession();
7178
+ if (!session3) throw new Error("project:rebuild \u2014 no active project session");
7179
+ if (typeof session3.rebuild !== "function") return { supported: false };
7180
+ await session3.rebuild();
7181
+ return { supported: true };
6939
7182
  }).handle(ProjectChannel.CaptureThumbnail, (_, ...args) => {
6940
7183
  const [projectPath] = validate(
6941
7184
  ProjectChannel.CaptureThumbnail,
@@ -8324,7 +8567,7 @@ function registerContextTools(server) {
8324
8567
  }
8325
8568
 
8326
8569
  // src/main/services/mcp/tools/project-tools.ts
8327
- import path15 from "node:path";
8570
+ import path14 from "node:path";
8328
8571
  import { z as z5 } from "zod";
8329
8572
  var DEFAULT_OPEN_TIMEOUT_MS = 18e4;
8330
8573
  var DEFAULT_WAIT_TIMEOUT_MS = 6e4;
@@ -8360,7 +8603,7 @@ function registerProjectTools(server, host) {
8360
8603
  timeoutMs: z5.number().optional().default(DEFAULT_OPEN_TIMEOUT_MS).describe("Max time to wait for the compile to settle")
8361
8604
  },
8362
8605
  async ({ path: rawPath, timeoutMs }) => {
8363
- const dir = path15.resolve(rawPath);
8606
+ const dir = path14.resolve(rawPath);
8364
8607
  const current = host.sessionStatus.get();
8365
8608
  if (host.workspace.getProjectPath() === dir && host.workspace.hasActiveSession() && current.phase === "ready") {
8366
8609
  return text({ ...statusPayload(host), note: "project already open" });
@@ -8370,7 +8613,7 @@ function registerProjectTools(server, host) {
8370
8613
  let project;
8371
8614
  if (await host.workspace.hasProject(dir)) {
8372
8615
  const known = (await host.workspace.listProjects()).find((p) => p.path === dir);
8373
- project = known ?? { name: path15.basename(dir), path: dir };
8616
+ project = known ?? { name: path14.basename(dir), path: dir };
8374
8617
  } else {
8375
8618
  project = await host.workspace.addProject(dir);
8376
8619
  }
@@ -9241,7 +9484,9 @@ function setupSimulatorCurrentPage(host, options) {
9241
9484
  const off = options.bridge.onRenderEvent((ev) => {
9242
9485
  if (ev.kind !== "activePage" || !ev.pagePath) return;
9243
9486
  if (host.isDestroyed()) return;
9244
- host.send(SimulatorChannel.CurrentPage, ev.pagePath);
9487
+ const query = {};
9488
+ for (const [k, v] of Object.entries(ev.query ?? {})) query[k] = String(v);
9489
+ host.send(SimulatorChannel.CurrentPage, encodePageSpec({ pagePath: ev.pagePath, query }));
9245
9490
  });
9246
9491
  registry.add(off);
9247
9492
  return registry;
@@ -9249,7 +9494,7 @@ function setupSimulatorCurrentPage(host, options) {
9249
9494
 
9250
9495
  // src/main/services/render-inspect/index.ts
9251
9496
  import { readFileSync } from "node:fs";
9252
- import path16 from "node:path";
9497
+ import path15 from "node:path";
9253
9498
  var DEFAULT_SOURCE_PATH = "dist/render-host/render-inspect.js";
9254
9499
  var HIGHLIGHT_CONFIG = {
9255
9500
  showInfo: true,
@@ -9275,7 +9520,7 @@ function withTimeout(p, ms) {
9275
9520
  });
9276
9521
  }
9277
9522
  function createRenderInspector(options = {}) {
9278
- const loadSource = options.loadSource ?? (() => readFileSync(path16.join(devtoolsPackageRoot, DEFAULT_SOURCE_PATH), "utf8"));
9523
+ const loadSource = options.loadSource ?? (() => readFileSync(path15.join(devtoolsPackageRoot, DEFAULT_SOURCE_PATH), "utf8"));
9279
9524
  let cachedSource = null;
9280
9525
  const injected = /* @__PURE__ */ new Set();
9281
9526
  const broker = options.broker ?? createCdpSessionBroker({ connections: options.connections });
@@ -9397,11 +9642,11 @@ import * as session_policy_star from "@dimina-kit/electron-runtime/main/session-
9397
9642
  import http from "node:http";
9398
9643
  import nodeFs3 from "node:fs";
9399
9644
  import fs8 from "node:fs/promises";
9400
- import path18 from "node:path";
9645
+ import path17 from "node:path";
9401
9646
 
9402
9647
  // src/main/services/fs-watch-sse.ts
9403
9648
  import nodeFs2 from "node:fs";
9404
- import path17 from "node:path";
9649
+ import path16 from "node:path";
9405
9650
 
9406
9651
  // src/main/services/http-json.ts
9407
9652
  function jsonRes(res, code, obj) {
@@ -9413,7 +9658,7 @@ function jsonRes(res, code, obj) {
9413
9658
  // src/main/services/fs-watch-sse.ts
9414
9659
  var WATCH_DEBOUNCE_MS = 80;
9415
9660
  function shouldReportWatchPath(rel) {
9416
- if (rel === "" || rel.startsWith("..") || path17.isAbsolute(rel)) return false;
9661
+ if (rel === "" || rel.startsWith("..") || path16.isAbsolute(rel)) return false;
9417
9662
  return !rel.split("/").some((segment) => SKIP_DIRS.has(segment));
9418
9663
  }
9419
9664
  function handleFsWatchRequest(req, res, getProjectRoot) {
@@ -9454,7 +9699,7 @@ function handleFsWatchRequest(req, res, getProjectRoot) {
9454
9699
  `);
9455
9700
  }
9456
9701
  function onChange(_event, filename) {
9457
- const rel = filename ? filename.toString().split(path17.sep).join("/") : ".";
9702
+ const rel = filename ? filename.toString().split(path16.sep).join("/") : ".";
9458
9703
  if (rel !== "." && !shouldReportWatchPath(rel)) return;
9459
9704
  pending.add(rel);
9460
9705
  if (!debounceTimer) {
@@ -9509,8 +9754,8 @@ function setIsolationHeaders(res) {
9509
9754
  }
9510
9755
  function containedStaticPath(root, pathname) {
9511
9756
  const rel = pathname.replace(/^\/+/, "") || "index.html";
9512
- const resolved = path18.resolve(root, rel);
9513
- if (resolved !== root && !resolved.startsWith(root + path18.sep)) return null;
9757
+ const resolved = path17.resolve(root, rel);
9758
+ if (resolved !== root && !resolved.startsWith(root + path17.sep)) return null;
9514
9759
  return resolved;
9515
9760
  }
9516
9761
  function serveStaticFile(res, root, pathname) {
@@ -9521,7 +9766,7 @@ function serveStaticFile(res, root, pathname) {
9521
9766
  return;
9522
9767
  }
9523
9768
  Promise.all([fs8.realpath(root), fs8.realpath(candidate)]).then(([realRoot, realFile]) => {
9524
- if (realFile !== realRoot && !realFile.startsWith(realRoot + path18.sep)) {
9769
+ if (realFile !== realRoot && !realFile.startsWith(realRoot + path17.sep)) {
9525
9770
  res.writeHead(403);
9526
9771
  res.end("Forbidden");
9527
9772
  return;
@@ -9533,7 +9778,7 @@ function serveStaticFile(res, root, pathname) {
9533
9778
  return;
9534
9779
  }
9535
9780
  res.writeHead(200, {
9536
- "Content-Type": MIME[path18.extname(realFile)] ?? "application/octet-stream",
9781
+ "Content-Type": MIME[path17.extname(realFile)] ?? "application/octet-stream",
9537
9782
  "Content-Length": stat.size,
9538
9783
  "Cache-Control": "no-store"
9539
9784
  });
@@ -9687,7 +9932,7 @@ async function listFilesRecursive(dir, base = "") {
9687
9932
  for (const e of entries) {
9688
9933
  const rel = base ? `${base}/${e.name}` : e.name;
9689
9934
  if (e.isDirectory()) {
9690
- out.push(...await listFilesRecursive(path18.join(dir, e.name), rel));
9935
+ out.push(...await listFilesRecursive(path17.join(dir, e.name), rel));
9691
9936
  } else if (e.isFile()) {
9692
9937
  out.push(rel);
9693
9938
  }
@@ -9704,9 +9949,9 @@ async function readContributedExtensions(extensionsDir) {
9704
9949
  }
9705
9950
  for (const e of entries) {
9706
9951
  if (!e.isDirectory()) continue;
9707
- const extDir = path18.join(extensionsDir, e.name);
9952
+ const extDir = path17.join(extensionsDir, e.name);
9708
9953
  try {
9709
- const pkgRaw = await fs8.readFile(path18.join(extDir, "package.json"), "utf8");
9954
+ const pkgRaw = await fs8.readFile(path17.join(extDir, "package.json"), "utf8");
9710
9955
  const files = await listFilesRecursive(extDir);
9711
9956
  out.push({ dir: e.name, packageJson: JSON.parse(pkgRaw), files });
9712
9957
  } catch {
@@ -9714,9 +9959,13 @@ async function readContributedExtensions(extensionsDir) {
9714
9959
  }
9715
9960
  return out;
9716
9961
  }
9962
+ function workspaceIdOf(identity) {
9963
+ if (!identity?.appId) return null;
9964
+ return (0, miniapp_partition_exports.miniappPartitionKey)(identity.appId, identity.projectPath || null);
9965
+ }
9717
9966
  async function startWorkbenchCoiServer(options) {
9718
- const root = path18.resolve(options.rootDir);
9719
- const contribRoot = options.extensionsDir ? path18.resolve(options.extensionsDir) : null;
9967
+ const root = path17.resolve(options.rootDir);
9968
+ const contribRoot = options.extensionsDir ? path17.resolve(options.extensionsDir) : null;
9720
9969
  const server = http.createServer((req, res) => {
9721
9970
  setIsolationHeaders(res);
9722
9971
  const url = new URL(req.url ?? "/", "http://127.0.0.1");
@@ -9734,6 +9983,10 @@ async function startWorkbenchCoiServer(options) {
9734
9983
  jsonRes(res, 200, options.getFileTypes?.() ?? {});
9735
9984
  return;
9736
9985
  }
9986
+ if (url.pathname === "/__project") {
9987
+ jsonRes(res, 200, { workspaceId: workspaceIdOf(options.getProjectIdentity?.()) });
9988
+ return;
9989
+ }
9737
9990
  if (url.pathname.startsWith("/__contrib/")) {
9738
9991
  if (!contribRoot) {
9739
9992
  res.writeHead(404);
@@ -9875,7 +10128,7 @@ var UpdateManager = class {
9875
10128
 
9876
10129
  // src/main/services/update/github-release-checker.ts
9877
10130
  import fs9 from "fs";
9878
- import path19 from "path";
10131
+ import path18 from "path";
9879
10132
  import https from "https";
9880
10133
  import { app as app12 } from "electron";
9881
10134
  function createGitHubReleaseChecker(opts) {
@@ -9901,10 +10154,10 @@ function createGitHubReleaseChecker(opts) {
9901
10154
  };
9902
10155
  },
9903
10156
  async downloadUpdate(info, onProgress) {
9904
- const tmpDir = path19.join(app12.getPath("temp"), `${opts.repo}-update`);
10157
+ const tmpDir = path18.join(app12.getPath("temp"), `${opts.repo}-update`);
9905
10158
  if (!fs9.existsSync(tmpDir)) fs9.mkdirSync(tmpDir, { recursive: true });
9906
- const fileName = path19.basename(new URL(info.downloadUrl).pathname);
9907
- const filePath = path19.join(tmpDir, fileName);
10159
+ const fileName = path18.basename(new URL(info.downloadUrl).pathname);
10160
+ const filePath = path18.join(tmpDir, fileName);
9908
10161
  await downloadFile(info.downloadUrl, filePath, opts.token, onProgress);
9909
10162
  return filePath;
9910
10163
  }
@@ -10187,7 +10440,7 @@ async function disposeContext(ctx) {
10187
10440
  function createConfiguredMainWindow(config, rendererDir2) {
10188
10441
  const mainWindow = createMainWindow({
10189
10442
  title: config.appName ?? "Dimina DevTools",
10190
- indexHtml: path20.join(rendererDir2, "entries/main/index.html"),
10443
+ indexHtml: path19.join(rendererDir2, "entries/main/index.html"),
10191
10444
  width: config.window?.width,
10192
10445
  height: config.window?.height,
10193
10446
  minWidth: config.window?.minWidth,
@@ -10350,6 +10603,7 @@ async function createDevtoolsRuntime(config = {}, onInstanceCreated) {
10350
10603
  context.internalDevtoolsWindow = createInternalDevtoolsWindow(mainWindow, { isAppQuitting });
10351
10604
  context.registry.add(toDisposable5(() => context.internalDevtoolsWindow?.dispose()));
10352
10605
  context.registry.add(registerInternalDevtoolsIpc(context));
10606
+ context.registry.add(registerTooltipIpc(context));
10353
10607
  context.registry.add((0, simulator_session_policy_exports.setupSimulatorSessionPolicy)());
10354
10608
  context.registry.add(installThemeBackgroundSync());
10355
10609
  if (!config.adapter) context.registry.add(setupCompileWorkerStandby(context));
@@ -10534,8 +10788,8 @@ async function createDevtoolsRuntime(config = {}, onInstanceCreated) {
10534
10788
  bridge: context.bridge
10535
10789
  }));
10536
10790
  }
10537
- const bundleDir = config.editorViewConfig?.bundleDir ?? path20.join(devtoolsPackageRoot, "dist/vscode-workbench");
10538
- if (!fs10.existsSync(path20.join(bundleDir, "index.html"))) {
10791
+ const bundleDir = config.editorViewConfig?.bundleDir ?? path19.join(devtoolsPackageRoot, "dist/vscode-workbench");
10792
+ if (!fs10.existsSync(path19.join(bundleDir, "index.html"))) {
10539
10793
  console.warn(
10540
10794
  `[workbench] editor bundle not found at ${bundleDir} \u2014 skipping embedded editor assembly`
10541
10795
  );
@@ -10544,7 +10798,14 @@ async function createDevtoolsRuntime(config = {}, onInstanceCreated) {
10544
10798
  rootDir: bundleDir,
10545
10799
  getProjectRoot: () => context.workspace.getProjectPath(),
10546
10800
  extensionsDir: config.editorViewConfig?.extensionsDir,
10547
- getFileTypes: () => context.fileTypes
10801
+ getFileTypes: () => context.fileTypes,
10802
+ // Names the editor's VS Code workspace after the active miniapp, so each
10803
+ // project gets its own open-editors/view-state bucket instead of all of
10804
+ // them sharing the one derived from the constant mirror root.
10805
+ getProjectIdentity: () => ({
10806
+ appId: getActiveAppId(),
10807
+ projectPath: context.workspace.getProjectPath()
10808
+ })
10548
10809
  });
10549
10810
  context.registry.add(() => coiServer.close());
10550
10811
  context.registry.add(() => {