@dimina-kit/devtools 0.4.0-dev.20260718095333 → 0.4.0-dev.20260728063215

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 (88) hide show
  1. package/dist/main/app/app.d.ts +10 -1
  2. package/dist/main/app/app.js +78 -2
  3. package/dist/main/app/lifecycle.d.ts +12 -1
  4. package/dist/main/app/lifecycle.js +27 -1
  5. package/dist/main/index.bundle.js +1263 -206
  6. package/dist/main/index.js +49 -1
  7. package/dist/main/ipc/bridge-router.d.ts +36 -0
  8. package/dist/main/ipc/bridge-router.js +56 -0
  9. package/dist/main/ipc/index.d.ts +1 -0
  10. package/dist/main/ipc/index.js +1 -0
  11. package/dist/main/ipc/internal-devtools.d.ts +15 -0
  12. package/dist/main/ipc/internal-devtools.js +9 -0
  13. package/dist/main/runtime/devtools-backend-before-quit.harness.d.ts +61 -0
  14. package/dist/main/runtime/devtools-backend-before-quit.harness.js +356 -0
  15. package/dist/main/runtime/devtools-backend.js +49 -4
  16. package/dist/main/services/compile-standby.js +4 -0
  17. package/dist/main/services/console-forward/cdp-inject.d.ts +18 -0
  18. package/dist/main/services/console-forward/cdp-inject.js +30 -0
  19. package/dist/main/services/console-forward/global-console-mirror.d.ts +33 -0
  20. package/dist/main/services/console-forward/global-console-mirror.js +71 -0
  21. package/dist/main/services/console-forward/global-diagnostics-mirror.d.ts +33 -0
  22. package/dist/main/services/console-forward/global-diagnostics-mirror.js +73 -0
  23. package/dist/main/services/console-forward/index.d.ts +15 -1
  24. package/dist/main/services/console-forward/index.js +42 -2
  25. package/dist/main/services/console-forward/internal-log.d.ts +11 -0
  26. package/dist/main/services/console-forward/internal-log.js +23 -0
  27. package/dist/main/services/console-forward/open-gated-relay.d.ts +67 -0
  28. package/dist/main/services/console-forward/open-gated-relay.js +55 -0
  29. package/dist/main/services/diagnostics/index.d.ts +10 -0
  30. package/dist/main/services/elements-forward/index.js +14 -96
  31. package/dist/main/services/mcp/server.js +24 -2
  32. package/dist/main/services/network-forward/frontend-dispatch.d.ts +64 -0
  33. package/dist/main/services/network-forward/frontend-dispatch.js +113 -8
  34. package/dist/main/services/network-forward/global-body-gate.d.ts +46 -0
  35. package/dist/main/services/network-forward/global-body-gate.js +93 -0
  36. package/dist/main/services/network-forward/global-mirror-test-fixtures.d.ts +48 -0
  37. package/dist/main/services/network-forward/global-mirror-test-fixtures.js +96 -0
  38. package/dist/main/services/network-forward/index.d.ts +31 -0
  39. package/dist/main/services/network-forward/index.js +256 -8
  40. package/dist/main/services/network-forward/user-facing.d.ts +21 -0
  41. package/dist/main/services/network-forward/user-facing.js +50 -0
  42. package/dist/main/services/projects/create-project-service.js +10 -3
  43. package/dist/main/services/update/github-release-checker.js +22 -3
  44. package/dist/main/services/update/update-manager.d.ts +4 -1
  45. package/dist/main/services/update/update-manager.js +30 -5
  46. package/dist/main/services/views/console-filter.d.ts +145 -0
  47. package/dist/main/services/views/console-filter.js +233 -0
  48. package/dist/main/services/views/frontend-bootstrap-gate.d.ts +59 -0
  49. package/dist/main/services/views/frontend-bootstrap-gate.js +117 -0
  50. package/dist/main/services/views/native-simulator-devtools-host.js +138 -30
  51. package/dist/main/services/views/view-manager-devtools-host-test-fixtures.d.ts +76 -0
  52. package/dist/main/services/views/view-manager-devtools-host-test-fixtures.js +182 -0
  53. package/dist/main/services/workbench-context.d.ts +10 -0
  54. package/dist/main/utils/theme.d.ts +10 -6
  55. package/dist/main/utils/theme.js +10 -6
  56. package/dist/main/windows/internal-devtools-window/index.d.ts +66 -0
  57. package/dist/main/windows/internal-devtools-window/index.js +160 -0
  58. package/dist/native-host/render/render.js +89 -73
  59. package/dist/native-host/service/service.js +2 -2
  60. package/dist/preload/windows/host-toolbar-runtime.cjs.map +1 -1
  61. package/dist/preload/windows/simulator.cjs.map +1 -1
  62. package/dist/renderer/assets/index-M5NDq_vi.js +49 -0
  63. package/dist/renderer/assets/{input-c2OcrrZy.js → input-dsgeTmVX.js} +2 -2
  64. package/dist/renderer/assets/ipc-transport-BgFdT9bT.js +9 -0
  65. package/dist/renderer/assets/{popover-kv2qspWz.js → popover-Disfu1cx.js} +2 -2
  66. package/dist/renderer/assets/{select-DKqzMtTh.js → select-DAw1hzkl.js} +2 -2
  67. package/dist/renderer/assets/{settings-dJNKTGr8.js → settings-M_8GFW2M.js} +2 -2
  68. package/dist/renderer/assets/settings-api-DFR5eDl_.js +2 -0
  69. package/dist/renderer/assets/{workbenchSettings-DQ_VP5-W.js → workbenchSettings-CxdXeoOu.js} +2 -2
  70. package/dist/renderer/entries/main/index.html +5 -5
  71. package/dist/renderer/entries/popover/index.html +4 -4
  72. package/dist/renderer/entries/settings/index.html +4 -4
  73. package/dist/renderer/entries/workbench-settings/index.html +3 -3
  74. package/dist/service-host/sync-impls/menu-button-geometry.js +15 -5
  75. package/dist/service-host/sync-impls/menu-button.js +5 -3
  76. package/dist/shared/ipc-channels.d.ts +3 -0
  77. package/dist/shared/ipc-channels.js +6 -0
  78. package/dist/simulator/assets/device-shell-Cs-rmP1f.js +2 -0
  79. package/dist/simulator/assets/device-shell-DOy53Y0s.css +1 -0
  80. package/dist/simulator/assets/{simulator-Cy8c-eA2.js → simulator-BG-5CADK.js} +3 -3
  81. package/dist/simulator/device-shell/menu-button-geometry.js +15 -5
  82. package/dist/simulator/simulator.html +1 -1
  83. package/package.json +7 -7
  84. package/dist/renderer/assets/index-U9F8MrtV.js +0 -49
  85. package/dist/renderer/assets/ipc-transport-CuDJ07aE.js +0 -9
  86. package/dist/renderer/assets/settings-api-qpXKDRXt.js +0 -2
  87. package/dist/simulator/assets/device-shell-C-HZY3bL.css +0 -1
  88. package/dist/simulator/assets/device-shell-Cu1ZPLfe.js +0 -2
@@ -545,6 +545,11 @@ var AppChannel = {
545
545
  var AutomationChannel = {
546
546
  GetPort: "automation:port"
547
547
  };
548
+ var InternalDevtoolsChannel = {
549
+ // Open (or focus, if already open) the internal debug DevTools, hosted in
550
+ // its own dedicated window (see internal-devtools-window/index.ts).
551
+ Open: "internal-devtools:open"
552
+ };
548
553
  var SettingsChannel = {
549
554
  SetVisible: "settings:setVisible",
550
555
  ConfigChanged: "settings:configChanged",
@@ -892,9 +897,9 @@ function registerProjectFsIpc(ctx) {
892
897
  }
893
898
 
894
899
  // src/main/app/app.ts
895
- import { app as app15, BrowserWindow as BrowserWindow8, nativeImage, session as session4 } from "electron";
896
- import fs12 from "fs";
897
- import path24 from "path";
900
+ import { app as app15, BrowserWindow as BrowserWindow9, nativeImage, session as session4 } from "electron";
901
+ import fs13 from "fs";
902
+ import path25 from "path";
898
903
 
899
904
  // src/main/utils/paths.ts
900
905
  import fs3 from "fs";
@@ -1074,13 +1079,268 @@ function wireMainWindowEvents(win, state = {}) {
1074
1079
  return registry;
1075
1080
  }
1076
1081
 
1082
+ // src/main/windows/internal-devtools-window/index.ts
1083
+ import { BrowserWindow as BrowserWindow3, View as View2, WebContentsView as WebContentsView2 } from "electron";
1084
+ function createInternalDevtoolsWindow(target, opts) {
1085
+ let win = null;
1086
+ let hostView = null;
1087
+ const hostChangedHandlers = /* @__PURE__ */ new Set();
1088
+ let currentHost = null;
1089
+ function notifyHostChanged(hostWc) {
1090
+ if (hostWc === currentHost) return;
1091
+ currentHost = hostWc;
1092
+ for (const handler of [...hostChangedHandlers]) {
1093
+ try {
1094
+ handler(hostWc);
1095
+ } catch (err2) {
1096
+ console.warn("[internal-devtools-window] onHostChanged handler threw, other handlers still ran:", err2 instanceof Error ? err2.message : String(err2));
1097
+ }
1098
+ }
1099
+ }
1100
+ function resizeHostView(hostWindow, view) {
1101
+ try {
1102
+ const [width, height] = hostWindow.getContentSize();
1103
+ view.setBounds({ x: 0, y: 0, width, height });
1104
+ } catch {
1105
+ }
1106
+ }
1107
+ function buildOnce() {
1108
+ if (win) return;
1109
+ const hostWindow = new BrowserWindow3({
1110
+ width: 1e3,
1111
+ height: 700,
1112
+ title: "\u5168\u5C40\u8C03\u8BD5",
1113
+ show: false
1114
+ });
1115
+ win = hostWindow;
1116
+ const view = new WebContentsView2();
1117
+ hostView = view;
1118
+ const container = new View2();
1119
+ container.addChildView(view);
1120
+ hostWindow.contentView = container;
1121
+ resizeHostView(hostWindow, view);
1122
+ hostWindow.on("resize", () => resizeHostView(hostWindow, view));
1123
+ hostWindow.on("close", (event) => {
1124
+ if (opts?.isAppQuitting?.()) return;
1125
+ event.preventDefault();
1126
+ hostWindow.hide();
1127
+ notifyHostChanged(null);
1128
+ });
1129
+ hostWindow.on("closed", () => {
1130
+ if (win !== hostWindow) return;
1131
+ win = null;
1132
+ notifyHostChanged(null);
1133
+ });
1134
+ hostWindow.on("hide", () => notifyHostChanged(null));
1135
+ hostWindow.on("show", () => notifyHostChanged(view.webContents));
1136
+ if (!target.webContents.isDestroyed()) {
1137
+ target.webContents.setDevToolsWebContents(view.webContents);
1138
+ target.webContents.openDevTools({ mode: "detach", activate: false });
1139
+ }
1140
+ }
1141
+ return {
1142
+ open() {
1143
+ buildOnce();
1144
+ if (process.env.NODE_ENV === "test") {
1145
+ win.showInactive();
1146
+ } else {
1147
+ win.show();
1148
+ win.focus();
1149
+ }
1150
+ if (hostView) notifyHostChanged(hostView.webContents);
1151
+ },
1152
+ dispose() {
1153
+ if (!win) return;
1154
+ const hostWindow = win;
1155
+ if (!hostWindow.isDestroyed()) hostWindow.destroy();
1156
+ if (win === hostWindow) {
1157
+ win = null;
1158
+ notifyHostChanged(null);
1159
+ }
1160
+ },
1161
+ onHostChanged(handler) {
1162
+ hostChangedHandlers.add(handler);
1163
+ if (currentHost) {
1164
+ queueMicrotask(() => {
1165
+ if (!hostChangedHandlers.has(handler)) return;
1166
+ if (!currentHost) return;
1167
+ try {
1168
+ handler(currentHost);
1169
+ } catch (err2) {
1170
+ console.warn("[internal-devtools-window] onHostChanged catch-up handler threw:", err2 instanceof Error ? err2.message : String(err2));
1171
+ }
1172
+ });
1173
+ }
1174
+ return () => {
1175
+ hostChangedHandlers.delete(handler);
1176
+ };
1177
+ }
1178
+ };
1179
+ }
1180
+
1181
+ // src/main/services/views/inject-when-ready.ts
1182
+ function isFrontendSettled(wc) {
1183
+ try {
1184
+ if (wc.isDestroyed()) return false;
1185
+ const url = wc.getURL();
1186
+ const mainFrameLoading = typeof wc.isLoadingMainFrame === "function" ? wc.isLoadingMainFrame() : wc.isLoading();
1187
+ return !mainFrameLoading && url !== "" && url !== "about:blank";
1188
+ } catch {
1189
+ return false;
1190
+ }
1191
+ }
1192
+ function createLoadDeferredInjector() {
1193
+ const pending = /* @__PURE__ */ new WeakMap();
1194
+ return function injectWhenReady(wc, kind, run) {
1195
+ if (wc.isDestroyed()) return;
1196
+ if (isFrontendSettled(wc)) {
1197
+ run();
1198
+ return;
1199
+ }
1200
+ let kinds = pending.get(wc);
1201
+ if (!kinds) {
1202
+ kinds = /* @__PURE__ */ new Map();
1203
+ pending.set(wc, kinds);
1204
+ }
1205
+ const alreadyHooked = kinds.has(kind);
1206
+ kinds.set(kind, run);
1207
+ if (alreadyHooked) return;
1208
+ wc.once("did-stop-loading", () => {
1209
+ const runner = kinds.get(kind);
1210
+ kinds.delete(kind);
1211
+ if (!runner || wc.isDestroyed()) return;
1212
+ runner();
1213
+ });
1214
+ };
1215
+ }
1216
+
1217
+ // src/main/services/console-forward/open-gated-relay.ts
1218
+ var DEFAULT_INJECT_TIMEOUT_MS = 1e4;
1219
+ function createOpenGatedRelay(onHostChanged, subscribe, inject, opts) {
1220
+ const injectTimeoutMs = opts?.injectTimeoutMs ?? DEFAULT_INJECT_TIMEOUT_MS;
1221
+ const state = /* @__PURE__ */ new WeakMap();
1222
+ let generationSeq = 0;
1223
+ const inFlightTimers = /* @__PURE__ */ new Set();
1224
+ let live = null;
1225
+ function deliver(entry) {
1226
+ if (state.has(entry)) return;
1227
+ const generation = ++generationSeq;
1228
+ state.set(entry, { phase: "pending", generation });
1229
+ const timer = setTimeout(() => {
1230
+ inFlightTimers.delete(timer);
1231
+ const cur = state.get(entry);
1232
+ if (cur && cur.phase === "pending" && cur.generation === generation) state.delete(entry);
1233
+ }, injectTimeoutMs);
1234
+ timer.unref?.();
1235
+ inFlightTimers.add(timer);
1236
+ const settle = (ok2) => {
1237
+ clearTimeout(timer);
1238
+ inFlightTimers.delete(timer);
1239
+ const cur = state.get(entry);
1240
+ if (!cur || cur.phase !== "pending" || cur.generation !== generation) return;
1241
+ if (ok2) state.set(entry, { phase: "done", generation });
1242
+ else state.delete(entry);
1243
+ };
1244
+ Promise.resolve().then(() => inject(entry)).then((ok2) => settle(ok2 === true), () => settle(false));
1245
+ }
1246
+ const unregister = onHostChanged((host) => {
1247
+ live?.dispose();
1248
+ live = host !== null ? subscribe(deliver, { replay: true }) : null;
1249
+ });
1250
+ return {
1251
+ dispose: () => {
1252
+ for (const timer of inFlightTimers) clearTimeout(timer);
1253
+ inFlightTimers.clear();
1254
+ live?.dispose();
1255
+ live = null;
1256
+ unregister();
1257
+ }
1258
+ };
1259
+ }
1260
+
1261
+ // src/main/services/console-forward/cdp-inject.ts
1262
+ function injectViaCdp(broker, target, script, warnTag) {
1263
+ const lease = broker.acquire(target);
1264
+ if (!lease) return false;
1265
+ return lease.send("Runtime.evaluate", { expression: script }).then(
1266
+ (result) => {
1267
+ if (result?.exceptionDetails) {
1268
+ console.warn(`[${warnTag}] Runtime.evaluate reported an exception, will retry on next reopen`);
1269
+ return false;
1270
+ }
1271
+ return true;
1272
+ },
1273
+ (err2) => {
1274
+ console.warn(`[${warnTag}] injection failed, will retry on next reopen:`, err2 instanceof Error ? err2.message : String(err2));
1275
+ return false;
1276
+ }
1277
+ );
1278
+ }
1279
+
1280
+ // src/main/services/console-forward/global-console-mirror.ts
1281
+ var FORWARDABLE_LEVELS = /* @__PURE__ */ new Set(["log", "warn", "error", "info", "debug"]);
1282
+ function buildMirrorScript(entry) {
1283
+ const method = FORWARDABLE_LEVELS.has(entry.level ?? "") ? entry.level : "log";
1284
+ const tag = entry.source === "render" ? "[render]" : "[service]";
1285
+ const argsJson = JSON.stringify(entry.args ?? []);
1286
+ return `(()=>{try{const a=JSON.parse(${JSON.stringify(argsJson)});console[${JSON.stringify(method)}](${JSON.stringify(tag)},...a)}catch(_){}})()`;
1287
+ }
1288
+ function createGlobalConsoleMirror(forwarder, target, onHostChanged, opts) {
1289
+ function inject(entry) {
1290
+ if (target.isDestroyed()) return false;
1291
+ if (!isFrontendSettled(target)) return false;
1292
+ let script;
1293
+ try {
1294
+ script = buildMirrorScript(entry);
1295
+ } catch {
1296
+ return false;
1297
+ }
1298
+ return injectViaCdp(opts.broker, target, script, "global-console-mirror");
1299
+ }
1300
+ return createOpenGatedRelay(
1301
+ onHostChanged,
1302
+ (sink, opts2) => forwarder.subscribe(sink, opts2),
1303
+ inject
1304
+ );
1305
+ }
1306
+
1307
+ // src/main/services/console-forward/global-diagnostics-mirror.ts
1308
+ var DIAGNOSTIC_CONSOLE_CALL = {
1309
+ error: "console.error",
1310
+ warn: "console.warn",
1311
+ info: "console.info"
1312
+ };
1313
+ function buildMirrorScript2(severity, message) {
1314
+ const call = DIAGNOSTIC_CONSOLE_CALL[severity];
1315
+ const argsJson = JSON.stringify([`[dimina-kit] ${message}`]);
1316
+ return `(()=>{try{const a=JSON.parse(${JSON.stringify(argsJson)});${call}(...a)}catch(_){}})()`;
1317
+ }
1318
+ function createGlobalDiagnosticsMirror(diagnostics, target, onHostChanged, opts) {
1319
+ function inject(d) {
1320
+ if (target.isDestroyed()) return false;
1321
+ if (!isFrontendSettled(target)) return false;
1322
+ let script;
1323
+ try {
1324
+ script = buildMirrorScript2(d.severity, d.message);
1325
+ } catch {
1326
+ return false;
1327
+ }
1328
+ return injectViaCdp(opts.broker, target, script, "global-diagnostics-mirror");
1329
+ }
1330
+ return createOpenGatedRelay(
1331
+ onHostChanged,
1332
+ (sink, opts2) => diagnostics.subscribe(sink, opts2),
1333
+ inject
1334
+ );
1335
+ }
1336
+
1077
1337
  // src/main/app/lifecycle.ts
1078
1338
  import { app as app4, globalShortcut as globalShortcut2 } from "electron";
1079
1339
  var appIsQuitting = false;
1080
1340
  function isAppQuitting() {
1081
1341
  return appIsQuitting;
1082
1342
  }
1083
- function registerAppLifecycle() {
1343
+ function registerAppLifecycle(onBeforeQuit) {
1084
1344
  app4.on("window-all-closed", () => {
1085
1345
  globalShortcut2.unregisterAll();
1086
1346
  app4.quit();
@@ -1088,6 +1348,11 @@ function registerAppLifecycle() {
1088
1348
  app4.on("before-quit", () => {
1089
1349
  appIsQuitting = true;
1090
1350
  globalShortcut2.unregisterAll();
1351
+ try {
1352
+ onBeforeQuit?.();
1353
+ } catch (err2) {
1354
+ console.error("[lifecycle] onBeforeQuit handler threw:", err2);
1355
+ }
1091
1356
  });
1092
1357
  }
1093
1358
 
@@ -1569,7 +1834,7 @@ function createPlacementReconciler(ctx) {
1569
1834
  }
1570
1835
 
1571
1836
  // src/main/services/views/workbench-view.ts
1572
- import { nativeTheme as nativeTheme3, WebContentsView as WebContentsView2 } from "electron";
1837
+ import { nativeTheme as nativeTheme3, WebContentsView as WebContentsView3 } from "electron";
1573
1838
 
1574
1839
  // src/shared/view-ids.ts
1575
1840
  var VIEW_ID = {
@@ -1626,7 +1891,7 @@ function createWorkbenchView(ctx, reconciler) {
1626
1891
  }
1627
1892
  async function attachWorkbench(url) {
1628
1893
  if (workbenchView) return;
1629
- const view = new WebContentsView2({
1894
+ const view = new WebContentsView3({
1630
1895
  webPreferences: {
1631
1896
  nodeIntegration: false,
1632
1897
  contextIsolation: true,
@@ -1750,7 +2015,7 @@ function createWorkbenchView(ctx, reconciler) {
1750
2015
  }
1751
2016
 
1752
2017
  // src/main/services/views/native-simulator-devtools-host.ts
1753
- import { WebContentsView as WebContentsView3 } from "electron";
2018
+ import { WebContentsView as WebContentsView4, webContents as electronWebContents } from "electron";
1754
2019
 
1755
2020
  // src/shared/open-in-editor-resource-path.ts
1756
2021
  function decodePathname(pathname) {
@@ -2211,40 +2476,146 @@ function buildCustomizeTabsScript(keptIds = DEVTOOLS_KEPT_VIEW_IDS) {
2211
2476
  }catch(_){}})()`;
2212
2477
  }
2213
2478
 
2214
- // src/main/services/views/inject-when-ready.ts
2215
- function isFrontendSettled(wc) {
2216
- try {
2217
- if (wc.isDestroyed()) return false;
2218
- const url = wc.getURL();
2219
- const mainFrameLoading = typeof wc.isLoadingMainFrame === "function" ? wc.isLoadingMainFrame() : wc.isLoading();
2220
- return !mainFrameLoading && url !== "" && url !== "about:blank";
2221
- } catch {
2222
- return false;
2223
- }
2479
+ // src/main/services/views/console-filter.ts
2480
+ var DEFAULT_INTERNAL_LOG_FILTER = "-/^\\[service\\]/";
2481
+ function buildConsoleFilterScript(negativeFilter = DEFAULT_INTERNAL_LOG_FILTER) {
2482
+ const keyJson = JSON.stringify("console.text-filter");
2483
+ const markKeyJson = JSON.stringify("console.text-filter.dimina-default");
2484
+ const valueJsonLiteral = JSON.stringify(JSON.stringify(negativeFilter));
2485
+ return `(function(){try{
2486
+ var IFH = globalThis.InspectorFrontendHost;
2487
+ if (!IFH || typeof IFH.getPreferences !== 'function' || typeof IFH.setPreference !== 'function') return;
2488
+ IFH.getPreferences(function(prefs){
2489
+ try {
2490
+ var KEY = ${keyJson};
2491
+ var MARK_KEY = ${markKeyJson};
2492
+ var VALUE = ${valueJsonLiteral};
2493
+ var existing = prefs ? prefs[KEY] : undefined;
2494
+ var mark = prefs ? prefs[MARK_KEY] : undefined;
2495
+ var isUnset = existing === undefined || existing === null || existing === '' || existing === '""';
2496
+ var isOurStaleDefault = !isUnset && mark !== undefined && mark !== null && existing === mark;
2497
+ if (isUnset || isOurStaleDefault) {
2498
+ IFH.setPreference(KEY, VALUE);
2499
+ IFH.setPreference(MARK_KEY, VALUE);
2500
+ }
2501
+ } catch(_){}
2502
+ });
2503
+ }catch(_){}})()`;
2224
2504
  }
2225
- function createLoadDeferredInjector() {
2226
- const pending = /* @__PURE__ */ new WeakMap();
2227
- return function injectWhenReady(wc, kind, run) {
2228
- if (wc.isDestroyed()) return;
2229
- if (isFrontendSettled(wc)) {
2230
- run();
2231
- return;
2232
- }
2233
- let kinds = pending.get(wc);
2234
- if (!kinds) {
2235
- kinds = /* @__PURE__ */ new Map();
2236
- pending.set(wc, kinds);
2505
+ var LIVE_FILTER_POLL_MAX_ATTEMPTS = 100;
2506
+ var LIVE_FILTER_POLL_INTERVAL_MS = 100;
2507
+ function buildLiveConsoleFilterScript(negativeFilter = DEFAULT_INTERNAL_LOG_FILTER) {
2508
+ const filterJson = JSON.stringify(negativeFilter);
2509
+ const maxAttempts = JSON.stringify(LIVE_FILTER_POLL_MAX_ATTEMPTS);
2510
+ const intervalMs = JSON.stringify(LIVE_FILTER_POLL_INTERVAL_MS);
2511
+ return `(function(){
2512
+ var VALUE = ${filterJson};
2513
+ var attempts = 0;
2514
+ function bootstrapReady() {
2515
+ try {
2516
+ var eui = globalThis.EUI;
2517
+ if (!eui || !eui.ShortcutRegistry || !eui.ShortcutRegistry.ShortcutRegistry) return false;
2518
+ eui.ShortcutRegistry.ShortcutRegistry.instance();
2519
+ return true;
2520
+ } catch (_) { return false; }
2521
+ }
2522
+ function tryApply() {
2523
+ attempts++;
2524
+ var scheduleRetry = attempts < ${maxAttempts};
2525
+ // In-realm bootstrap probe FIRST (defense in depth on top of the
2526
+ // main-process whenFrontendBootstrapped gate): touching
2527
+ // Console.ConsoleView.instance() before the front-end's own
2528
+ // MainImpl bootstrap completes constructs IssuesManager early and
2529
+ // permanently kills that bootstrap (ensureFirst conflict) \u2014 the probe
2530
+ // throws BEFORE constructing anything, so a not-ready tick costs
2531
+ // nothing and never touches ConsoleView.
2532
+ if (!bootstrapReady()) {
2533
+ if (scheduleRetry) { setTimeout(tryApply, ${intervalMs}); return; }
2534
+ console.warn('[console-filter] gave up applying the live Console filter after ' + attempts + ' attempts \u2014 the front-end bootstrap never completed');
2535
+ return;
2536
+ }
2537
+ try {
2538
+ var ConsoleNS = globalThis.Console;
2539
+ var view = ConsoleNS && ConsoleNS.ConsoleView ? ConsoleNS.ConsoleView.instance() : null;
2540
+ var f = view ? view.filter : null;
2541
+ if (!f || !f.textFilterUI || typeof f.textFilterUI.setValue !== 'function' || typeof f.textFilterUI.value !== 'function') {
2542
+ if (scheduleRetry) { setTimeout(tryApply, ${intervalMs}); return; }
2543
+ console.warn('[console-filter] gave up applying the live Console filter after ' + attempts + ' attempts \u2014 Console.ConsoleView never became usable');
2544
+ return;
2545
+ }
2546
+ var current = f.textFilterUI.value();
2547
+ var isUnset = current === undefined || current === null || current === '';
2548
+ var isOurDefault = current === VALUE;
2549
+ if (isUnset || isOurDefault) {
2550
+ f.textFilterUI.setValue(VALUE);
2551
+ if (typeof f.updateCurrentFilter === 'function') f.updateCurrentFilter();
2552
+ if (typeof f.onFilterChanged === 'function') f.onFilterChanged();
2553
+ }
2554
+ // Either applied, or a real user customization was detected \u2014 both
2555
+ // are terminal: nothing left for a later retry to accomplish.
2556
+ } catch(_) {
2557
+ if (scheduleRetry) setTimeout(tryApply, ${intervalMs});
2558
+ }
2237
2559
  }
2238
- const alreadyHooked = kinds.has(kind);
2239
- kinds.set(kind, run);
2240
- if (alreadyHooked) return;
2241
- wc.once("did-stop-loading", () => {
2242
- const runner = kinds.get(kind);
2243
- kinds.delete(kind);
2244
- if (!runner || wc.isDestroyed()) return;
2245
- runner();
2246
- });
2247
- };
2560
+ tryApply();
2561
+ })()`;
2562
+ }
2563
+
2564
+ // src/main/services/views/frontend-bootstrap-gate.ts
2565
+ var FRONTEND_BOOTSTRAP_PROBE_SCRIPT = `(() => {
2566
+ try {
2567
+ const eui = globalThis.EUI
2568
+ if (!eui || !eui.ShortcutRegistry || !eui.ShortcutRegistry.ShortcutRegistry) return false
2569
+ eui.ShortcutRegistry.ShortcutRegistry.instance()
2570
+ return true
2571
+ } catch (_) {
2572
+ return false
2573
+ }
2574
+ })()`;
2575
+ var DEFAULT_TIMEOUT_MS = 45e3;
2576
+ var DEFAULT_INTERVAL_MS = 150;
2577
+ function whenFrontendBootstrapped(wc, opts) {
2578
+ const timeoutMs = opts?.timeoutMs ?? DEFAULT_TIMEOUT_MS;
2579
+ const intervalMs = opts?.intervalMs ?? DEFAULT_INTERVAL_MS;
2580
+ return new Promise((resolve) => {
2581
+ let timer = null;
2582
+ let settled = false;
2583
+ const finish = (ready) => {
2584
+ if (settled) return;
2585
+ settled = true;
2586
+ clearTimeout(deadline);
2587
+ if (timer) {
2588
+ clearTimeout(timer);
2589
+ timer = null;
2590
+ }
2591
+ resolve(ready);
2592
+ };
2593
+ const deadline = setTimeout(() => {
2594
+ console.warn(`[frontend-bootstrap-gate] front-end bootstrap probe never reported ready within ${timeoutMs}ms \u2014 bootstrap-gated injections stay skipped for this host`);
2595
+ finish(false);
2596
+ }, timeoutMs);
2597
+ deadline.unref?.();
2598
+ const attempt = () => {
2599
+ if (wc.isDestroyed()) {
2600
+ finish(false);
2601
+ return;
2602
+ }
2603
+ Promise.resolve().then(() => wc.executeJavaScript(FRONTEND_BOOTSTRAP_PROBE_SCRIPT)).then((ready) => ready === true, () => false).then((ready) => {
2604
+ if (settled) return;
2605
+ if (wc.isDestroyed()) {
2606
+ finish(false);
2607
+ return;
2608
+ }
2609
+ if (ready) {
2610
+ finish(true);
2611
+ return;
2612
+ }
2613
+ timer = setTimeout(attempt, intervalMs);
2614
+ timer.unref?.();
2615
+ });
2616
+ };
2617
+ attempt();
2618
+ });
2248
2619
  }
2249
2620
 
2250
2621
  // src/main/services/network-forward/index.ts
@@ -2393,15 +2764,174 @@ var PrefetchCache = class {
2393
2764
  total -= e.size;
2394
2765
  }
2395
2766
  }
2396
- };
2397
-
2398
- // src/main/services/network-forward/frontend-dispatch.ts
2399
- var PROBE_DEVTOOLS_API = `(window.DevToolsAPI && typeof window.DevToolsAPI.dispatchMessage === 'function')`;
2400
- var MAX_SINGLE_DISPATCH_CHARS = 1e6;
2401
- var CHUNK_CHARS = 256 * 1024;
2402
- function buildChunkedDispatchScript(chunks, totalSize) {
2403
- const arr = JSON.stringify(chunks);
2404
- return `(()=>{try{if(!(window.DevToolsAPI&&typeof window.DevToolsAPI.dispatchMessageChunk==='function'))return false;const cs=JSON.parse(${JSON.stringify(arr)});for(let i=0;i<cs.length;i++){try{if(i===0){window.DevToolsAPI.dispatchMessageChunk(cs[i], ${totalSize})}else{window.DevToolsAPI.dispatchMessageChunk(cs[i])}}catch(_){}}return true;}catch(_){return false}})()`;
2767
+ };
2768
+
2769
+ // src/main/services/network-forward/frontend-dispatch.ts
2770
+ var PROBE_DEVTOOLS_API = `(window.DevToolsAPI && typeof window.DevToolsAPI.dispatchMessage === 'function')`;
2771
+ var MAX_SINGLE_DISPATCH_CHARS = 1e6;
2772
+ var CHUNK_CHARS = 256 * 1024;
2773
+ function buildChunkedDispatchScript(chunks, totalSize) {
2774
+ const arr = JSON.stringify(chunks);
2775
+ return `(()=>{try{if(!(window.DevToolsAPI&&typeof window.DevToolsAPI.dispatchMessageChunk==='function'))return false;const cs=JSON.parse(${JSON.stringify(arr)});for(let i=0;i<cs.length;i++){try{if(i===0){window.DevToolsAPI.dispatchMessageChunk(cs[i], ${totalSize})}else{window.DevToolsAPI.dispatchMessageChunk(cs[i])}}catch(_){}}return true;}catch(_){return false}})()`;
2776
+ }
2777
+ function buildSingleDispatchScript(message) {
2778
+ return `(()=>{try{if(!${PROBE_DEVTOOLS_API})return false;window.DevToolsAPI.dispatchMessage(JSON.parse(${JSON.stringify(message)}));return true;}catch(_){return false}})()`;
2779
+ }
2780
+ function createFrontendReplyChannel(hostWc, isDisposed) {
2781
+ function dispatchToFrontend(message) {
2782
+ if (isDisposed() || hostWc.isDestroyed()) return;
2783
+ if (!isFrontendSettled(hostWc)) return;
2784
+ let json;
2785
+ try {
2786
+ json = JSON.stringify(message);
2787
+ } catch {
2788
+ return;
2789
+ }
2790
+ if (json.length > MAX_SINGLE_DISPATCH_CHARS) {
2791
+ const chunks = [];
2792
+ for (let i = 0; i < json.length; i += CHUNK_CHARS) chunks.push(json.slice(i, i + CHUNK_CHARS));
2793
+ let script2;
2794
+ try {
2795
+ script2 = buildChunkedDispatchScript(chunks, json.length);
2796
+ } catch {
2797
+ return;
2798
+ }
2799
+ hostWc.executeJavaScript(script2, true).catch(() => {
2800
+ });
2801
+ return;
2802
+ }
2803
+ let script;
2804
+ try {
2805
+ script = buildSingleDispatchScript(json);
2806
+ } catch {
2807
+ return;
2808
+ }
2809
+ hostWc.executeJavaScript(script, true).catch(() => {
2810
+ });
2811
+ }
2812
+ function replyResult(cmd, result) {
2813
+ const msg = { id: cmd.id, result };
2814
+ if (cmd.sessionId) msg.sessionId = cmd.sessionId;
2815
+ dispatchToFrontend(msg);
2816
+ }
2817
+ function replyError(cmd, message) {
2818
+ const msg = { id: cmd.id, error: { code: -32e3, message } };
2819
+ if (cmd.sessionId) msg.sessionId = cmd.sessionId;
2820
+ dispatchToFrontend(msg);
2821
+ }
2822
+ return { dispatchToFrontend, replyResult, replyError };
2823
+ }
2824
+ function drainOutboundBatch(batch, handle) {
2825
+ if (!Array.isArray(batch)) return;
2826
+ for (const raw of batch) {
2827
+ if (!raw || typeof raw !== "object") continue;
2828
+ const cmd = raw;
2829
+ if (typeof cmd.method !== "string") continue;
2830
+ handle(cmd);
2831
+ }
2832
+ }
2833
+ function answerNetworkBodyCommand(cmd, provider, reply) {
2834
+ const requestId = cmd.params?.requestId;
2835
+ if (!provider || typeof requestId !== "string") {
2836
+ reply.replyError(cmd, "No resource with given identifier found");
2837
+ return;
2838
+ }
2839
+ const lookup = cmd.method === "Network.getRequestPostData" ? provider.getRequestPostData(requestId) : provider.getResponseBody(requestId);
2840
+ lookup.then(
2841
+ (result) => reply.replyResult(cmd, result),
2842
+ (err2) => reply.replyError(cmd, err2 instanceof Error ? err2.message : String(err2))
2843
+ );
2844
+ }
2845
+
2846
+ // src/main/services/network-forward/user-facing.ts
2847
+ var USER_FACING_SCHEMES = /* @__PURE__ */ new Set(["http:", "https:", "ws:", "wss:"]);
2848
+ function isUserFacingRequest(url, internalOrigins) {
2849
+ let parsed;
2850
+ try {
2851
+ parsed = new URL(url);
2852
+ } catch {
2853
+ return true;
2854
+ }
2855
+ if (!USER_FACING_SCHEMES.has(parsed.protocol)) return false;
2856
+ for (const baseUrl of internalOrigins ?? []) {
2857
+ if (!baseUrl) continue;
2858
+ try {
2859
+ if (parsed.origin === new URL(baseUrl).origin) return false;
2860
+ } catch {
2861
+ }
2862
+ }
2863
+ return true;
2864
+ }
2865
+
2866
+ // src/main/services/network-forward/global-body-gate.ts
2867
+ var NETWORK_BODY_METHODS = ["Network.getResponseBody", "Network.getRequestPostData"];
2868
+ var DRAIN_INTERVAL_MS = 150;
2869
+ function buildNetworkOnlyHookScript() {
2870
+ const netMethods = JSON.stringify(NETWORK_BODY_METHODS);
2871
+ const vprefix = JSON.stringify(VIRTUAL_REQUEST_ID_PREFIX);
2872
+ return `(function(){try{
2873
+ if (globalThis.__diminaGlobalNetworkHookInstalled) return 'already';
2874
+ var OUT = (globalThis.__diminaGlobalNetworkOutbound = globalThis.__diminaGlobalNetworkOutbound || []);
2875
+ var NET_METHODS = ${netMethods};
2876
+ var VPREFIX = ${vprefix};
2877
+ function isNetworkBody(m){
2878
+ if (!m || !m.method) return false;
2879
+ if (NET_METHODS.indexOf(m.method) < 0) return false;
2880
+ return !!(m.params && typeof m.params.requestId === 'string' && m.params.requestId.indexOf(VPREFIX) === 0);
2881
+ }
2882
+ var IFH = globalThis.InspectorFrontendHost;
2883
+ if (IFH && typeof IFH.sendMessageToBackend === 'function' && !IFH.__diminaGlobalNetworkWrapped){
2884
+ var origSend = IFH.sendMessageToBackend.bind(IFH);
2885
+ IFH.sendMessageToBackend = function(message){
2886
+ try {
2887
+ var m = (typeof message === 'string') ? JSON.parse(message) : message;
2888
+ if (isNetworkBody(m)){
2889
+ OUT.push({ id: (m && typeof m.id === 'number') ? m.id : null,
2890
+ method: m.method, params: m.params || {},
2891
+ sessionId: (m && m.sessionId) ? m.sessionId : null });
2892
+ return;
2893
+ }
2894
+ } catch(_){ /* fall through to original on any parse hiccup */ }
2895
+ return origSend(message);
2896
+ };
2897
+ IFH.__diminaGlobalNetworkWrapped = true;
2898
+ globalThis.__diminaGlobalNetworkHookInstalled = true;
2899
+ return 'installed';
2900
+ }
2901
+ return 'partial';
2902
+ }catch(e){ return 'error:' + (e && e.message); }})()`;
2903
+ }
2904
+ function buildReconcileScript() {
2905
+ return `(function(){var status; try { status = ${buildNetworkOnlyHookScript()}; } catch(e){ status = 'error:'+(e&&e.message); }var batch = []; try { if (globalThis.__diminaGlobalNetworkOutbound) batch = globalThis.__diminaGlobalNetworkOutbound.splice(0); } catch(_){}return { status: status, batch: batch };})()`;
2906
+ }
2907
+ function installGlobalNetworkBodyGate(hostWc, bodies) {
2908
+ let disposed = false;
2909
+ let reconcileTimer = null;
2910
+ const reply = createFrontendReplyChannel(hostWc, () => disposed);
2911
+ function handleOutbound(batch) {
2912
+ drainOutboundBatch(batch, (cmd) => answerNetworkBodyCommand(cmd, bodies, reply));
2913
+ }
2914
+ reconcileTimer = setInterval(() => {
2915
+ if (disposed || hostWc.isDestroyed()) {
2916
+ stop();
2917
+ return;
2918
+ }
2919
+ if (!isFrontendSettled(hostWc)) return;
2920
+ hostWc.executeJavaScript(buildReconcileScript()).then((res) => {
2921
+ if (disposed) return;
2922
+ const r = res ?? {};
2923
+ handleOutbound(r.batch);
2924
+ }).catch(() => {
2925
+ });
2926
+ }, DRAIN_INTERVAL_MS);
2927
+ function stop() {
2928
+ disposed = true;
2929
+ if (reconcileTimer) {
2930
+ clearInterval(reconcileTimer);
2931
+ reconcileTimer = null;
2932
+ }
2933
+ }
2934
+ return stop;
2405
2935
  }
2406
2936
 
2407
2937
  // src/main/services/network-forward/index.ts
@@ -2561,6 +3091,122 @@ function createNetworkForwarder(bridge) {
2561
3091
  const broker = bridge.broker ?? createCdpSessionBroker({ connections: bridge.connections });
2562
3092
  let devtoolsWc = null;
2563
3093
  let devtoolsHostDisposable = null;
3094
+ let globalDevtoolsWc = null;
3095
+ let globalDevtoolsHostDisposable = null;
3096
+ let globalBodyGateStop = null;
3097
+ const MAX_GLOBAL_PENDING_QUEUE = 2e3;
3098
+ let globalPendingQueue = [];
3099
+ let globalPendingOverflowWarned = false;
3100
+ let globalFlushTimer = null;
3101
+ const GLOBAL_FLUSH_POLL_MAX_MS = 6e4;
3102
+ function clearGlobalPending() {
3103
+ globalPendingQueue = [];
3104
+ globalPendingOverflowWarned = false;
3105
+ if (globalFlushTimer) {
3106
+ clearTimeout(globalFlushTimer);
3107
+ globalFlushTimer = null;
3108
+ }
3109
+ }
3110
+ function scheduleGlobalFlush(startedAt = Date.now()) {
3111
+ if (globalFlushTimer) return;
3112
+ if (Date.now() - startedAt >= GLOBAL_FLUSH_POLL_MAX_MS) return;
3113
+ globalFlushTimer = setTimeout(() => {
3114
+ globalFlushTimer = null;
3115
+ if (globalPendingQueue.length === 0) return;
3116
+ if (!globalDevtoolsWc || globalDevtoolsWc.isDestroyed()) {
3117
+ clearGlobalPending();
3118
+ return;
3119
+ }
3120
+ if (!isFrontendSettled(globalDevtoolsWc)) {
3121
+ scheduleGlobalFlush(startedAt);
3122
+ return;
3123
+ }
3124
+ flushGlobalPending();
3125
+ }, READY_RETRY_MS);
3126
+ globalFlushTimer.unref?.();
3127
+ }
3128
+ function flushGlobalPending() {
3129
+ if (globalPendingQueue.length === 0) return;
3130
+ const target = globalDevtoolsWc;
3131
+ if (!target || target.isDestroyed()) {
3132
+ clearGlobalPending();
3133
+ return;
3134
+ }
3135
+ while (globalPendingQueue.length > 0) {
3136
+ const { batch, chunked, remaining } = packDispatchBatch(globalPendingQueue, MAX_SINGLE_DISPATCH_CHARS, MAX_BATCH_CHARS);
3137
+ globalPendingQueue = remaining;
3138
+ for (const msg of chunked) dispatchChunked(target, msg);
3139
+ if (batch.length > 0) {
3140
+ target.executeJavaScript(buildDispatchScript(batch), true).catch(() => {
3141
+ });
3142
+ }
3143
+ }
3144
+ globalPendingOverflowWarned = false;
3145
+ }
3146
+ function enqueueGlobalPending(json) {
3147
+ if (globalPendingQueue.length >= MAX_GLOBAL_PENDING_QUEUE) {
3148
+ globalPendingQueue.shift();
3149
+ if (!globalPendingOverflowWarned) {
3150
+ globalPendingOverflowWarned = true;
3151
+ console.warn(`[network-forward] global mirror queue overflow (cap ${MAX_GLOBAL_PENDING_QUEUE}): dropping oldest events while the debug window front-end is still loading`);
3152
+ }
3153
+ }
3154
+ globalPendingQueue.push(json);
3155
+ scheduleGlobalFlush();
3156
+ }
3157
+ function applyGlobalDevtoolsHost(host) {
3158
+ globalDevtoolsHostDisposable?.dispose();
3159
+ globalDevtoolsHostDisposable = null;
3160
+ globalBodyGateStop?.();
3161
+ globalBodyGateStop = null;
3162
+ clearGlobalPending();
3163
+ globalDevtoolsWc = host && !host.isDestroyed() ? host : null;
3164
+ if (!globalDevtoolsWc) return;
3165
+ const target = globalDevtoolsWc;
3166
+ const onHostDestroyed = () => {
3167
+ if (globalDevtoolsWc === target) globalDevtoolsWc = null;
3168
+ globalBodyGateStop?.();
3169
+ globalBodyGateStop = null;
3170
+ clearGlobalPending();
3171
+ };
3172
+ const reg = bridge.connections;
3173
+ if (reg && typeof target.once === "function") {
3174
+ const owned = reg.acquire(target).own(onHostDestroyed);
3175
+ globalDevtoolsHostDisposable = toDisposable3(() => owned.dispose());
3176
+ } else {
3177
+ if (typeof target.once === "function") target.once("destroyed", onHostDestroyed);
3178
+ globalDevtoolsHostDisposable = toDisposable3(() => {
3179
+ try {
3180
+ target.removeListener?.("destroyed", onHostDestroyed);
3181
+ } catch {
3182
+ }
3183
+ });
3184
+ }
3185
+ globalBodyGateStop = installGlobalNetworkBodyGate(target, {
3186
+ getResponseBody: (requestId) => bodyCache.lookup(requestId),
3187
+ getRequestPostData: (requestId) => postDataCache.lookup(requestId)
3188
+ });
3189
+ }
3190
+ function dispatchToGlobal(method, params) {
3191
+ if (!globalDevtoolsWc || globalDevtoolsWc.isDestroyed()) return;
3192
+ let json;
3193
+ try {
3194
+ json = JSON.stringify({ method, params });
3195
+ } catch {
3196
+ return;
3197
+ }
3198
+ if (!isFrontendSettled(globalDevtoolsWc)) {
3199
+ enqueueGlobalPending(json);
3200
+ return;
3201
+ }
3202
+ flushGlobalPending();
3203
+ if (json.length > MAX_SINGLE_DISPATCH_CHARS) {
3204
+ dispatchChunked(globalDevtoolsWc, json);
3205
+ return;
3206
+ }
3207
+ globalDevtoolsWc.executeJavaScript(buildDispatchScript([json]), true).catch(() => {
3208
+ });
3209
+ }
2564
3210
  let sink = "idle";
2565
3211
  let probeConsoleBuffer = [];
2566
3212
  let readyTimeoutTimer = null;
@@ -2770,10 +3416,12 @@ function createNetworkForwarder(bridge) {
2770
3416
  function wireNetworkCapture(wc, source, attach, epoch) {
2771
3417
  const ns = new RequestIdNamespace(epoch);
2772
3418
  const pending = /* @__PURE__ */ new Map();
3419
+ const userFacingByRawId = /* @__PURE__ */ new Map();
2773
3420
  const postDataWanted = /* @__PURE__ */ new Set();
2774
3421
  const prefetchBodies = (rawId, encodedDataLength) => {
2775
- if (sink === "degraded") return;
2776
- if (sink === "idle" && !resolveDevtoolsWc()) return;
3422
+ const userSinkUsable = sink !== "degraded" && !(sink === "idle" && !resolveDevtoolsWc());
3423
+ const globalUsable = globalDevtoolsWc !== null && !globalDevtoolsWc.isDestroyed();
3424
+ if (!userSinkUsable && !globalUsable) return;
2777
3425
  const virtualId = ns.resolve(rawId);
2778
3426
  const knownOversized = typeof encodedDataLength === "number" && encodedDataLength > DEFAULT_PER_ENTRY_MAX_CHARS;
2779
3427
  if (!knownOversized) {
@@ -2807,20 +3455,25 @@ function createNetworkForwarder(bridge) {
2807
3455
  const req = pending.get(p.requestId);
2808
3456
  if (req) req.status = p.response?.status ?? 0;
2809
3457
  }
3458
+ function retirePending(rawId) {
3459
+ userFacingByRawId.delete(rawId);
3460
+ const req = pending.get(rawId);
3461
+ if (!req) return void 0;
3462
+ pending.delete(rawId);
3463
+ return req;
3464
+ }
2810
3465
  function onLoadingFinished(params) {
2811
3466
  const p = params;
2812
3467
  if (typeof p?.requestId === "string") prefetchBodies(p.requestId, p.encodedDataLength);
2813
- const req = pending.get(p.requestId);
3468
+ const req = retirePending(p?.requestId);
2814
3469
  if (!req) return;
2815
- pending.delete(p.requestId);
2816
3470
  maybeFallback({ source, url: req.url, method: req.method, status: req.status });
2817
3471
  }
2818
3472
  function onLoadingFailed(params) {
2819
3473
  const p = params;
2820
3474
  postDataWanted.delete(p?.requestId);
2821
- const req = pending.get(p.requestId);
3475
+ const req = retirePending(p?.requestId);
2822
3476
  if (!req) return;
2823
- pending.delete(p.requestId);
2824
3477
  maybeFallback({
2825
3478
  source,
2826
3479
  url: req.url,
@@ -2835,10 +3488,29 @@ function createNetworkForwarder(bridge) {
2835
3488
  "Network.loadingFinished": onLoadingFinished,
2836
3489
  "Network.loadingFailed": onLoadingFailed
2837
3490
  };
3491
+ function resolveUserFacing(method, params, rawId) {
3492
+ if (method === "Network.requestWillBeSent") {
3493
+ const url = params?.request?.url;
3494
+ const verdict = typeof url === "string" ? isUserFacingRequest(url, [bridge.getResourceServerBaseUrl?.(), bridge.getSimulatorServerBaseUrl?.()]) : true;
3495
+ if (rawId) {
3496
+ if (userFacingByRawId.size >= MAX_PENDING) userFacingByRawId.clear();
3497
+ userFacingByRawId.set(rawId, verdict);
3498
+ }
3499
+ return verdict;
3500
+ }
3501
+ if (rawId && userFacingByRawId.has(rawId)) return userFacingByRawId.get(rawId);
3502
+ if (method === "Network.requestWillBeSentExtraInfo") return false;
3503
+ return true;
3504
+ }
2838
3505
  const onMessage = (_event, method, params) => {
2839
3506
  if (FORWARDED_METHODS.has(method)) {
2840
3507
  const rewritten = rewriteRequestId(method, params, ns);
2841
- enqueueNative(rewritten.method, rewritten.params);
3508
+ dispatchToGlobal(rewritten.method, rewritten.params);
3509
+ const rawId = params?.requestId;
3510
+ const userFacing = resolveUserFacing(method, params, typeof rawId === "string" ? rawId : void 0);
3511
+ if (userFacing) {
3512
+ enqueueNative(rewritten.method, rewritten.params);
3513
+ }
2842
3514
  } else if (REWRITE_REQUEST_ID_METHODS.has(method)) {
2843
3515
  rewriteRequestId(method, params, ns);
2844
3516
  }
@@ -2999,6 +3671,14 @@ function createNetworkForwarder(bridge) {
2999
3671
  readyRetryTimer = null;
3000
3672
  }
3001
3673
  });
3674
+ registry.add(() => {
3675
+ globalDevtoolsHostDisposable?.dispose();
3676
+ globalDevtoolsHostDisposable = null;
3677
+ globalBodyGateStop?.();
3678
+ globalBodyGateStop = null;
3679
+ globalDevtoolsWc = null;
3680
+ clearGlobalPending();
3681
+ });
3002
3682
  registry.add(() => {
3003
3683
  bodyCache.clear();
3004
3684
  postDataCache.clear();
@@ -3015,6 +3695,7 @@ function createNetworkForwarder(bridge) {
3015
3695
  detachSimulator,
3016
3696
  attachRenderGuest,
3017
3697
  setDevtoolsHost: (wc) => applyDevtoolsHost(wc),
3698
+ setGlobalDevtoolsHost: (wc) => applyGlobalDevtoolsHost(wc),
3018
3699
  // report() has no observing debugger, so there's no live CDP event to push
3019
3700
  // natively — surface it via the console fallback line.
3020
3701
  report: (record) => forwardToConsole(record),
@@ -3043,13 +3724,13 @@ function routeByDomain(method) {
3043
3724
  function isRenderEventMethod(method) {
3044
3725
  return routeByDomain(method) === "render";
3045
3726
  }
3046
- var NETWORK_BODY_METHODS = [
3727
+ var NETWORK_BODY_METHODS2 = [
3047
3728
  "Network.getResponseBody",
3048
3729
  "Network.getRequestPostData"
3049
3730
  ];
3050
3731
  function buildElementsHookScript() {
3051
3732
  const prefixes = JSON.stringify(RENDER_DOMAIN_PREFIXES);
3052
- const netMethods = JSON.stringify(NETWORK_BODY_METHODS);
3733
+ const netMethods = JSON.stringify(NETWORK_BODY_METHODS2);
3053
3734
  const vprefix = JSON.stringify(VIRTUAL_REQUEST_ID_PREFIX);
3054
3735
  return `(function(){try{
3055
3736
  if (globalThis.__diminaElementsHookInstalled) return 'already';
@@ -3097,17 +3778,14 @@ function buildElementsHookScript() {
3097
3778
  return 'partial';
3098
3779
  }catch(e){ return 'error:' + (e && e.message); }})()`;
3099
3780
  }
3100
- function buildReconcileScript() {
3781
+ function buildReconcileScript2() {
3101
3782
  return `(function(){var status; try { status = ${buildElementsHookScript()}; } catch(e){ status = 'error:'+(e&&e.message); }var batch = []; try { if (globalThis.__diminaElementsOutbound) batch = globalThis.__diminaElementsOutbound.splice(0); } catch(_){}return { status: status, batch: batch };})()`;
3102
3783
  }
3103
- function buildDispatchScript2(message) {
3104
- return `(()=>{try{if(!${PROBE_DEVTOOLS_API})return false;window.DevToolsAPI.dispatchMessage(JSON.parse(${JSON.stringify(message)}));return true;}catch(_){return false}})()`;
3105
- }
3106
3784
  function buildDocumentUpdatedScript() {
3107
3785
  const msg = JSON.stringify({ method: "DOM.documentUpdated", params: {} });
3108
- return buildDispatchScript2(msg);
3786
+ return buildSingleDispatchScript(msg);
3109
3787
  }
3110
- var DRAIN_INTERVAL_MS = 150;
3788
+ var DRAIN_INTERVAL_MS2 = 150;
3111
3789
  function installElementsForward(deps) {
3112
3790
  const { devtoolsWc, bridge } = deps;
3113
3791
  const ownsBroker = !deps.broker;
@@ -3143,39 +3821,7 @@ function installElementsForward(deps) {
3143
3821
  }
3144
3822
  }
3145
3823
  };
3146
- function dispatchToFrontend(message) {
3147
- if (disposed || devtoolsWc.isDestroyed()) return;
3148
- if (!isFrontendSettled(devtoolsWc)) return;
3149
- let json;
3150
- try {
3151
- json = JSON.stringify(message);
3152
- } catch {
3153
- return;
3154
- }
3155
- if (json.length > MAX_SINGLE_DISPATCH_CHARS) {
3156
- const chunks = [];
3157
- for (let i = 0; i < json.length; i += CHUNK_CHARS) {
3158
- chunks.push(json.slice(i, i + CHUNK_CHARS));
3159
- }
3160
- let script2;
3161
- try {
3162
- script2 = buildChunkedDispatchScript(chunks, json.length);
3163
- } catch {
3164
- return;
3165
- }
3166
- devtoolsWc.executeJavaScript(script2, true).catch(() => {
3167
- });
3168
- return;
3169
- }
3170
- let script;
3171
- try {
3172
- script = buildDispatchScript2(json);
3173
- } catch {
3174
- return;
3175
- }
3176
- devtoolsWc.executeJavaScript(script, true).catch(() => {
3177
- });
3178
- }
3824
+ const { dispatchToFrontend, replyResult, replyError } = createFrontendReplyChannel(devtoolsWc, () => disposed);
3179
3825
  function pushDocumentUpdated() {
3180
3826
  if (disposed || devtoolsWc.isDestroyed()) return;
3181
3827
  if (!isFrontendSettled(devtoolsWc)) return;
@@ -3188,16 +3834,6 @@ function installElementsForward(deps) {
3188
3834
  devtoolsWc.executeJavaScript(script, true).catch(() => {
3189
3835
  });
3190
3836
  }
3191
- function replyResult(cmd, result) {
3192
- const msg = { id: cmd.id, result };
3193
- if (cmd.sessionId) msg.sessionId = cmd.sessionId;
3194
- dispatchToFrontend(msg);
3195
- }
3196
- function replyError(cmd, message) {
3197
- const msg = { id: cmd.id, error: { code: -32e3, message } };
3198
- if (cmd.sessionId) msg.sessionId = cmd.sessionId;
3199
- dispatchToFrontend(msg);
3200
- }
3201
3837
  function activeRenderWc() {
3202
3838
  try {
3203
3839
  const wc = bridge.getActiveRenderWc(deps.appId);
@@ -3270,34 +3906,16 @@ function installElementsForward(deps) {
3270
3906
  });
3271
3907
  }
3272
3908
  function answerNetworkCommand(cmd) {
3273
- const provider = deps.network;
3274
- const requestId = cmd.params?.requestId;
3275
- if (!provider || typeof requestId !== "string") {
3276
- replyError(cmd, "No resource with given identifier found");
3277
- return;
3278
- }
3279
- const lookup = cmd.method === "Network.getRequestPostData" ? provider.getRequestPostData(requestId) : provider.getResponseBody(requestId);
3280
- lookup.then(
3281
- (result) => {
3282
- if (!disposed) replyResult(cmd, result);
3283
- },
3284
- (err2) => {
3285
- if (!disposed) replyError(cmd, err2 instanceof Error ? err2.message : String(err2));
3286
- }
3287
- );
3909
+ answerNetworkBodyCommand(cmd, deps.network, { replyResult, replyError });
3288
3910
  }
3289
3911
  function handleOutbound(batch) {
3290
- if (!Array.isArray(batch)) return;
3291
- for (const raw of batch) {
3292
- if (!raw || typeof raw !== "object") continue;
3293
- const cmd = raw;
3294
- if (typeof cmd.method !== "string") continue;
3912
+ drainOutboundBatch(batch, (cmd) => {
3295
3913
  if (cmd.route === "network") {
3296
3914
  answerNetworkCommand(cmd);
3297
- continue;
3915
+ return;
3298
3916
  }
3299
3917
  routeCommand(cmd);
3300
- }
3918
+ });
3301
3919
  }
3302
3920
  const onRenderEvent = (event) => {
3303
3921
  if (disposed) return;
@@ -3320,7 +3938,7 @@ function installElementsForward(deps) {
3320
3938
  return;
3321
3939
  }
3322
3940
  if (!isFrontendSettled(devtoolsWc)) return;
3323
- devtoolsWc.executeJavaScript(buildReconcileScript()).then((res) => {
3941
+ devtoolsWc.executeJavaScript(buildReconcileScript2()).then((res) => {
3324
3942
  if (disposed) return;
3325
3943
  const r = res ?? {};
3326
3944
  if (r.status === "installed") {
@@ -3331,7 +3949,7 @@ function installElementsForward(deps) {
3331
3949
  handleOutbound(r.batch);
3332
3950
  }).catch(() => {
3333
3951
  });
3334
- }, DRAIN_INTERVAL_MS);
3952
+ }, DRAIN_INTERVAL_MS2);
3335
3953
  };
3336
3954
  devtoolsWc.on("dom-ready", onReady);
3337
3955
  onReady();
@@ -3551,6 +4169,7 @@ function createDevtoolsHost(ctx, reconciler, deps) {
3551
4169
  let nativeDevtoolsSourceWc = null;
3552
4170
  let devtoolsHostUsed = false;
3553
4171
  let unsubscribeNativeRenderEvents = null;
4172
+ let unsubscribeNativeServiceHostReady = null;
3554
4173
  let stopElementsForward = null;
3555
4174
  let stopServiceConsole = null;
3556
4175
  let nativeDevtoolsRetryTimer = null;
@@ -3589,6 +4208,13 @@ function createDevtoolsHost(ctx, reconciler, deps) {
3589
4208
  }
3590
4209
  unsubscribeNativeRenderEvents = null;
3591
4210
  }
4211
+ if (unsubscribeNativeServiceHostReady) {
4212
+ try {
4213
+ unsubscribeNativeServiceHostReady();
4214
+ } catch {
4215
+ }
4216
+ unsubscribeNativeServiceHostReady = null;
4217
+ }
3592
4218
  closeNativeDevtoolsSource();
3593
4219
  }
3594
4220
  function injectOpenResourceHandler(serviceWc, devtoolsWc) {
@@ -3619,6 +4245,25 @@ function createDevtoolsHost(ctx, reconciler, deps) {
3619
4245
  } catch {
3620
4246
  }
3621
4247
  }
4248
+ function applyConsoleFilter(devtoolsWc) {
4249
+ try {
4250
+ if (devtoolsWc.isDestroyed()) return;
4251
+ const inject = () => {
4252
+ void whenFrontendBootstrapped(devtoolsWc).then((ready) => {
4253
+ if (!ready || devtoolsWc.isDestroyed()) return;
4254
+ try {
4255
+ void devtoolsWc.executeJavaScript(buildConsoleFilterScript()).catch(() => {
4256
+ });
4257
+ void devtoolsWc.executeJavaScript(buildLiveConsoleFilterScript()).catch(() => {
4258
+ });
4259
+ } catch {
4260
+ }
4261
+ });
4262
+ };
4263
+ injectWhenReady(devtoolsWc, "console-filter", inject);
4264
+ } catch {
4265
+ }
4266
+ }
3622
4267
  function wireOpenInEditor(serviceWc, devtoolsWc) {
3623
4268
  if (!devtoolsWc.isDestroyed()) {
3624
4269
  injectWhenReady(devtoolsWc, "open-in-editor", () => injectOpenResourceHandler(serviceWc, devtoolsWc));
@@ -3664,6 +4309,7 @@ function createDevtoolsHost(ctx, reconciler, deps) {
3664
4309
  devtoolsHostUsed = true;
3665
4310
  wireOpenInEditor(next, simulatorView.webContents);
3666
4311
  customizeDevtoolsTabs(simulatorView.webContents);
4312
+ applyConsoleFilter(simulatorView.webContents);
3667
4313
  try {
3668
4314
  stopServiceConsole?.();
3669
4315
  } catch {
@@ -3689,8 +4335,10 @@ function createDevtoolsHost(ctx, reconciler, deps) {
3689
4335
  if (!wc || wc.isDestroyed()) return false;
3690
4336
  return pointNativeDevtoolsAtServiceWc(wc);
3691
4337
  }
3692
- function scheduleNativeDevtoolsFollow(appId, attempt = 0) {
3693
- if (attempt >= 20) return;
4338
+ const NATIVE_DEVTOOLS_FALLBACK_POLL_MAX_MS = 6e4;
4339
+ const NATIVE_DEVTOOLS_FALLBACK_POLL_INTERVAL_MS = 50;
4340
+ function scheduleNativeDevtoolsFollow(appId, startedAt = Date.now()) {
4341
+ if (Date.now() - startedAt >= NATIVE_DEVTOOLS_FALLBACK_POLL_MAX_MS) return;
3694
4342
  if (!ctx.bridge?.isNativeHost()) return;
3695
4343
  const token = nativeDevtoolsRetryToken;
3696
4344
  if (nativeDevtoolsRetryTimer) clearTimeout(nativeDevtoolsRetryTimer);
@@ -3698,14 +4346,27 @@ function createDevtoolsHost(ctx, reconciler, deps) {
3698
4346
  nativeDevtoolsRetryTimer = null;
3699
4347
  if (token !== nativeDevtoolsRetryToken) return;
3700
4348
  if (pointNativeDevtoolsAtActiveServiceHost(appId)) return;
3701
- scheduleNativeDevtoolsFollow(appId, attempt + 1);
3702
- }, 50);
4349
+ scheduleNativeDevtoolsFollow(appId, startedAt);
4350
+ }, NATIVE_DEVTOOLS_FALLBACK_POLL_INTERVAL_MS);
3703
4351
  }
3704
4352
  function followNativeDevtoolsServiceHost(appId) {
3705
4353
  clearNativeDevtoolsRetry();
3706
4354
  if (pointNativeDevtoolsAtActiveServiceHost(appId)) return;
3707
4355
  scheduleNativeDevtoolsFollow(appId);
3708
4356
  }
4357
+ function onNativeServiceHostReady(event) {
4358
+ if (!ctx.bridge?.isNativeHost()) return;
4359
+ if (!simulatorView || simulatorView.webContents.isDestroyed()) return;
4360
+ const wc = electronWebContents.fromId(event.serviceWcId);
4361
+ if (!wc || wc.isDestroyed()) return;
4362
+ const current = ctx.bridge.getServiceWc(event.appId);
4363
+ if (current && current.id !== event.serviceWcId) return;
4364
+ if (pointNativeDevtoolsAtServiceWc(wc)) {
4365
+ clearNativeDevtoolsRetry();
4366
+ return;
4367
+ }
4368
+ scheduleNativeDevtoolsFollow(event.appId);
4369
+ }
3709
4370
  function onNativeRenderEvent(event) {
3710
4371
  if (event.kind !== "activePage" && event.kind !== "domReady") return;
3711
4372
  followNativeDevtoolsServiceHost(event.appId);
@@ -3721,7 +4382,7 @@ function createDevtoolsHost(ctx, reconciler, deps) {
3721
4382
  }
3722
4383
  simulatorView = null;
3723
4384
  }
3724
- simulatorView = new WebContentsView3();
4385
+ simulatorView = new WebContentsView4();
3725
4386
  const devtoolsWc = simulatorView.webContents;
3726
4387
  raiseExecuteJavaScriptListenerCeiling(devtoolsWc);
3727
4388
  ctx.networkForward?.setDevtoolsHost(devtoolsWc);
@@ -3752,27 +4413,21 @@ function createDevtoolsHost(ctx, reconciler, deps) {
3752
4413
  });
3753
4414
  }
3754
4415
  injectWhenReady(devtoolsWc, "console-default", () => {
3755
- devtoolsWc.executeJavaScript(`
3756
- (function() {
3757
- try { localStorage.setItem('panel-selectedTab', '"console"') } catch {}
3758
- let tries = 0
3759
- const timer = setInterval(() => {
3760
- tries++
4416
+ void whenFrontendBootstrapped(devtoolsWc).then((ready) => {
4417
+ if (!ready || devtoolsWc.isDestroyed()) return;
4418
+ devtoolsWc.executeJavaScript(`
4419
+ (function() {
3761
4420
  try {
3762
- const UI = globalThis.UI
3763
- const vm = UI && UI.ViewManager && typeof UI.ViewManager.instance === 'function'
3764
- ? UI.ViewManager.instance()
4421
+ var EUI = globalThis.EUI
4422
+ var vm = EUI && EUI.ViewManager && EUI.ViewManager.ViewManager
4423
+ && typeof EUI.ViewManager.ViewManager.instance === 'function'
4424
+ ? EUI.ViewManager.ViewManager.instance()
3765
4425
  : null
3766
- if (vm && typeof vm.showView === 'function') {
3767
- vm.showView('console')
3768
- clearInterval(timer)
3769
- return
3770
- }
3771
- } catch {}
3772
- if (tries > 80) clearInterval(timer)
3773
- }, 50)
3774
- })()
3775
- `).catch(() => {
4426
+ if (vm && typeof vm.showView === 'function') void vm.showView('console')
4427
+ } catch (_) {}
4428
+ })()
4429
+ `).catch(() => {
4430
+ });
3776
4431
  });
3777
4432
  });
3778
4433
  reconciler.reconcileNow();
@@ -3783,6 +4438,7 @@ function createDevtoolsHost(ctx, reconciler, deps) {
3783
4438
  rebuildDevtoolsHostView();
3784
4439
  if (ctx.bridge?.isNativeHost()) {
3785
4440
  unsubscribeNativeRenderEvents = ctx.bridge.onRenderEvent(onNativeRenderEvent);
4441
+ unsubscribeNativeServiceHostReady = ctx.bridge.onServiceHostReady(onNativeServiceHostReady);
3786
4442
  followNativeDevtoolsServiceHost();
3787
4443
  }
3788
4444
  }
@@ -3824,7 +4480,7 @@ function createDevtoolsHost(ctx, reconciler, deps) {
3824
4480
  }
3825
4481
 
3826
4482
  // src/main/services/views/host-toolbar-view.ts
3827
- import { WebContentsView as WebContentsView4 } from "electron";
4483
+ import { WebContentsView as WebContentsView5 } from "electron";
3828
4484
 
3829
4485
  // src/main/services/views/host-toolbar-session-runtime.ts
3830
4486
  import { session } from "electron";
@@ -4020,7 +4676,7 @@ function createHostToolbarView(ctx, reconciler, deps) {
4020
4676
  if (hostToolbarPreloadOverride !== null) {
4021
4677
  webPreferences.preload = hostToolbarPreloadOverride;
4022
4678
  }
4023
- const view = new WebContentsView4({ webPreferences });
4679
+ const view = new WebContentsView5({ webPreferences });
4024
4680
  hostToolbarView = view;
4025
4681
  hostToolbarPort.attach(view.webContents);
4026
4682
  try {
@@ -4068,8 +4724,8 @@ function createHostToolbarView(ctx, reconciler, deps) {
4068
4724
  hide() {
4069
4725
  hideHostToolbar();
4070
4726
  },
4071
- setPreloadPath(path25) {
4072
- hostToolbarPreloadOverride = path25;
4727
+ setPreloadPath(path26) {
4728
+ hostToolbarPreloadOverride = path26;
4073
4729
  },
4074
4730
  setHeightMode(mode) {
4075
4731
  if (mode !== "auto" && !(Number.isFinite(mode.fixed) && mode.fixed >= 0)) {
@@ -4122,7 +4778,7 @@ function createHostToolbarView(ctx, reconciler, deps) {
4122
4778
  }
4123
4779
 
4124
4780
  // src/main/services/views/overlay-panels-view.ts
4125
- import { WebContentsView as WebContentsView5 } from "electron";
4781
+ import { WebContentsView as WebContentsView6 } from "electron";
4126
4782
  import path8 from "path";
4127
4783
 
4128
4784
  // src/main/services/layout/index.ts
@@ -4190,7 +4846,7 @@ function createOverlayPanelsView(ctx, reconciler, deps) {
4190
4846
  }
4191
4847
  async function showSettings() {
4192
4848
  if (!settingsView) {
4193
- settingsView = new WebContentsView5({
4849
+ settingsView = new WebContentsView6({
4194
4850
  webPreferences: {
4195
4851
  nodeIntegration: false,
4196
4852
  contextIsolation: true,
@@ -4212,7 +4868,7 @@ function createOverlayPanelsView(ctx, reconciler, deps) {
4212
4868
  }
4213
4869
  function showPopover(data) {
4214
4870
  hidePopover();
4215
- const popover = new WebContentsView5({
4871
+ const popover = new WebContentsView6({
4216
4872
  webPreferences: {
4217
4873
  nodeIntegration: false,
4218
4874
  contextIsolation: true,
@@ -4279,7 +4935,7 @@ function createOverlayPanelsView(ctx, reconciler, deps) {
4279
4935
  }
4280
4936
 
4281
4937
  // src/main/services/views/native-simulator-view.ts
4282
- import { ipcMain as ipcMain2, nativeTheme as nativeTheme4, shell as shell2, WebContentsView as WebContentsView6, webContents as webContents2 } from "electron";
4938
+ import { ipcMain as ipcMain2, nativeTheme as nativeTheme4, shell as shell2, WebContentsView as WebContentsView7, webContents as webContents2 } from "electron";
4283
4939
 
4284
4940
  // src/main/services/simulator/custom-apis.ts
4285
4941
  async function handleCustomApiBridgeRequest(apis, req) {
@@ -4608,7 +5264,7 @@ function createNativeSimulatorView(ctx, reconciler, deps) {
4608
5264
  const route = parseRoute(simulatorUrl);
4609
5265
  const partition = miniappPartition(route?.appId, ctx.workspace?.getProjectPath());
4610
5266
  configureMiniappSession(partition);
4611
- const view = new WebContentsView6({
5267
+ const view = new WebContentsView7({
4612
5268
  webPreferences: {
4613
5269
  nodeIntegration: false,
4614
5270
  contextIsolation: false,
@@ -4847,10 +5503,10 @@ function createWindowService(mainWindow) {
4847
5503
  }
4848
5504
 
4849
5505
  // src/main/windows/settings-window/create.ts
4850
- import { BrowserWindow as BrowserWindow3 } from "electron";
5506
+ import { BrowserWindow as BrowserWindow4 } from "electron";
4851
5507
  import path9 from "path";
4852
5508
  async function createSettingsWindow(parent, rendererDir2) {
4853
- const win = new BrowserWindow3({
5509
+ const win = new BrowserWindow4({
4854
5510
  width: 420,
4855
5511
  height: 560,
4856
5512
  minWidth: 380,
@@ -5535,7 +6191,11 @@ function setupCompileWorkerStandby(ctx, deps = {}) {
5535
6191
  ctx.diagnostics?.report({
5536
6192
  severity: EVENT_SEVERITY[ev.type] ?? "info",
5537
6193
  code: "compile-standby",
5538
- message: detail
6194
+ message: detail,
6195
+ // Devtools-tooling-only state, unrelated to the inspected mini-program
6196
+ // — must never reach the right-panel (user-facing) Console panel; see
6197
+ // console-forward/index.ts's audience gate and global-diagnostics-mirror.ts.
6198
+ audience: "internal"
5539
6199
  });
5540
6200
  } catch {
5541
6201
  }
@@ -5867,7 +6527,7 @@ async function materializeTemplate(target, template, name) {
5867
6527
  `Template source missing on disk: ${template.source.path}`
5868
6528
  );
5869
6529
  }
5870
- fs7.cpSync(template.source.path, target, {
6530
+ await fs7.promises.cp(template.source.path, target, {
5871
6531
  recursive: true,
5872
6532
  force: true
5873
6533
  });
@@ -6134,6 +6794,13 @@ var settingsModule = {
6134
6794
  setup: (ctx) => registerSettingsIpc(ctx)
6135
6795
  };
6136
6796
 
6797
+ // src/main/ipc/internal-devtools.ts
6798
+ function registerInternalDevtoolsIpc(ctx) {
6799
+ return new IpcRegistry(ctx.senderPolicy).handle(InternalDevtoolsChannel.Open, () => {
6800
+ ctx.internalDevtoolsWindow?.open();
6801
+ });
6802
+ }
6803
+
6137
6804
  // src/main/ipc/simulator-module.ts
6138
6805
  import { DisposableRegistry as DisposableRegistry5 } from "@dimina-kit/electron-deck/main";
6139
6806
 
@@ -6292,7 +6959,7 @@ function setCorsHeaders(res) {
6292
6959
  }
6293
6960
 
6294
6961
  // src/main/windows/service-host-window/create.ts
6295
- import { app as app10, BrowserWindow as BrowserWindow4 } from "electron";
6962
+ import { app as app10, BrowserWindow as BrowserWindow5 } from "electron";
6296
6963
  import path16 from "node:path";
6297
6964
  import { pathToFileURL as pathToFileURL2 } from "node:url";
6298
6965
  var SERVICE_HOST_PARTITION = SHARED_MINIAPP_PARTITION;
@@ -6301,7 +6968,7 @@ var serviceHostHtmlPath = path16.join(devtoolsPackageRoot, "dist/service-host/se
6301
6968
  function constructServiceHostWindow(opts = {}) {
6302
6969
  const partition = opts.partition ?? SERVICE_HOST_PARTITION;
6303
6970
  configureMiniappSession(partition);
6304
- return new BrowserWindow4({
6971
+ return new BrowserWindow5({
6305
6972
  width: 980,
6306
6973
  height: 720,
6307
6974
  show: false,
@@ -6382,7 +7049,7 @@ function createServiceHostWindow(opts) {
6382
7049
  }
6383
7050
 
6384
7051
  // src/main/services/service-host-pool/pool.ts
6385
- import { BrowserWindow as BrowserWindow5 } from "electron";
7052
+ import { BrowserWindow as BrowserWindow6 } from "electron";
6386
7053
  var BLANK_URL = "about:blank";
6387
7054
  var HARD_MAX_POOL_SIZE = 4;
6388
7055
  var RESET_STORAGES = [
@@ -6579,7 +7246,7 @@ var ServiceHostPool = class {
6579
7246
  }
6580
7247
  }
6581
7248
  createWindow(spec) {
6582
- return new BrowserWindow5({
7249
+ return new BrowserWindow6({
6583
7250
  show: false,
6584
7251
  width: spec.size?.width,
6585
7252
  height: spec.size?.height,
@@ -6687,20 +7354,32 @@ var ServiceHostPool = class {
6687
7354
 
6688
7355
  // src/main/services/console-forward/index.ts
6689
7356
  import { DisposableRegistry as DisposableRegistry3, toDisposable as toDisposable4 } from "@dimina-kit/electron-deck/main";
6690
- var FORWARDABLE_LEVELS = /* @__PURE__ */ new Set(["log", "warn", "error", "info", "debug"]);
7357
+
7358
+ // src/main/services/console-forward/internal-log.ts
7359
+ var SERVICE_PREFIX = "[service]";
7360
+ var RENDER_PREFIX = "[system]";
7361
+ function isInternalLogMessage(entry) {
7362
+ const first = entry.args?.[0];
7363
+ if (typeof first !== "string") return false;
7364
+ if (first === RENDER_PREFIX) return true;
7365
+ return first === SERVICE_PREFIX || first.startsWith(`${SERVICE_PREFIX} `);
7366
+ }
7367
+
7368
+ // src/main/services/console-forward/index.ts
7369
+ var FORWARDABLE_LEVELS2 = /* @__PURE__ */ new Set(["log", "warn", "error", "info", "debug"]);
6691
7370
  function buildForwardScript2(level, args) {
6692
- const method = FORWARDABLE_LEVELS.has(level) ? level : "log";
7371
+ const method = FORWARDABLE_LEVELS2.has(level) ? level : "log";
6693
7372
  const argsJson = JSON.stringify(args ?? []);
6694
7373
  return `(()=>{try{const a=JSON.parse(${JSON.stringify(argsJson)});console[${JSON.stringify(method)}]('[\u89C6\u56FE]',...a)}catch(_){}})()
6695
7374
  //# sourceURL=${RENDER_FORWARD_SOURCE_URL}`;
6696
7375
  }
6697
- var DIAGNOSTIC_CONSOLE_CALL = {
7376
+ var DIAGNOSTIC_CONSOLE_CALL2 = {
6698
7377
  error: "console.error",
6699
7378
  warn: "console.warn",
6700
7379
  info: "console.info"
6701
7380
  };
6702
7381
  function buildDiagnosticScript(severity, message) {
6703
- const call = DIAGNOSTIC_CONSOLE_CALL[severity];
7382
+ const call = DIAGNOSTIC_CONSOLE_CALL2[severity];
6704
7383
  const argsJson = JSON.stringify([`[dimina-kit] ${message}`]);
6705
7384
  return `(()=>{try{const a=JSON.parse(${JSON.stringify(argsJson)});${call}(...a)}catch(_){}})()
6706
7385
  //# sourceURL=${RENDER_FORWARD_SOURCE_URL}`;
@@ -6708,6 +7387,8 @@ function buildDiagnosticScript(severity, message) {
6708
7387
  function createConsoleForwarder(bridge, diagnostics) {
6709
7388
  const sinks = /* @__PURE__ */ new Set();
6710
7389
  const registry = new DisposableRegistry3();
7390
+ const CONSOLE_BUFFER_CAP = 200;
7391
+ const buffer = [];
6711
7392
  const pendingBySession = /* @__PURE__ */ new Map();
6712
7393
  const pendingGlobal = [];
6713
7394
  const readySessions = /* @__PURE__ */ new Set();
@@ -6716,6 +7397,7 @@ function createConsoleForwarder(bridge, diagnostics) {
6716
7397
  });
6717
7398
  }
6718
7399
  function handleDiagnostic(d) {
7400
+ if (d.audience === "internal") return;
6719
7401
  if (d.appSessionId) {
6720
7402
  const wc2 = readySessions.has(d.appSessionId) && bridge.getServiceWcForBridge ? bridge.getServiceWcForBridge(d.appSessionId) : null;
6721
7403
  if (wc2 && !wc2.isDestroyed()) {
@@ -6738,6 +7420,7 @@ function createConsoleForwarder(bridge, diagnostics) {
6738
7420
  registry.add(diagnostics.subscribe(handleDiagnostic, { replay: true }));
6739
7421
  }
6740
7422
  function forwardRenderToServiceHost(entry) {
7423
+ if (isInternalLogMessage(entry)) return;
6741
7424
  let wc = null;
6742
7425
  if (entry.bridgeId && bridge.getServiceWcForBridge) {
6743
7426
  wc = bridge.getServiceWcForBridge(entry.bridgeId);
@@ -6759,6 +7442,8 @@ function createConsoleForwarder(bridge, diagnostics) {
6759
7442
  // (render only — see loop-safety invariant in the module header).
6760
7443
  emit(raw) {
6761
7444
  const entry = raw ?? {};
7445
+ buffer.push(entry);
7446
+ if (buffer.length > CONSOLE_BUFFER_CAP) buffer.shift();
6762
7447
  for (const sink of sinks) {
6763
7448
  try {
6764
7449
  sink(entry);
@@ -6767,7 +7452,15 @@ function createConsoleForwarder(bridge, diagnostics) {
6767
7452
  }
6768
7453
  if (entry.source === "render") forwardRenderToServiceHost(entry);
6769
7454
  },
6770
- subscribe(sink) {
7455
+ subscribe(sink, opts) {
7456
+ if (opts?.replay) {
7457
+ for (const entry of buffer) {
7458
+ try {
7459
+ sink(entry);
7460
+ } catch {
7461
+ }
7462
+ }
7463
+ }
6771
7464
  sinks.add(sink);
6772
7465
  return registry.add(toDisposable4(() => {
6773
7466
  sinks.delete(sink);
@@ -6789,6 +7482,7 @@ function createConsoleForwarder(bridge, diagnostics) {
6789
7482
  },
6790
7483
  dispose() {
6791
7484
  sinks.clear();
7485
+ buffer.length = 0;
6792
7486
  pendingBySession.clear();
6793
7487
  pendingGlobal.length = 0;
6794
7488
  readySessions.clear();
@@ -7462,6 +8156,9 @@ function installBridgeRouter(ctx) {
7462
8156
  pool: null,
7463
8157
  emitRenderEvent: () => {
7464
8158
  },
8159
+ emitServiceHostReady: () => {
8160
+ },
8161
+ lastServiceHostReady: null,
7465
8162
  connections: ctx.connections,
7466
8163
  debugTap: createDebugTap({ enabled: resolveDebugTapEnabled() }),
7467
8164
  appLifecycle: createAppLifecycleController(),
@@ -7509,6 +8206,18 @@ function installBridgeRouter(ctx) {
7509
8206
  }
7510
8207
  };
7511
8208
  state.emitRenderEvent = emitRenderEvent;
8209
+ const serviceHostReadyListeners = /* @__PURE__ */ new Set();
8210
+ const emitServiceHostReady = (event) => {
8211
+ state.lastServiceHostReady = event;
8212
+ for (const listener of serviceHostReadyListeners) {
8213
+ try {
8214
+ listener(event);
8215
+ } catch (error) {
8216
+ console.warn("[bridge-router] service-host-ready listener threw:", error);
8217
+ }
8218
+ }
8219
+ };
8220
+ state.emitServiceHostReady = emitServiceHostReady;
7512
8221
  const bridgeHandle = {
7513
8222
  isNativeHost: () => true,
7514
8223
  resolveRenderWc: (bridgeId) => {
@@ -7534,6 +8243,10 @@ function installBridgeRouter(ctx) {
7534
8243
  const ap = resolveCurrentApp(state, ctx, appId);
7535
8244
  return ap?.pageStack ?? null;
7536
8245
  },
8246
+ getResourceBaseUrl: (appId) => {
8247
+ const ap = resolveCurrentApp(state, ctx, appId);
8248
+ return ap?.resourceBaseUrl ?? null;
8249
+ },
7537
8250
  getActiveRenderWc: (appId) => {
7538
8251
  const ap = resolveCurrentApp(state, ctx, appId);
7539
8252
  if (!ap) return null;
@@ -7544,6 +8257,23 @@ function installBridgeRouter(ctx) {
7544
8257
  renderEventListeners.add(listener);
7545
8258
  return () => renderEventListeners.delete(listener);
7546
8259
  },
8260
+ onServiceHostReady: (listener) => {
8261
+ serviceHostReadyListeners.add(listener);
8262
+ const candidate = state.lastServiceHostReady;
8263
+ if (candidate) {
8264
+ queueMicrotask(() => {
8265
+ if (!serviceHostReadyListeners.has(listener)) return;
8266
+ const ap = state.appSessions.get(candidate.appSessionId);
8267
+ if (!ap || ap.serviceWc.isDestroyed() || ap.serviceWc.id !== candidate.serviceWcId) return;
8268
+ try {
8269
+ listener(candidate);
8270
+ } catch (error) {
8271
+ console.warn("[bridge-router] service-host-ready catch-up listener threw:", error);
8272
+ }
8273
+ });
8274
+ }
8275
+ return () => serviceHostReadyListeners.delete(listener);
8276
+ },
7547
8277
  getDevice: () => currentDevice,
7548
8278
  setDevice: (device) => {
7549
8279
  currentDevice = device;
@@ -8073,6 +8803,7 @@ function handleNavCallback(state, sender, payload) {
8073
8803
  async function bootServiceHost(state, ap, ctx) {
8074
8804
  if (state.appSessions.get(ap.appSessionId) !== ap) return;
8075
8805
  ctx.consoleForwarder?.notifyServiceHostReady?.(ap.appSessionId);
8806
+ state.emitServiceHostReady({ appId: ap.appId, appSessionId: ap.appSessionId, serviceWcId: ap.serviceWc.id });
8076
8807
  ap.logicInjected = await injectLogicBundle(ap);
8077
8808
  if (!ap.logicInjected) {
8078
8809
  const reason = reportLogicLoadFailure(ap, ctx);
@@ -10250,7 +10981,6 @@ function startMcpServer(resolvedCdpPort, mcpPort) {
10250
10981
  });
10251
10982
  connectTarget("workbench").catch(() => {
10252
10983
  });
10253
- const server = buildServer();
10254
10984
  const transports = /* @__PURE__ */ new Map();
10255
10985
  const httpServer = createServer(async (req, res) => {
10256
10986
  const url = new URL(req.url ?? "/", `http://localhost`);
@@ -10258,7 +10988,14 @@ function startMcpServer(resolvedCdpPort, mcpPort) {
10258
10988
  const transport = new SSEServerTransport("/message", res);
10259
10989
  transports.set(transport.sessionId, transport);
10260
10990
  res.on("close", () => transports.delete(transport.sessionId));
10261
- await server.connect(transport);
10991
+ try {
10992
+ await buildServer().connect(transport);
10993
+ } catch (err2) {
10994
+ transports.delete(transport.sessionId);
10995
+ if (!res.headersSent) res.writeHead(500).end("MCP connect failed");
10996
+ else res.end();
10997
+ console.error("[MCP] SSE connect failed:", err2);
10998
+ }
10262
10999
  } else if (req.method === "POST" && url.pathname === "/message") {
10263
11000
  const sessionId = url.searchParams.get("sessionId") ?? "";
10264
11001
  const transport = transports.get(sessionId);
@@ -10607,13 +11344,13 @@ function createRenderInspector(options = {}) {
10607
11344
  import { toDisposable as toDisposable6 } from "@dimina-kit/electron-deck/main";
10608
11345
 
10609
11346
  // src/main/services/simulator-temp-files/store.ts
10610
- function registerTempFile(store, path25, mime, bytes) {
11347
+ function registerTempFile(store, path26, mime, bytes) {
10611
11348
  const buf = Buffer.isBuffer(bytes) ? bytes : Buffer.from(new Uint8Array(bytes));
10612
- store.delete(path25);
10613
- store.set(path25, { bytes: buf, mime });
11349
+ store.delete(path26);
11350
+ store.set(path26, { bytes: buf, mime });
10614
11351
  }
10615
- function revokeTempFile(store, path25) {
10616
- store.delete(path25);
11352
+ function revokeTempFile(store, path26) {
11353
+ store.delete(path26);
10617
11354
  }
10618
11355
  function revokeAllTempFiles(store) {
10619
11356
  store.clear();
@@ -11041,10 +11778,10 @@ function setupSimulatorTempFiles(simSession) {
11041
11778
  const store = /* @__PURE__ */ new Map();
11042
11779
  const pendingWaiters = /* @__PURE__ */ new Map();
11043
11780
  let disposed = false;
11044
- function drainWaiters(path25) {
11045
- const list = pendingWaiters.get(path25);
11781
+ function drainWaiters(path26) {
11782
+ const list = pendingWaiters.get(path26);
11046
11783
  if (!list) return;
11047
- pendingWaiters.delete(path25);
11784
+ pendingWaiters.delete(path26);
11048
11785
  for (const fn of list) fn();
11049
11786
  }
11050
11787
  function drainAllWaiters() {
@@ -11057,15 +11794,15 @@ function setupSimulatorTempFiles(simSession) {
11057
11794
  const registry = new IpcRegistry(simulatorOnlyPolicy);
11058
11795
  registry.on("simulator:temp-file:write", (_event, payload) => {
11059
11796
  if (disposed) return;
11060
- const { path: path25, mime, bytes } = payload;
11061
- registerTempFile(store, path25, mime, bytes);
11797
+ const { path: path26, mime, bytes } = payload;
11798
+ registerTempFile(store, path26, mime, bytes);
11062
11799
  enforceStoreCap(store);
11063
- drainWaiters(path25);
11800
+ drainWaiters(path26);
11064
11801
  });
11065
11802
  registry.on("simulator:temp-file:revoke", (_event, payload) => {
11066
11803
  if (disposed) return;
11067
- const { path: path25 } = payload;
11068
- revokeTempFile(store, path25);
11804
+ const { path: path26 } = payload;
11805
+ revokeTempFile(store, path26);
11069
11806
  });
11070
11807
  registry.on("simulator:temp-file:revoke-all", () => {
11071
11808
  if (disposed) return;
@@ -11619,8 +12356,9 @@ var UpdateManager = class {
11619
12356
  const currentVersion = this.getCurrentVersion();
11620
12357
  const info = await this.checker.checkForUpdates(currentVersion);
11621
12358
  if (info) {
12359
+ const isSameUpdate = this.latestUpdate?.version === info.version && this.latestUpdate?.downloadUrl === info.downloadUrl;
11622
12360
  this.latestUpdate = info;
11623
- this.downloadedPath = null;
12361
+ if (!isSameUpdate) this.downloadedPath = null;
11624
12362
  return { hasUpdate: true, info };
11625
12363
  }
11626
12364
  return { hasUpdate: false };
@@ -11644,11 +12382,17 @@ var UpdateManager = class {
11644
12382
  return { success: false, error: String(err2) };
11645
12383
  }
11646
12384
  }
11647
- install() {
11648
- if (this.downloadedPath) {
11649
- shell3.openPath(this.downloadedPath);
11650
- app13.quit();
12385
+ async install() {
12386
+ if (!this.downloadedPath) {
12387
+ return { success: false, error: "No update downloaded" };
11651
12388
  }
12389
+ const failure = await shell3.openPath(this.downloadedPath);
12390
+ if (failure) {
12391
+ console.warn("[UpdateManager] install failed:", failure);
12392
+ return { success: false, error: failure };
12393
+ }
12394
+ app13.quit();
12395
+ return { success: true };
11652
12396
  }
11653
12397
  /**
11654
12398
  * Tear down timers + IPC handlers. Returns a Promise so callers that need
@@ -11681,7 +12425,249 @@ var UpdateManager = class {
11681
12425
  };
11682
12426
 
11683
12427
  // src/main/services/update/github-release-checker.ts
12428
+ import fs12 from "fs";
12429
+ import path24 from "path";
12430
+ import https from "https";
11684
12431
  import { app as app14 } from "electron";
12432
+ function createGitHubReleaseChecker(opts) {
12433
+ const releaseUrl = opts.includePrereleases ? `https://api.github.com/repos/${opts.owner}/${opts.repo}/releases` : `https://api.github.com/repos/${opts.owner}/${opts.repo}/releases/latest`;
12434
+ const parseVersion = opts.parseVersion ?? schemeParser(opts.versionScheme ?? "semver");
12435
+ return {
12436
+ async checkForUpdates(currentVersion) {
12437
+ const release = await fetchRelease(releaseUrl, opts);
12438
+ if (!release) return null;
12439
+ const latestVersion = parseVersion(release);
12440
+ if (!latestVersion) return null;
12441
+ if (compareSemver(latestVersion, stripV(currentVersion)) <= 0) return null;
12442
+ const asset = (opts.pickAsset ?? defaultPickAsset)(release.assets, {
12443
+ platform: process.platform,
12444
+ arch: process.arch
12445
+ });
12446
+ if (!asset) return null;
12447
+ return {
12448
+ version: latestVersion,
12449
+ downloadUrl: asset.browser_download_url,
12450
+ releaseNotes: release.body,
12451
+ mandatory: opts.mandatory
12452
+ };
12453
+ },
12454
+ async downloadUpdate(info, onProgress) {
12455
+ const tmpDir = path24.join(app14.getPath("temp"), `${opts.repo}-update`);
12456
+ if (!fs12.existsSync(tmpDir)) fs12.mkdirSync(tmpDir, { recursive: true });
12457
+ const fileName = path24.basename(new URL(info.downloadUrl).pathname);
12458
+ const filePath = path24.join(tmpDir, fileName);
12459
+ await downloadFile(info.downloadUrl, filePath, opts.token, onProgress);
12460
+ return filePath;
12461
+ }
12462
+ };
12463
+ }
12464
+ function defaultPickAsset(assets, ctx) {
12465
+ const candidates = platformMatchers(ctx.platform, ctx.arch);
12466
+ for (const match of candidates) {
12467
+ const hit = assets.find((a) => match(a.name));
12468
+ if (hit) return hit;
12469
+ }
12470
+ return void 0;
12471
+ }
12472
+ function platformMatchers(platform, arch) {
12473
+ const lc = (s) => s.toLowerCase();
12474
+ const archTags = archAliases(arch);
12475
+ const hasArch = (name) => archTags.some((tag) => lc(name).includes(tag));
12476
+ const endsWith = (name, ext) => lc(name).endsWith(ext);
12477
+ switch (platform) {
12478
+ case "darwin":
12479
+ return [
12480
+ (n) => endsWith(n, ".dmg") && hasArch(n),
12481
+ (n) => endsWith(n, ".dmg"),
12482
+ // mac builds are often universal / unarch-tagged
12483
+ (n) => endsWith(n, ".zip") && (lc(n).includes("mac") || lc(n).includes("darwin"))
12484
+ ];
12485
+ case "win32":
12486
+ return [
12487
+ (n) => endsWith(n, ".exe") && hasArch(n),
12488
+ (n) => endsWith(n, ".zip") && (lc(n).includes("win") || lc(n).includes("windows")) && hasArch(n),
12489
+ (n) => endsWith(n, ".exe"),
12490
+ (n) => endsWith(n, ".zip") && (lc(n).includes("win") || lc(n).includes("windows"))
12491
+ ];
12492
+ case "linux":
12493
+ return [
12494
+ (n) => endsWith(n, ".appimage") && hasArch(n),
12495
+ (n) => endsWith(n, ".tar.gz") && lc(n).includes("linux") && hasArch(n),
12496
+ (n) => endsWith(n, ".appimage"),
12497
+ (n) => endsWith(n, ".tar.gz") && lc(n).includes("linux"),
12498
+ (n) => endsWith(n, ".deb") && hasArch(n)
12499
+ ];
12500
+ default:
12501
+ return [];
12502
+ }
12503
+ }
12504
+ function archAliases(arch) {
12505
+ switch (arch) {
12506
+ case "x64":
12507
+ return ["x64", "x86_64", "amd64"];
12508
+ case "arm64":
12509
+ return ["arm64", "aarch64"];
12510
+ case "ia32":
12511
+ return ["ia32", "x86", "i386"];
12512
+ default:
12513
+ return [arch];
12514
+ }
12515
+ }
12516
+ var SEMVER_RE = /(\d+)\.(\d+)\.(\d+)(?:[-+]([0-9A-Za-z.-]+))?/;
12517
+ var TRAILING_NUMBER_RE = /-(\d+)$/;
12518
+ function schemeParser(scheme) {
12519
+ if (scheme === "trailing-number") {
12520
+ return (release) => {
12521
+ const m = release.tag_name.match(TRAILING_NUMBER_RE);
12522
+ return m ? m[1] : null;
12523
+ };
12524
+ }
12525
+ return defaultParseVersion;
12526
+ }
12527
+ function defaultParseVersion(release) {
12528
+ const fromTag = extractSemver(release.tag_name);
12529
+ if (fromTag) return fromTag;
12530
+ if (release.name) {
12531
+ const fromName = extractSemver(release.name);
12532
+ if (fromName) return fromName;
12533
+ }
12534
+ for (const asset of release.assets) {
12535
+ const hit = extractSemver(asset.name);
12536
+ if (hit) return hit;
12537
+ }
12538
+ return null;
12539
+ }
12540
+ function extractSemver(input) {
12541
+ const m = input.match(SEMVER_RE);
12542
+ if (!m) return null;
12543
+ const [, major, minor, patch, pre] = m;
12544
+ return pre ? `${major}.${minor}.${patch}-${pre}` : `${major}.${minor}.${patch}`;
12545
+ }
12546
+ function stripV(version) {
12547
+ return version.replace(/^v/i, "");
12548
+ }
12549
+ function compareSemver(a, b) {
12550
+ const [aCore, aPre] = splitPre(a);
12551
+ const [bCore, bPre] = splitPre(b);
12552
+ const [a1, a2, a3] = parseCore(aCore);
12553
+ const [b1, b2, b3] = parseCore(bCore);
12554
+ if (a1 !== b1) return a1 - b1;
12555
+ if (a2 !== b2) return a2 - b2;
12556
+ if (a3 !== b3) return a3 - b3;
12557
+ if (!aPre && bPre) return 1;
12558
+ if (aPre && !bPre) return -1;
12559
+ if (!aPre && !bPre) return 0;
12560
+ return aPre.localeCompare(bPre);
12561
+ }
12562
+ function splitPre(v) {
12563
+ const i = v.indexOf("-");
12564
+ return i < 0 ? [v, null] : [v.slice(0, i), v.slice(i + 1)];
12565
+ }
12566
+ function parseCore(core) {
12567
+ const parts = core.split(".").map((s) => parseInt(s, 10) || 0);
12568
+ return [parts[0] ?? 0, parts[1] ?? 0, parts[2] ?? 0];
12569
+ }
12570
+ function ghHeaders(token) {
12571
+ const headers = {
12572
+ "User-Agent": "dimina-kit-updater",
12573
+ "Accept": "application/vnd.github+json",
12574
+ "X-GitHub-Api-Version": "2022-11-28"
12575
+ };
12576
+ if (token) headers.Authorization = `Bearer ${token}`;
12577
+ return headers;
12578
+ }
12579
+ async function fetchRelease(url, opts) {
12580
+ const body = await httpGetText(url, { headers: ghHeaders(opts.token) });
12581
+ if (!body) return null;
12582
+ if (opts.includePrereleases) {
12583
+ const list = JSON.parse(body);
12584
+ const first = list.find((r) => !r.draft);
12585
+ return first ?? null;
12586
+ }
12587
+ const release = JSON.parse(body);
12588
+ return release.draft ? null : release;
12589
+ }
12590
+ function httpGetText(url, init) {
12591
+ return new Promise((resolve, reject) => {
12592
+ const req = https.get(url, { headers: init.headers }, (res) => {
12593
+ if (res.statusCode && res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
12594
+ res.resume();
12595
+ resolve(httpGetText(res.headers.location, init));
12596
+ return;
12597
+ }
12598
+ if (res.statusCode !== 200) {
12599
+ res.resume();
12600
+ resolve(null);
12601
+ return;
12602
+ }
12603
+ let body = "";
12604
+ res.setEncoding("utf8");
12605
+ res.on("data", (chunk) => {
12606
+ body += chunk;
12607
+ });
12608
+ res.on("end", () => resolve(body));
12609
+ });
12610
+ req.on("error", reject);
12611
+ });
12612
+ }
12613
+ function downloadFile(url, dest, token, onProgress) {
12614
+ return new Promise((resolve, reject) => {
12615
+ const headers = ghHeaders(token);
12616
+ const cleanup = () => fs12.promises.unlink(dest).catch(() => {
12617
+ });
12618
+ const attempt = (target, redirectsLeft) => {
12619
+ const req = https.get(target, { headers }, (res) => {
12620
+ if (res.statusCode && res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
12621
+ res.resume();
12622
+ if (redirectsLeft <= 0) {
12623
+ reject(new Error("Too many redirects"));
12624
+ return;
12625
+ }
12626
+ attempt(res.headers.location, redirectsLeft - 1);
12627
+ return;
12628
+ }
12629
+ if (res.statusCode !== 200) {
12630
+ res.resume();
12631
+ reject(new Error(`HTTP ${res.statusCode} while downloading update`));
12632
+ return;
12633
+ }
12634
+ const total = parseInt(res.headers["content-length"] || "0", 10);
12635
+ let received = 0;
12636
+ const out = fs12.createWriteStream(dest);
12637
+ res.on("data", (chunk) => {
12638
+ received += chunk.length;
12639
+ if (total > 0 && onProgress) {
12640
+ onProgress(received / total * 100);
12641
+ }
12642
+ });
12643
+ res.on("error", async (err2) => {
12644
+ out.destroy();
12645
+ await cleanup();
12646
+ reject(err2);
12647
+ });
12648
+ res.pipe(out);
12649
+ out.on("finish", async () => {
12650
+ out.close();
12651
+ if (total > 0 && received !== total) {
12652
+ await cleanup();
12653
+ reject(new Error(`Downloaded ${received} bytes, expected ${total} \u2014 update download was truncated`));
12654
+ return;
12655
+ }
12656
+ resolve();
12657
+ });
12658
+ out.on("error", async (err2) => {
12659
+ await cleanup();
12660
+ reject(err2);
12661
+ });
12662
+ });
12663
+ req.on("error", async (err2) => {
12664
+ await cleanup();
12665
+ reject(err2);
12666
+ });
12667
+ };
12668
+ attempt(url, 5);
12669
+ });
12670
+ }
11685
12671
 
11686
12672
  // src/main/app/app.ts
11687
12673
  import { toDisposable as toDisposable8 } from "@dimina-kit/electron-deck/main";
@@ -11752,7 +12738,7 @@ async function disposeContext(ctx) {
11752
12738
  function createConfiguredMainWindow(config, rendererDir2) {
11753
12739
  const mainWindow = createMainWindow({
11754
12740
  title: config.appName ?? "Dimina DevTools",
11755
- indexHtml: path24.join(rendererDir2, "entries/main/index.html"),
12741
+ indexHtml: path25.join(rendererDir2, "entries/main/index.html"),
11756
12742
  width: config.window?.width,
11757
12743
  height: config.window?.height,
11758
12744
  minWidth: config.window?.minWidth,
@@ -11865,10 +12851,10 @@ function enableDevRendererAutoReload(rendererDir2) {
11865
12851
  });
11866
12852
  }
11867
12853
  let reloadTimer = null;
11868
- const watcher = fs12.watch(rendererDir2, { recursive: true }, () => {
12854
+ const watcher = fs13.watch(rendererDir2, { recursive: true }, () => {
11869
12855
  if (reloadTimer) clearTimeout(reloadTimer);
11870
12856
  reloadTimer = setTimeout(() => {
11871
- for (const win of BrowserWindow8.getAllWindows()) {
12857
+ for (const win of BrowserWindow9.getAllWindows()) {
11872
12858
  win.webContents.reload();
11873
12859
  }
11874
12860
  }, 300);
@@ -11895,7 +12881,7 @@ function runDevtoolsBootstrap(config = {}) {
11895
12881
  } catch {
11896
12882
  }
11897
12883
  }
11898
- async function createDevtoolsRuntime(config = {}) {
12884
+ async function createDevtoolsRuntime(config = {}, onInstanceCreated) {
11899
12885
  await app15.whenReady();
11900
12886
  applyTheme(loadWorkbenchSettings().theme);
11901
12887
  const rendererDir2 = config.rendererDir ?? rendererDir;
@@ -11904,10 +12890,33 @@ async function createDevtoolsRuntime(config = {}) {
11904
12890
  context.connections.acquire(mainWindow.webContents);
11905
12891
  context.registry.add(registerAppIpc(context));
11906
12892
  context.registry.add(registerProjectFsIpc(context));
12893
+ context.internalDevtoolsWindow = createInternalDevtoolsWindow(mainWindow, { isAppQuitting });
12894
+ context.registry.add(toDisposable8(() => context.internalDevtoolsWindow?.dispose()));
12895
+ context.registry.add(registerInternalDevtoolsIpc(context));
11907
12896
  context.registry.add(setupSimulatorSessionPolicy());
11908
12897
  context.registry.add(installThemeBackgroundSync());
11909
12898
  if (!config.adapter) context.registry.add(setupCompileWorkerStandby(context));
11910
12899
  registerBuiltinModules(config, context);
12900
+ if (context.consoleForwarder && context.internalDevtoolsWindow) {
12901
+ const consoleMirror = createGlobalConsoleMirror(
12902
+ context.consoleForwarder,
12903
+ mainWindow.webContents,
12904
+ context.internalDevtoolsWindow.onHostChanged,
12905
+ // CDP transport (never executeJavaScript) — see the mirror's inject()
12906
+ // doc for the setDevToolsWebContents + external-CDP double-attach hang.
12907
+ { broker: context.cdpSessionBroker }
12908
+ );
12909
+ context.registry.add(toDisposable8(() => consoleMirror.dispose()));
12910
+ }
12911
+ if (context.diagnostics && context.internalDevtoolsWindow) {
12912
+ const diagnosticsMirror = createGlobalDiagnosticsMirror(
12913
+ context.diagnostics,
12914
+ mainWindow.webContents,
12915
+ context.internalDevtoolsWindow.onHostChanged,
12916
+ { broker: context.cdpSessionBroker }
12917
+ );
12918
+ context.registry.add(toDisposable8(() => diagnosticsMirror.dispose()));
12919
+ }
11911
12920
  const simSession = session4.fromPartition(SHARED_MINIAPP_PARTITION);
11912
12921
  context.registry.add(setupSimulatorTempFiles(simSession));
11913
12922
  installMenu(config, mainWindow, context);
@@ -11924,6 +12933,7 @@ async function createDevtoolsRuntime(config = {}) {
11924
12933
  registerSimulatorApi: (name, handler) => context.registry.add(toDisposable8(context.simulatorApis.register(name, handler))),
11925
12934
  dispose: () => disposeContext(context)
11926
12935
  };
12936
+ onInstanceCreated?.(instance);
11927
12937
  instance.registerSimulatorApi("login", async () => {
11928
12938
  return "hello";
11929
12939
  });
@@ -12006,6 +13016,17 @@ async function createDevtoolsRuntime(config = {}) {
12006
13016
  if (context.bridge?.isNativeHost()) {
12007
13017
  const networkForward = createNetworkForwarder({
12008
13018
  getServiceWc: (appId) => context.bridge?.getServiceWc(appId) ?? null,
13019
+ getResourceServerBaseUrl: () => context.bridge?.getResourceBaseUrl?.() ?? null,
13020
+ // The simulator shell's own static-asset server (serves simulator.html
13021
+ // + its JS/CSS, independent from the resource server above — see
13022
+ // NetworkForwarderBridge.getSimulatorServerBaseUrl's doc). Host is
13023
+ // always 'localhost' — see shared/simulator-route.ts's
13024
+ // buildSimulatorUrlFromSpec default. Absent (null port) when no
13025
+ // project is open.
13026
+ getSimulatorServerBaseUrl: () => {
13027
+ const port = context.workspace?.getSession()?.port;
13028
+ return typeof port === "number" ? `http://localhost:${port}/` : null;
13029
+ },
12009
13030
  connections: context.connections,
12010
13031
  broker: context.cdpSessionBroker
12011
13032
  });
@@ -12014,6 +13035,12 @@ async function createDevtoolsRuntime(config = {}) {
12014
13035
  context.registry.add(() => {
12015
13036
  context.networkForward = void 0;
12016
13037
  });
13038
+ context.registry.add(toDisposable8(
13039
+ context.internalDevtoolsWindow?.onHostChanged((hostWc) => {
13040
+ context.networkForward?.setGlobalDevtoolsHost(hostWc);
13041
+ }) ?? (() => {
13042
+ })
13043
+ ));
12017
13044
  context.registry.add(setupSimulatorWxml(mainWindow.webContents, {
12018
13045
  senderPolicy: context.senderPolicy,
12019
13046
  bridge: context.bridge,
@@ -12036,8 +13063,8 @@ async function createDevtoolsRuntime(config = {}) {
12036
13063
  bridge: context.bridge
12037
13064
  }));
12038
13065
  }
12039
- const bundleDir = config.editorViewConfig?.bundleDir ?? path24.join(devtoolsPackageRoot, "dist/vscode-workbench");
12040
- if (!fs12.existsSync(path24.join(bundleDir, "index.html"))) {
13066
+ const bundleDir = config.editorViewConfig?.bundleDir ?? path25.join(devtoolsPackageRoot, "dist/vscode-workbench");
13067
+ if (!fs13.existsSync(path25.join(bundleDir, "index.html"))) {
12041
13068
  console.warn(
12042
13069
  `[workbench] editor bundle not found at ${bundleDir} \u2014 skipping embedded editor assembly`
12043
13070
  );
@@ -12074,6 +13101,7 @@ async function createDevtoolsRuntime(config = {}) {
12074
13101
  // src/main/runtime/devtools-backend.ts
12075
13102
  function createDevtoolsBackend(config = {}) {
12076
13103
  let instance = null;
13104
+ let assembling = null;
12077
13105
  return {
12078
13106
  // The backend builds the devtools main window itself (framework skips its own).
12079
13107
  // Its only construction-time needs are the host preload + `sandbox:false`
@@ -12095,15 +13123,33 @@ function createDevtoolsBackend(config = {}) {
12095
13123
  // Setup (post-whenReady): app lifecycle (window-all-closed → quit) + the
12096
13124
  // full devtools assembly.
12097
13125
  assemble: async () => {
12098
- registerAppLifecycle();
12099
- instance = await createDevtoolsRuntime(config);
13126
+ registerAppLifecycle(() => instance?.context.views.disposeAll());
13127
+ assembling = createDevtoolsRuntime(config, (created) => {
13128
+ instance = created;
13129
+ if (isAppQuitting()) instance.context.views.disposeAll();
13130
+ }).then(() => {
13131
+ });
13132
+ await assembling;
12100
13133
  },
12101
13134
  // Dispose the devtools context during the framework's deterministic shutdown
12102
13135
  // (app.on('will-quit') → shutdown() → runShutdownCleanup(), awaited once).
12103
13136
  // Without this, the compile session (a child process, torn down by
12104
13137
  // closeProject) and the IPC registry would leak on exit. The framework awaits
12105
13138
  // this hook, so teardown is no longer a best-effort before-quit reach-around.
12106
- onShutdown: () => instance?.dispose()
13139
+ //
13140
+ // Waits for `assembling` first: `instance` can be non-null (published
13141
+ // early, above) while `createDevtoolsRuntime`'s own async body — the
13142
+ // host's `onSetup` and everything scheduled after it — is still running
13143
+ // and still adding entries to `instance.context.registry`. Disposing
13144
+ // that registry out from under an in-flight assembly throws instead of
13145
+ // tearing down cleanly (`DisposableRegistry.add` rejects post-dispose).
13146
+ // `.catch()` here: assembly failing is `assemble`'s problem to surface,
13147
+ // not a reason to skip disposing whatever DID get constructed.
13148
+ onShutdown: async () => {
13149
+ await assembling?.catch(() => {
13150
+ });
13151
+ await instance?.dispose();
13152
+ }
12107
13153
  };
12108
13154
  }
12109
13155
 
@@ -12113,7 +13159,18 @@ function launch(config = {}) {
12113
13159
  }
12114
13160
 
12115
13161
  // src/main/index.ts
12116
- launch().catch((err2) => {
13162
+ var updateChecker = app16.isPackaged && !app16.getVersion().includes("-dev.") ? createGitHubReleaseChecker({
13163
+ owner: "EchoTechFE",
13164
+ repo: "dimina-kit",
13165
+ parseVersion: (release) => {
13166
+ for (const asset of release.assets) {
13167
+ const match = /^dimina-devtools-(\d+\.\d+\.\d+)-/.exec(asset.name);
13168
+ if (match) return match[1];
13169
+ }
13170
+ return null;
13171
+ }
13172
+ }) : void 0;
13173
+ launch({ updateChecker }).catch((err2) => {
12117
13174
  console.error("[devtools] fatal: launch() failed during boot", err2);
12118
13175
  app16.exit(1);
12119
13176
  });