@dimina-kit/devtools 0.4.0-dev.20260616102751 → 0.4.0-dev.20260624040247

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 (78) hide show
  1. package/README.md +30 -25
  2. package/dist/main/app/app.js +14 -2
  3. package/dist/main/index.bundle.js +559 -111
  4. package/dist/main/ipc/bridge-router.js +57 -9
  5. package/dist/main/ipc/projects.js +1 -1
  6. package/dist/main/ipc/simulator.js +1 -1
  7. package/dist/main/runtime/devtools-backend.d.ts +1 -1
  8. package/dist/main/runtime/devtools-backend.js +1 -1
  9. package/dist/main/runtime/miniapp-runtime.d.ts +5 -5
  10. package/dist/main/services/console-forward/index.js +8 -1
  11. package/dist/main/services/elements-forward/index.js +36 -12
  12. package/dist/main/services/layout/index.d.ts +12 -0
  13. package/dist/main/services/layout/index.js +14 -2
  14. package/dist/main/services/network-forward/index.d.ts +5 -6
  15. package/dist/main/services/network-forward/index.js +9 -10
  16. package/dist/main/services/notifications/renderer-notifier.d.ts +3 -4
  17. package/dist/main/services/projects/index.js +1 -1
  18. package/dist/main/services/projects/types.d.ts +1 -1
  19. package/dist/main/services/projects/types.js +1 -1
  20. package/dist/main/services/service-console/console-api.d.ts +77 -0
  21. package/dist/main/services/service-console/console-api.js +103 -0
  22. package/dist/main/services/service-console/index.d.ts +47 -0
  23. package/dist/main/services/service-console/index.js +139 -0
  24. package/dist/main/services/service-host-pool/pool.d.ts +2 -3
  25. package/dist/main/services/simulator-storage/index.d.ts +2 -4
  26. package/dist/main/services/simulator-storage/index.js +2 -4
  27. package/dist/main/services/simulator-temp-files/index.js +2 -2
  28. package/dist/main/services/update/update-manager.d.ts +1 -1
  29. package/dist/main/services/update/update-manager.js +1 -1
  30. package/dist/main/services/views/host-toolbar-session-runtime.d.ts +4 -4
  31. package/dist/main/services/views/host-toolbar-session-runtime.js +4 -4
  32. package/dist/main/services/views/view-manager.d.ts +24 -1
  33. package/dist/main/services/views/view-manager.js +120 -41
  34. package/dist/main/services/workbench-context.d.ts +7 -6
  35. package/dist/main/services/workspace/workspace-service.js +11 -0
  36. package/dist/main/windows/service-host-window/create.d.ts +1 -0
  37. package/dist/main/windows/service-host-window/create.js +1 -0
  38. package/dist/preload/runtime/host-toolbar-port.d.ts +1 -1
  39. package/dist/preload/runtime/host-toolbar-port.js +1 -1
  40. package/dist/preload/runtime/host-toolbar-runtime.d.ts +8 -7
  41. package/dist/preload/runtime/host-toolbar-runtime.js +8 -7
  42. package/dist/preload/windows/host-toolbar-runtime.cjs.map +2 -2
  43. package/dist/preload/windows/main.cjs.map +2 -2
  44. package/dist/preload/windows/simulator.cjs +1 -1
  45. package/dist/preload/windows/simulator.cjs.map +1 -1
  46. package/dist/preload/windows/simulator.js +1 -1
  47. package/dist/renderer/assets/index-PtsdWlGu.js +50 -0
  48. package/dist/renderer/assets/{input-B8NDCYv3.js → input-DiCxYlqY.js} +2 -2
  49. package/dist/renderer/assets/{ipc-transport-DhrajiC5.js → ipc-transport-DSBmaWpJ.js} +1 -1
  50. package/dist/renderer/assets/ipc-transport-DZxf2YoM.css +1 -0
  51. package/dist/renderer/assets/{popover-DbZOg03s.js → popover-CyL_uffj.js} +2 -2
  52. package/dist/renderer/assets/{select-pW3Ysc9T.js → select-BSwvDMtA.js} +2 -2
  53. package/dist/renderer/assets/settings-Ch8XbFxf.js +2 -0
  54. package/dist/renderer/assets/{settings-api-BSKzKiWd.js → settings-api-e9ILe2JO.js} +2 -2
  55. package/dist/renderer/assets/{workbenchSettings-BGxjl25x.js → workbenchSettings-DZsHf1g_.js} +2 -2
  56. package/dist/renderer/entries/main/index.html +6 -6
  57. package/dist/renderer/entries/popover/index.html +5 -5
  58. package/dist/renderer/entries/settings/index.html +11 -5
  59. package/dist/renderer/entries/workbench-settings/index.html +4 -4
  60. package/dist/service-host/preload.cjs +13 -15
  61. package/dist/service-host/sourcemap-rewrite.cjs +21 -12
  62. package/dist/shared/appdata-accumulator.d.ts +2 -2
  63. package/dist/shared/appdata-accumulator.js +3 -3
  64. package/dist/shared/constants.d.ts +1 -1
  65. package/dist/shared/constants.js +1 -1
  66. package/dist/shared/ipc-channels.d.ts +3 -3
  67. package/dist/shared/ipc-channels.js +3 -3
  68. package/dist/shared/open-in-editor.d.ts +20 -1
  69. package/dist/shared/open-in-editor.js +246 -3
  70. package/dist/shared/vpath.d.ts +2 -2
  71. package/dist/shared/vpath.js +2 -2
  72. package/dist/simulator/assets/{device-shell-BWX7Yopg.js → device-shell-TtcSXwhb.js} +2 -2
  73. package/dist/simulator/assets/{simulator-sf-D0mhw.js → simulator-CtyXt_4V.js} +3 -3
  74. package/dist/simulator/simulator.html +1 -1
  75. package/package.json +8 -6
  76. package/dist/renderer/assets/index-Z4Rh52G8.js +0 -50
  77. package/dist/renderer/assets/ipc-transport-9agi76dX.css +0 -1
  78. package/dist/renderer/assets/settings-CZJOHt8b.js +0 -2
@@ -410,11 +410,11 @@ var ProjectsChannel = {
410
410
  List: "projects:list",
411
411
  Add: "projects:add",
412
412
  Remove: "projects:remove",
413
- /** Phase 3: merged + sanitized template catalog for the create-project dialog. */
413
+ /** Merged + sanitized template catalog for the create-project dialog. */
414
414
  ListTemplates: "projects:listTemplates",
415
- /** Phase 3: host-supplied create-project dialog hook (returns input or null). */
415
+ /** Host-supplied create-project dialog hook (returns input or null). */
416
416
  OpenCreateDialog: "projects:openCreateDialog",
417
- /** Phase 3: server-side scaffold + register (delegates to create-project-service). */
417
+ /** Server-side scaffold + register (delegates to create-project-service). */
418
418
  Create: "projects:create",
419
419
  /** Default values used to pre-fill the create-project dialog (baseDir). */
420
420
  GetCreateDefaults: "projects:getCreateDefaults"
@@ -762,7 +762,7 @@ function registerProjectFsIpc(ctx) {
762
762
 
763
763
  // src/main/app/app.ts
764
764
  import { app as app15, BrowserWindow as BrowserWindow8, nativeImage, session as session4 } from "electron";
765
- import fs10 from "fs";
765
+ import fs11 from "fs";
766
766
  import path21 from "path";
767
767
 
768
768
  // src/main/utils/paths.ts
@@ -1052,6 +1052,7 @@ function createRendererNotifier(ctx) {
1052
1052
 
1053
1053
  // src/main/services/views/view-manager.ts
1054
1054
  import { ipcMain as ipcMain2, nativeTheme as nativeTheme3, shell as shell2, WebContentsView as WebContentsView2, webContents } from "electron";
1055
+ import fs4 from "node:fs";
1055
1056
  import path7 from "path";
1056
1057
 
1057
1058
  // src/shared/open-in-editor.ts
@@ -1078,8 +1079,11 @@ function decodeOpenInEditorUrl(raw) {
1078
1079
  }
1079
1080
  return out;
1080
1081
  }
1081
- function resourceUrlToProjectRelativePath(resourceUrl, expectedOrigin) {
1082
+ function resourceUrlToProjectRelativePath(resourceUrl, expectedOriginOrContext) {
1082
1083
  if (typeof resourceUrl !== "string" || !resourceUrl) return null;
1084
+ if (expectedOriginOrContext && typeof expectedOriginOrContext === "object") {
1085
+ return projectAwareResourcePath(resourceUrl, expectedOriginOrContext);
1086
+ }
1083
1087
  let resource;
1084
1088
  try {
1085
1089
  resource = new URL(resourceUrl);
@@ -1087,10 +1091,10 @@ function resourceUrlToProjectRelativePath(resourceUrl, expectedOrigin) {
1087
1091
  return null;
1088
1092
  }
1089
1093
  if (resource.protocol !== "http:" && resource.protocol !== "https:") return null;
1090
- if (expectedOrigin) {
1094
+ if (expectedOriginOrContext) {
1091
1095
  let base;
1092
1096
  try {
1093
- base = new URL(expectedOrigin);
1097
+ base = new URL(expectedOriginOrContext);
1094
1098
  } catch {
1095
1099
  return null;
1096
1100
  }
@@ -1106,6 +1110,218 @@ function resourceUrlToProjectRelativePath(resourceUrl, expectedOrigin) {
1106
1110
  if (segments.length < 2) return null;
1107
1111
  return segments.slice(1).join("/");
1108
1112
  }
1113
+ function decodePathname(pathname) {
1114
+ return pathname.split("/").map((segment) => {
1115
+ try {
1116
+ return decodeURIComponent(segment);
1117
+ } catch {
1118
+ return segment;
1119
+ }
1120
+ }).join("/");
1121
+ }
1122
+ function normalizeSlashPath(value) {
1123
+ return decodePathname(value.replace(/\\/g, "/")).replace(/\/+/g, "/");
1124
+ }
1125
+ function safeRelativePath(segments) {
1126
+ if (segments.length === 0 || segments.some((segment) => !segment || segment === "." || segment === "..")) {
1127
+ return null;
1128
+ }
1129
+ return segments.join("/");
1130
+ }
1131
+ function projectAwareResourcePath(resourceUrl, context) {
1132
+ let base;
1133
+ try {
1134
+ base = new URL(context.resourceBaseUrl);
1135
+ } catch {
1136
+ return null;
1137
+ }
1138
+ const projectRoot = normalizeSlashPath(context.projectRoot).replace(/\/$/, "");
1139
+ const raw = resourceUrl.trim();
1140
+ if (!raw) return null;
1141
+ const normalizedRaw = normalizeSlashPath(raw);
1142
+ if (projectRoot && (normalizedRaw === projectRoot || normalizedRaw.startsWith(`${projectRoot}/`))) {
1143
+ const relative = normalizedRaw.slice(projectRoot.length).replace(/^\/+/, "");
1144
+ return safeRelativePath(relative.split("/").filter(Boolean));
1145
+ }
1146
+ if (/^\/(?:Volumes|Users|home|private|tmp|var|opt|Applications)\//.test(normalizedRaw)) {
1147
+ return null;
1148
+ }
1149
+ if (!raw.startsWith("/") && !/^[a-z][a-z0-9+.-]*:/i.test(raw)) return null;
1150
+ let resource;
1151
+ try {
1152
+ resource = raw.startsWith("/") && !raw.startsWith("//") ? new URL(raw, base.origin) : new URL(raw);
1153
+ } catch {
1154
+ return null;
1155
+ }
1156
+ if (resource.protocol === "file:") {
1157
+ const filePath = normalizeSlashPath(resource.pathname);
1158
+ if (!projectRoot || filePath !== projectRoot && !filePath.startsWith(`${projectRoot}/`)) return null;
1159
+ return safeRelativePath(
1160
+ filePath.slice(projectRoot.length).replace(/^\/+/, "").split("/").filter(Boolean)
1161
+ );
1162
+ }
1163
+ if (resource.protocol !== "http:" && resource.protocol !== "https:") return null;
1164
+ if (resource.origin !== base.origin) return null;
1165
+ let segments = decodePathname(resource.pathname).split("/").filter(Boolean);
1166
+ if (context.appId && segments[0] === context.appId) {
1167
+ segments = segments.slice(1);
1168
+ if (context.outputRoot && segments[0] === context.outputRoot) segments = segments.slice(1);
1169
+ }
1170
+ return safeRelativePath(segments);
1171
+ }
1172
+ function projectSourceContextFromServiceHostUrl(serviceHostUrl, activeProjectRoot) {
1173
+ let url;
1174
+ try {
1175
+ url = new URL(serviceHostUrl);
1176
+ } catch {
1177
+ return null;
1178
+ }
1179
+ const projectRoot = url.searchParams.get("pkgRoot") || "";
1180
+ const resourceBaseUrl = url.searchParams.get("resourceBaseUrl") ?? "";
1181
+ const appId = url.searchParams.get("appId") ?? "";
1182
+ const outputRoot = url.searchParams.get("root") ?? "main";
1183
+ if (!projectRoot || !resourceBaseUrl || !appId) return null;
1184
+ if (activeProjectRoot) {
1185
+ const authoritativeRoot = normalizeSlashPath(projectRoot).replace(/\/+$/, "");
1186
+ const currentRoot = normalizeSlashPath(activeProjectRoot).replace(/\/+$/, "");
1187
+ if (!authoritativeRoot || authoritativeRoot !== currentRoot) return null;
1188
+ }
1189
+ try {
1190
+ new URL(resourceBaseUrl);
1191
+ } catch {
1192
+ return null;
1193
+ }
1194
+ return { projectRoot, resourceBaseUrl, appId, outputRoot };
1195
+ }
1196
+ function buildDevtoolsProjectSourceLinksScript(context) {
1197
+ const config = JSON.stringify(context);
1198
+ const scheme = JSON.stringify(OPEN_IN_EDITOR_SCHEME);
1199
+ return `
1200
+ (function() {
1201
+ try {
1202
+ const stateKey = '__diminaProjectSourceLinksState__'
1203
+ const previousState = globalThis[stateKey]
1204
+ if (previousState && typeof previousState.dispose === 'function') {
1205
+ try { previousState.dispose() } catch (_) {}
1206
+ }
1207
+
1208
+ const cfg = ${config}
1209
+ const diminaProjectSourcePath = ${projectAwareResourcePath.toString()}
1210
+ const decodePathname = ${decodePathname.toString()}
1211
+ const normalizeSlashPath = ${normalizeSlashPath.toString()}
1212
+ const safeRelativePath = ${safeRelativePath.toString()}
1213
+ const observedRoots = new Set()
1214
+ const observers = []
1215
+ let timer = null
1216
+ const state = {
1217
+ dispose() {
1218
+ if (timer !== null) {
1219
+ clearInterval(timer)
1220
+ timer = null
1221
+ }
1222
+ for (const observer of observers.splice(0)) {
1223
+ try { observer.disconnect() } catch (_) {}
1224
+ }
1225
+ observedRoots.clear()
1226
+ },
1227
+ }
1228
+ globalThis[stateKey] = state
1229
+
1230
+ function splitLocation(value) {
1231
+ const raw = String(value || '')
1232
+ const match = raw.match(/^(.*?)(?::(\\d+))(?::(\\d+))?$/)
1233
+ return match
1234
+ ? { url: match[1], suffix: ':' + match[2] + (match[3] ? ':' + match[3] : '') }
1235
+ : { url: raw, suffix: '' }
1236
+ }
1237
+
1238
+ function rewriteLink(link) {
1239
+ if (!link || link.dataset.diminaProjectSourcePath) return
1240
+ const candidates = [
1241
+ link.getAttribute && link.getAttribute('title'),
1242
+ link.getAttribute && link.getAttribute('href'),
1243
+ link.getAttribute && link.getAttribute('data-url'),
1244
+ ]
1245
+ for (const candidate of candidates) {
1246
+ if (!candidate) continue
1247
+ const location = splitLocation(candidate)
1248
+ const relative = diminaProjectSourcePath(location.url, cfg)
1249
+ if (!relative) continue
1250
+ const textSuffix = location.suffix || ((String(link.textContent || '').match(/(:\\d+(?::\\d+)?)$/) || [])[1] || '')
1251
+ link.textContent = relative + textSuffix
1252
+ link.dataset.diminaProjectSourcePath = relative
1253
+ return
1254
+ }
1255
+ }
1256
+
1257
+ function observeRoot(root) {
1258
+ if (!root || !root.querySelectorAll || observedRoots.has(root)) return
1259
+ observedRoots.add(root)
1260
+
1261
+ const observer = new MutationObserver((records) => {
1262
+ for (const record of records) {
1263
+ if (record.type === 'attributes') rewriteLink(record.target)
1264
+ for (const node of record.addedNodes || []) visitNode(node)
1265
+ }
1266
+ })
1267
+ observer.observe(root, {
1268
+ subtree: true,
1269
+ childList: true,
1270
+ attributes: true,
1271
+ attributeFilter: ['title', 'href', 'data-url'],
1272
+ })
1273
+ observers.push(observer)
1274
+
1275
+ for (const link of root.querySelectorAll('.devtools-link')) rewriteLink(link)
1276
+ for (const element of root.querySelectorAll('*')) {
1277
+ if (element.shadowRoot) observeRoot(element.shadowRoot)
1278
+ }
1279
+ }
1280
+
1281
+ function visitNode(node) {
1282
+ if (!node) return
1283
+ if (node.matches && node.matches('.devtools-link')) rewriteLink(node)
1284
+ if (node.shadowRoot) observeRoot(node.shadowRoot)
1285
+ if (!node.querySelectorAll) return
1286
+ for (const link of node.querySelectorAll('.devtools-link')) rewriteLink(link)
1287
+ for (const element of node.querySelectorAll('*')) {
1288
+ if (element.shadowRoot) observeRoot(element.shadowRoot)
1289
+ }
1290
+ }
1291
+
1292
+ observeRoot(document)
1293
+
1294
+ let tries = 0
1295
+ timer = setInterval(() => {
1296
+ tries++
1297
+ try {
1298
+ const Host = globalThis.Host
1299
+ const host = Host && Host.InspectorFrontendHost
1300
+ if (host && typeof host.setOpenResourceHandler === 'function'
1301
+ && typeof host.openInNewTab === 'function') {
1302
+ host.setOpenResourceHandler((url, lineNumber, columnNumber) => {
1303
+ try {
1304
+ if (!diminaProjectSourcePath(String(url), cfg)) return
1305
+ const p = new URLSearchParams()
1306
+ p.set('u', String(url))
1307
+ if (typeof lineNumber === 'number') p.set('l', String(lineNumber))
1308
+ if (typeof columnNumber === 'number') p.set('c', String(columnNumber))
1309
+ host.openInNewTab(${scheme} + ':?' + p.toString())
1310
+ } catch (_) {}
1311
+ })
1312
+ clearInterval(timer)
1313
+ timer = null
1314
+ }
1315
+ } catch (_) {}
1316
+ if (tries > 80 && timer !== null) {
1317
+ clearInterval(timer)
1318
+ timer = null
1319
+ }
1320
+ }, 50)
1321
+ } catch (_) {}
1322
+ })()
1323
+ `;
1324
+ }
1109
1325
 
1110
1326
  // src/main/services/safe-area/index.ts
1111
1327
  function guestInsets(device, isTabPage2) {
@@ -1276,7 +1492,7 @@ function buildDocumentUpdatedScript() {
1276
1492
  return buildDispatchScript(msg);
1277
1493
  }
1278
1494
  var DRAIN_INTERVAL_MS = 150;
1279
- var INSTALL_POLL_TRIES = 80;
1495
+ var INSTALL_POLL_TRIES = 200;
1280
1496
  var INSTALL_POLL_INTERVAL_MS = 50;
1281
1497
  function installElementsForward(deps) {
1282
1498
  const { devtoolsWc, bridge } = deps;
@@ -1503,6 +1719,14 @@ function installElementsForward(deps) {
1503
1719
  const unsubscribeRenderEvents = bridge.onRenderEvent(onRenderEvent);
1504
1720
  const onReady = () => {
1505
1721
  if (disposed) return;
1722
+ if (installTimer) {
1723
+ clearInterval(installTimer);
1724
+ installTimer = null;
1725
+ }
1726
+ if (drainTimer) {
1727
+ clearInterval(drainTimer);
1728
+ drainTimer = null;
1729
+ }
1506
1730
  let tries = 0;
1507
1731
  installTimer = setInterval(() => {
1508
1732
  tries++;
@@ -1537,11 +1761,8 @@ function installElementsForward(deps) {
1537
1761
  });
1538
1762
  }, DRAIN_INTERVAL_MS);
1539
1763
  };
1540
- if (devtoolsWc.isLoading()) {
1541
- devtoolsWc.once("dom-ready", onReady);
1542
- } else {
1543
- onReady();
1544
- }
1764
+ devtoolsWc.on("dom-ready", onReady);
1765
+ onReady();
1545
1766
  let devtoolsClosedSub;
1546
1767
  try {
1547
1768
  if (deps.connections) devtoolsClosedSub = deps.connections.acquire(devtoolsWc).on("closed", stop);
@@ -1557,10 +1778,160 @@ function installElementsForward(deps) {
1557
1778
  devtoolsClosedSub?.dispose();
1558
1779
  } catch {
1559
1780
  }
1781
+ try {
1782
+ devtoolsWc.removeListener("dom-ready", onReady);
1783
+ } catch {
1784
+ }
1560
1785
  stop();
1561
1786
  };
1562
1787
  }
1563
1788
 
1789
+ // src/main/services/service-console/console-api.ts
1790
+ var RENDER_FORWARD_SOURCE_URL = "dimina://render-console-forward";
1791
+ var KNOWN_LEVELS = /* @__PURE__ */ new Set(["log", "warn", "error", "info", "debug"]);
1792
+ function mapConsoleApiType(type) {
1793
+ if (type === "warning") return "warn";
1794
+ if (type && KNOWN_LEVELS.has(type)) return type;
1795
+ return "log";
1796
+ }
1797
+ var BIGINT_LITERAL = /^-?\d+n$/;
1798
+ function remoteObjectToValue(ro) {
1799
+ if (!ro) return ro;
1800
+ if ("value" in ro) return ro.value;
1801
+ if (typeof ro.unserializableValue === "string") {
1802
+ const u = ro.unserializableValue;
1803
+ if (u === "Infinity") return Infinity;
1804
+ if (u === "-Infinity") return -Infinity;
1805
+ if (u === "NaN") return NaN;
1806
+ if (u === "-0") return -0;
1807
+ if (BIGINT_LITERAL.test(u)) return u;
1808
+ return u;
1809
+ }
1810
+ switch (ro.type) {
1811
+ case "undefined":
1812
+ return void 0;
1813
+ case "function":
1814
+ return ro.description ?? "[Function]";
1815
+ case "symbol":
1816
+ return ro.description ?? "[Symbol]";
1817
+ case "object":
1818
+ if (ro.subtype === "null") return null;
1819
+ return ro.description ?? "[Object]";
1820
+ default:
1821
+ return ro.description ?? "[Unknown]";
1822
+ }
1823
+ }
1824
+ function needsDeepFetch(ro) {
1825
+ if (!ro) return false;
1826
+ if ("value" in ro) return false;
1827
+ return ro.type === "object" && ro.subtype !== "null" && typeof ro.objectId === "string";
1828
+ }
1829
+ function isRenderForwardEvent(params, sentinelUrl) {
1830
+ const top = params?.stackTrace?.callFrames?.[0]?.url;
1831
+ return typeof top === "string" && top === sentinelUrl;
1832
+ }
1833
+
1834
+ // src/main/services/service-console/index.ts
1835
+ function installServiceConsoleForward(deps) {
1836
+ const { serviceWc, emit, connections } = deps;
1837
+ let disposed = false;
1838
+ let selfAttached = false;
1839
+ let tail = Promise.resolve();
1840
+ let closedSub;
1841
+ function usableDebugger() {
1842
+ try {
1843
+ if (serviceWc.isDestroyed()) return false;
1844
+ if (serviceWc.debugger.isAttached()) return true;
1845
+ } catch {
1846
+ return false;
1847
+ }
1848
+ try {
1849
+ serviceWc.debugger.attach("1.3");
1850
+ selfAttached = true;
1851
+ return true;
1852
+ } catch {
1853
+ try {
1854
+ return serviceWc.debugger.isAttached();
1855
+ } catch {
1856
+ return false;
1857
+ }
1858
+ }
1859
+ }
1860
+ async function resolveArg(ro) {
1861
+ if (!needsDeepFetch(ro)) return remoteObjectToValue(ro);
1862
+ try {
1863
+ const res = await serviceWc.debugger.sendCommand("Runtime.callFunctionOn", {
1864
+ objectId: ro.objectId,
1865
+ functionDeclaration: "function () { return this }",
1866
+ returnByValue: true
1867
+ });
1868
+ if (res && res.result && "value" in res.result) return res.result.value;
1869
+ } catch {
1870
+ }
1871
+ return remoteObjectToValue(ro);
1872
+ }
1873
+ async function handleConsoleApi(params) {
1874
+ if (disposed) return;
1875
+ if (isRenderForwardEvent(params, RENDER_FORWARD_SOURCE_URL)) return;
1876
+ const level = mapConsoleApiType(params.type);
1877
+ const rawArgs = Array.isArray(params.args) ? params.args : [];
1878
+ let args;
1879
+ try {
1880
+ args = await Promise.all(rawArgs.map((a) => resolveArg(a)));
1881
+ } catch {
1882
+ args = rawArgs.map((a) => remoteObjectToValue(a));
1883
+ }
1884
+ if (disposed) return;
1885
+ emit({ source: "service", level, args, ts: Date.now() });
1886
+ }
1887
+ const onMessage = (_event, method, params) => {
1888
+ if (disposed) return;
1889
+ if (method !== "Runtime.consoleAPICalled") return;
1890
+ const p = params;
1891
+ tail = tail.then(() => handleConsoleApi(p)).catch(() => {
1892
+ });
1893
+ };
1894
+ function stop() {
1895
+ if (disposed) return;
1896
+ disposed = true;
1897
+ try {
1898
+ closedSub?.dispose();
1899
+ } catch {
1900
+ }
1901
+ try {
1902
+ serviceWc.debugger.removeListener("message", onMessage);
1903
+ } catch {
1904
+ }
1905
+ if (selfAttached) {
1906
+ try {
1907
+ if (!serviceWc.isDestroyed() && serviceWc.debugger.isAttached()) serviceWc.debugger.detach();
1908
+ } catch {
1909
+ }
1910
+ selfAttached = false;
1911
+ }
1912
+ }
1913
+ if (!usableDebugger()) {
1914
+ disposed = true;
1915
+ return { stop() {
1916
+ } };
1917
+ }
1918
+ try {
1919
+ serviceWc.debugger.on("message", onMessage);
1920
+ } catch {
1921
+ stop();
1922
+ return { stop() {
1923
+ } };
1924
+ }
1925
+ serviceWc.debugger.sendCommand("Runtime.enable").catch(() => {
1926
+ });
1927
+ try {
1928
+ if (connections) closedSub = connections.acquire(serviceWc).on("closed", stop);
1929
+ else serviceWc.once("destroyed", stop);
1930
+ } catch {
1931
+ }
1932
+ return { stop };
1933
+ }
1934
+
1564
1935
  // src/main/services/layout/index.ts
1565
1936
  function computeNativeSimulatorViewParams(rect, zoomPercent) {
1566
1937
  const zoomFactor = zoomPercent / 100;
@@ -1574,12 +1945,11 @@ function computeNativeSimulatorViewParams(rect, zoomPercent) {
1574
1945
  zoomFactor
1575
1946
  };
1576
1947
  }
1577
- var SETTINGS_W = 320;
1578
1948
  function computeSettingsBounds(contentWidth, contentHeight, headerHeight) {
1579
1949
  return {
1580
- x: Math.max(0, contentWidth - SETTINGS_W),
1950
+ x: 0,
1581
1951
  y: headerHeight,
1582
- width: Math.min(SETTINGS_W, Math.max(1, contentWidth)),
1952
+ width: Math.max(1, contentWidth),
1583
1953
  height: Math.max(1, contentHeight - headerHeight)
1584
1954
  };
1585
1955
  }
@@ -1868,12 +2238,36 @@ function parseRoute(url) {
1868
2238
  }
1869
2239
 
1870
2240
  // src/main/services/views/view-manager.ts
2241
+ function resolveProjectEditorTarget(serviceHostUrl, activeProjectRoot, req, isFile = (absolutePath) => fs4.statSync(absolutePath).isFile()) {
2242
+ const sourceContext = projectSourceContextFromServiceHostUrl(
2243
+ serviceHostUrl,
2244
+ activeProjectRoot
2245
+ );
2246
+ if (!sourceContext) return null;
2247
+ const rel = resourceUrlToProjectRelativePath(req.url, sourceContext);
2248
+ if (!rel) return null;
2249
+ const absolute = path7.resolve(sourceContext.projectRoot, ...rel.split("/"));
2250
+ const fromRoot = path7.relative(path7.resolve(sourceContext.projectRoot), absolute);
2251
+ if (!fromRoot || fromRoot.startsWith("..") || path7.isAbsolute(fromRoot)) return null;
2252
+ try {
2253
+ if (!isFile(absolute)) return null;
2254
+ } catch {
2255
+ return null;
2256
+ }
2257
+ return {
2258
+ path: rel,
2259
+ line: typeof req.line === "number" ? req.line + 1 : void 0,
2260
+ column: typeof req.column === "number" ? req.column + 1 : void 0
2261
+ };
2262
+ }
1871
2263
  function createViewManager(ctx) {
1872
2264
  const safeArea = createSafeAreaController({ connections: ctx.connections });
1873
2265
  let simulatorView = null;
1874
2266
  let simulatorViewAdded = false;
1875
2267
  let nativeSimulatorView = null;
1876
2268
  let nativeSimulatorViewAdded = false;
2269
+ let nativeSimulatorProjectPath = null;
2270
+ let settleNativeSimulatorReady = null;
1877
2271
  let lastRendererRect = null;
1878
2272
  let nativeCustomApiBridgeHandler = null;
1879
2273
  let currentZoomFactor = 1;
@@ -1884,6 +2278,7 @@ function createViewManager(ctx) {
1884
2278
  let nativeDevtoolsSourceWc = null;
1885
2279
  let unsubscribeNativeRenderEvents = null;
1886
2280
  let stopElementsForward = null;
2281
+ let stopServiceConsole = null;
1887
2282
  let nativeDevtoolsRetryTimer = null;
1888
2283
  let nativeDevtoolsRetryToken = 0;
1889
2284
  let simulatorBoundsOverride = null;
@@ -1931,6 +2326,7 @@ function createViewManager(ctx) {
1931
2326
  if (!simulatorViewAdded) {
1932
2327
  ctx.windows.mainWindow.contentView.addChildView(simulatorView);
1933
2328
  simulatorViewAdded = true;
2329
+ raiseTopOverlays();
1934
2330
  }
1935
2331
  simulatorView.setBounds(bounds);
1936
2332
  }
@@ -2079,6 +2475,11 @@ function createViewManager(ctx) {
2079
2475
  function closeNativeDevtoolsSource() {
2080
2476
  const source = nativeDevtoolsSourceWc;
2081
2477
  nativeDevtoolsSourceWc = null;
2478
+ try {
2479
+ stopServiceConsole?.();
2480
+ } catch {
2481
+ }
2482
+ stopServiceConsole = null;
2082
2483
  if (!source || source.isDestroyed()) return;
2083
2484
  try {
2084
2485
  if (source.isDevToolsOpened()) {
@@ -2099,37 +2500,13 @@ function createViewManager(ctx) {
2099
2500
  closeNativeDevtoolsSource();
2100
2501
  }
2101
2502
  const openInEditorWiredWcIds = /* @__PURE__ */ new Set();
2102
- function injectOpenResourceHandler(devtoolsWc) {
2103
- const scheme = JSON.stringify(OPEN_IN_EDITOR_SCHEME);
2104
- devtoolsWc.executeJavaScript(`
2105
- (function() {
2106
- try {
2107
- let tries = 0
2108
- const timer = setInterval(() => {
2109
- tries++
2110
- try {
2111
- const Host = globalThis.Host
2112
- const host = Host && Host.InspectorFrontendHost
2113
- if (host && typeof host.setOpenResourceHandler === 'function'
2114
- && typeof host.openInNewTab === 'function') {
2115
- host.setOpenResourceHandler((url, lineNumber, columnNumber) => {
2116
- try {
2117
- const p = new URLSearchParams()
2118
- p.set('u', String(url))
2119
- if (typeof lineNumber === 'number') p.set('l', String(lineNumber))
2120
- if (typeof columnNumber === 'number') p.set('c', String(columnNumber))
2121
- host.openInNewTab(${scheme} + ':?' + p.toString())
2122
- } catch (_) {}
2123
- })
2124
- clearInterval(timer)
2125
- return
2126
- }
2127
- } catch (_) {}
2128
- if (tries > 80) clearInterval(timer)
2129
- }, 50)
2130
- } catch (_) {}
2131
- })()
2132
- `).catch(() => {
2503
+ function injectOpenResourceHandler(serviceWc, devtoolsWc) {
2504
+ const sourceContext = projectSourceContextFromServiceHostUrl(
2505
+ serviceWc.getURL(),
2506
+ ctx.workspace?.getProjectPath?.()
2507
+ );
2508
+ if (!sourceContext) return;
2509
+ devtoolsWc.executeJavaScript(buildDevtoolsProjectSourceLinksScript(sourceContext)).catch(() => {
2133
2510
  });
2134
2511
  }
2135
2512
  function customizeDevtoolsTabs(devtoolsWc) {
@@ -2154,9 +2531,9 @@ function createViewManager(ctx) {
2154
2531
  function wireOpenInEditor(serviceWc, devtoolsWc) {
2155
2532
  if (!devtoolsWc.isDestroyed()) {
2156
2533
  if (devtoolsWc.isLoading()) {
2157
- devtoolsWc.once("dom-ready", () => injectOpenResourceHandler(devtoolsWc));
2534
+ devtoolsWc.once("dom-ready", () => injectOpenResourceHandler(serviceWc, devtoolsWc));
2158
2535
  } else {
2159
- injectOpenResourceHandler(devtoolsWc);
2536
+ injectOpenResourceHandler(serviceWc, devtoolsWc);
2160
2537
  }
2161
2538
  }
2162
2539
  if (openInEditorWiredWcIds.has(serviceWc.id)) return;
@@ -2164,11 +2541,13 @@ function createViewManager(ctx) {
2164
2541
  const onOpenUrl = (_event, url) => {
2165
2542
  const req = decodeOpenInEditorUrl(url);
2166
2543
  if (!req) return;
2167
- const rel = resourceUrlToProjectRelativePath(req.url);
2168
- if (!rel) return;
2169
- const line = typeof req.line === "number" ? req.line + 1 : void 0;
2170
- const column = typeof req.column === "number" ? req.column + 1 : void 0;
2171
- ctx.notify.editorOpenFile({ path: rel, line, column });
2544
+ const target = resolveProjectEditorTarget(
2545
+ serviceWc.getURL(),
2546
+ ctx.workspace?.getProjectPath?.(),
2547
+ req
2548
+ );
2549
+ if (!target) return;
2550
+ ctx.notify.editorOpenFile(target);
2172
2551
  };
2173
2552
  serviceWc.on("devtools-open-url", onOpenUrl);
2174
2553
  const conn = ctx.connections.acquire(serviceWc);
@@ -2192,6 +2571,15 @@ function createViewManager(ctx) {
2192
2571
  next.openDevTools({ mode: "detach", activate: false });
2193
2572
  wireOpenInEditor(next, simulatorView.webContents);
2194
2573
  customizeDevtoolsTabs(simulatorView.webContents);
2574
+ try {
2575
+ stopServiceConsole?.();
2576
+ } catch {
2577
+ }
2578
+ stopServiceConsole = installServiceConsoleForward({
2579
+ serviceWc: next,
2580
+ connections: ctx.connections,
2581
+ emit: (entry) => ctx.consoleForwarder?.emit(entry)
2582
+ }).stop;
2195
2583
  return true;
2196
2584
  } catch {
2197
2585
  if (nativeDevtoolsSourceWc?.id === next.id) {
@@ -2319,8 +2707,10 @@ function createViewManager(ctx) {
2319
2707
  function attachNativeSimulator(simulatorUrl, _simWidth) {
2320
2708
  if (!ctx.preloadPath) {
2321
2709
  console.error("[workbench] attachNativeSimulator \u2014 preloadPath unset; cannot mount native simulator");
2322
- return;
2710
+ return Promise.resolve();
2323
2711
  }
2712
+ settleNativeSimulatorReady?.();
2713
+ settleNativeSimulatorReady = null;
2324
2714
  if (nativeSimulatorView) {
2325
2715
  detachNativeCustomApiBridge();
2326
2716
  if (nativeSimulatorViewAdded) {
@@ -2338,6 +2728,10 @@ function createViewManager(ctx) {
2338
2728
  }
2339
2729
  nativeSimulatorView = null;
2340
2730
  }
2731
+ nativeSimulatorProjectPath = null;
2732
+ const ready = new Promise((resolve) => {
2733
+ settleNativeSimulatorReady = resolve;
2734
+ });
2341
2735
  const route = parseRoute(simulatorUrl);
2342
2736
  const partition = miniappPartition(route?.appId);
2343
2737
  configureMiniappSession(partition);
@@ -2352,6 +2746,7 @@ function createViewManager(ctx) {
2352
2746
  }
2353
2747
  });
2354
2748
  nativeSimulatorView = view;
2749
+ nativeSimulatorProjectPath = ctx.workspace?.getProjectPath() || null;
2355
2750
  view.setBackgroundColor(simDeskBg());
2356
2751
  const simWc = view.webContents;
2357
2752
  const syncDeskBg = () => {
@@ -2401,6 +2796,11 @@ function createViewManager(ctx) {
2401
2796
  e.preventDefault();
2402
2797
  }
2403
2798
  });
2799
+ guestWc.once("did-finish-load", () => {
2800
+ if (nativeSimulatorView !== view || simWc.isDestroyed()) return;
2801
+ settleNativeSimulatorReady?.();
2802
+ settleNativeSimulatorReady = null;
2803
+ });
2404
2804
  followNativeDevtoolsServiceHost();
2405
2805
  });
2406
2806
  simWc.setWindowOpenHandler(({ url }) => handleWindowOpenExternal(url));
@@ -2429,8 +2829,11 @@ function createViewManager(ctx) {
2429
2829
  setNativeSimulatorViewBounds(lastRendererRect);
2430
2830
  }
2431
2831
  attachNativeSimulatorDevtoolsHost();
2832
+ return ready;
2432
2833
  }
2433
2834
  function detachSimulator() {
2835
+ settleNativeSimulatorReady?.();
2836
+ settleNativeSimulatorReady = null;
2434
2837
  stopFollowingNativeServiceHost();
2435
2838
  detachNativeCustomApiBridge();
2436
2839
  try {
@@ -2464,6 +2867,7 @@ function createViewManager(ctx) {
2464
2867
  simulatorView = null;
2465
2868
  simulatorViewAdded = false;
2466
2869
  simulatorWebContentsId = null;
2870
+ nativeSimulatorProjectPath = null;
2467
2871
  simulatorBoundsOverride = null;
2468
2872
  lastRendererRect = null;
2469
2873
  }
@@ -2488,6 +2892,7 @@ function createViewManager(ctx) {
2488
2892
  }
2489
2893
  });
2490
2894
  applyNavigationHardening(settingsView.webContents, ctx.rendererDir);
2895
+ settingsView.setBackgroundColor("#00000000");
2491
2896
  await settingsView.webContents.loadFile(
2492
2897
  path7.join(ctx.rendererDir, "entries/settings/index.html")
2493
2898
  );
@@ -2507,6 +2912,12 @@ function createViewManager(ctx) {
2507
2912
  settingsViewAdded = false;
2508
2913
  }
2509
2914
  }
2915
+ function raiseTopOverlays() {
2916
+ if (ctx.windows.mainWindow.isDestroyed()) return;
2917
+ const cv = ctx.windows.mainWindow.contentView;
2918
+ if (settingsView && settingsViewAdded) cv.addChildView(settingsView);
2919
+ if (popoverView) cv.addChildView(popoverView);
2920
+ }
2510
2921
  function showPopover(data) {
2511
2922
  hidePopover();
2512
2923
  const popover = new WebContentsView2({
@@ -2572,6 +2983,7 @@ function createViewManager(ctx) {
2572
2983
  if (!nativeSimulatorViewAdded) {
2573
2984
  ctx.windows.mainWindow.contentView.addChildView(nativeSimulatorView);
2574
2985
  nativeSimulatorViewAdded = true;
2986
+ raiseTopOverlays();
2575
2987
  }
2576
2988
  nativeSimulatorView.setBounds(p.bounds);
2577
2989
  const simWc = nativeSimulatorView.webContents;
@@ -2607,6 +3019,7 @@ function createViewManager(ctx) {
2607
3019
  const wc = webContents.fromId(simulatorWebContentsId);
2608
3020
  return wc && !wc.isDestroyed() ? wc : null;
2609
3021
  },
3022
+ getSimulatorProjectPath: () => nativeSimulatorProjectPath,
2610
3023
  getSettingsWebContents: () => {
2611
3024
  if (!settingsView) return null;
2612
3025
  if (settingsView.webContents.isDestroyed()) return null;
@@ -2731,20 +3144,20 @@ import { z as z2 } from "zod";
2731
3144
  // src/main/services/projects/project-repository.ts
2732
3145
  import { app as app6 } from "electron";
2733
3146
  import path9 from "path";
2734
- import fs4 from "fs";
3147
+ import fs5 from "fs";
2735
3148
  var log2 = createLogger("projects");
2736
3149
  function getProjectsFile() {
2737
3150
  return path9.join(app6.getPath("userData"), "dimina-projects.json");
2738
3151
  }
2739
3152
  function load() {
2740
3153
  try {
2741
- return JSON.parse(fs4.readFileSync(getProjectsFile(), "utf-8"));
3154
+ return JSON.parse(fs5.readFileSync(getProjectsFile(), "utf-8"));
2742
3155
  } catch {
2743
3156
  return [];
2744
3157
  }
2745
3158
  }
2746
3159
  function save(projects) {
2747
- fs4.writeFileSync(getProjectsFile(), JSON.stringify(projects, null, 2));
3160
+ fs5.writeFileSync(getProjectsFile(), JSON.stringify(projects, null, 2));
2748
3161
  }
2749
3162
  function listProjects() {
2750
3163
  return load();
@@ -2753,14 +3166,14 @@ function validateProjectDir(dirPath) {
2753
3166
  if (!dirPath) {
2754
3167
  return "\u5C0F\u7A0B\u5E8F\u76EE\u5F55\u8DEF\u5F84\u4E3A\u7A7A\uFF0C\u8BF7\u9009\u62E9\u5305\u542B\u5C0F\u7A0B\u5E8F\u6E90\u7801\u7684\u76EE\u5F55";
2755
3168
  }
2756
- if (!fs4.existsSync(dirPath)) {
3169
+ if (!fs5.existsSync(dirPath)) {
2757
3170
  return `\u5C0F\u7A0B\u5E8F\u76EE\u5F55\u4E0D\u5B58\u5728\uFF1A${dirPath}`;
2758
3171
  }
2759
- if (!fs4.existsSync(path9.join(dirPath, "app.json"))) {
3172
+ if (!fs5.existsSync(path9.join(dirPath, "app.json"))) {
2760
3173
  const configPath = path9.join(dirPath, "project.config.json");
2761
- if (fs4.existsSync(configPath)) {
3174
+ if (fs5.existsSync(configPath)) {
2762
3175
  try {
2763
- const cfg = JSON.parse(fs4.readFileSync(configPath, "utf-8"));
3176
+ const cfg = JSON.parse(fs5.readFileSync(configPath, "utf-8"));
2764
3177
  if (cfg.miniprogramRoot) {
2765
3178
  const resolvedRoot = path9.resolve(dirPath, cfg.miniprogramRoot);
2766
3179
  return `\u8BE5\u76EE\u5F55\u7F3A\u5C11 app.json\uFF0Cproject.config.json \u4E2D\u6307\u5B9A\u4E86 miniprogramRoot: "${cfg.miniprogramRoot}"\uFF0C\u8BF7\u5BFC\u5165 ${resolvedRoot}`;
@@ -2778,8 +3191,8 @@ function addProject(dirPath) {
2778
3191
  let name = path9.basename(dirPath);
2779
3192
  try {
2780
3193
  const configPath = path9.join(dirPath, "project.config.json");
2781
- if (fs4.existsSync(configPath)) {
2782
- const cfg = JSON.parse(fs4.readFileSync(configPath, "utf-8"));
3194
+ if (fs5.existsSync(configPath)) {
3195
+ const cfg = JSON.parse(fs5.readFileSync(configPath, "utf-8"));
2783
3196
  if (cfg.projectname) name = cfg.projectname;
2784
3197
  }
2785
3198
  } catch (err) {
@@ -2819,7 +3232,7 @@ function getProjectPages(dirPath) {
2819
3232
  const appJsonPath = path9.join(dirPath, "app.json");
2820
3233
  try {
2821
3234
  const appJson = JSON.parse(
2822
- fs4.readFileSync(appJsonPath, "utf-8")
3235
+ fs5.readFileSync(appJsonPath, "utf-8")
2823
3236
  );
2824
3237
  return {
2825
3238
  pages: appJson.pages || [],
@@ -2843,7 +3256,7 @@ function getProjectSettings(projectPath) {
2843
3256
  }
2844
3257
  try {
2845
3258
  const configPath = path9.join(projectPath, "project.config.json");
2846
- const config = JSON.parse(fs4.readFileSync(configPath, "utf-8"));
3259
+ const config = JSON.parse(fs5.readFileSync(configPath, "utf-8"));
2847
3260
  return {
2848
3261
  uploadWithSourceMap: !!config.setting?.uploadWithSourceMap
2849
3262
  };
@@ -2856,14 +3269,14 @@ function updateProjectSettings(projectPath, patch) {
2856
3269
  const configPath = path9.join(projectPath, "project.config.json");
2857
3270
  let config = {};
2858
3271
  try {
2859
- config = JSON.parse(fs4.readFileSync(configPath, "utf-8"));
3272
+ config = JSON.parse(fs5.readFileSync(configPath, "utf-8"));
2860
3273
  } catch {
2861
3274
  }
2862
3275
  const nextSetting = {
2863
3276
  ...config.setting ?? {},
2864
3277
  ...patch.uploadWithSourceMap === void 0 ? {} : { uploadWithSourceMap: patch.uploadWithSourceMap }
2865
3278
  };
2866
- fs4.writeFileSync(
3279
+ fs5.writeFileSync(
2867
3280
  configPath,
2868
3281
  JSON.stringify({ ...config, setting: nextSetting }, null, 2)
2869
3282
  );
@@ -3038,10 +3451,16 @@ function createWorkspaceService(ctx) {
3038
3451
  getLastClosedProjectPath: () => lastClosedProjectPath,
3039
3452
  hasActiveSession: () => currentSession !== null,
3040
3453
  async captureThumbnail(projectPath) {
3454
+ if (!currentSession || projectPath !== currentProjectPath) return null;
3041
3455
  const wc = ctx.views.getSimulatorWebContents();
3042
3456
  if (!wc) return null;
3457
+ if (ctx.views.getSimulatorProjectPath() !== projectPath) return null;
3458
+ const session5 = currentSession;
3043
3459
  try {
3044
3460
  const image = await wc.capturePage();
3461
+ if (currentSession !== session5 || currentProjectPath !== projectPath || ctx.views.getSimulatorWebContents() !== wc || ctx.views.getSimulatorProjectPath() !== projectPath) {
3462
+ return null;
3463
+ }
3045
3464
  const dataUrl = `data:image/png;base64,${image.toPNG().toString("base64")}`;
3046
3465
  if (provider.saveThumbnail) {
3047
3466
  await provider.saveThumbnail(projectPath, dataUrl);
@@ -3075,7 +3494,7 @@ function createWorkspaceService(ctx) {
3075
3494
 
3076
3495
  // src/main/services/projects/thumbnail.ts
3077
3496
  import { createHash } from "crypto";
3078
- import fs5 from "fs";
3497
+ import fs6 from "fs";
3079
3498
  import path10 from "path";
3080
3499
  import { app as app7 } from "electron";
3081
3500
  function getThumbnailDir() {
@@ -3091,13 +3510,13 @@ var DATA_URL_PNG_PREFIX = "data:image/png;base64,";
3091
3510
  function saveThumbnailFromDataUrl(projectPath, imageDataUrl) {
3092
3511
  if (!imageDataUrl.startsWith(DATA_URL_PNG_PREFIX)) return;
3093
3512
  const png = Buffer.from(imageDataUrl.slice(DATA_URL_PNG_PREFIX.length), "base64");
3094
- fs5.mkdirSync(getThumbnailDir(), { recursive: true });
3095
- fs5.writeFileSync(getThumbnailPath(projectPath), png);
3513
+ fs6.mkdirSync(getThumbnailDir(), { recursive: true });
3514
+ fs6.writeFileSync(getThumbnailPath(projectPath), png);
3096
3515
  }
3097
3516
  function loadThumbnail(projectPath) {
3098
3517
  const filePath = getThumbnailPath(projectPath);
3099
3518
  try {
3100
- const buf = fs5.readFileSync(filePath);
3519
+ const buf = fs6.readFileSync(filePath);
3101
3520
  return `${DATA_URL_PNG_PREFIX}${buf.toString("base64")}`;
3102
3521
  } catch {
3103
3522
  return null;
@@ -3457,7 +3876,7 @@ function deviceInfoToHostEnv(d) {
3457
3876
  function registerSimulatorIpc(ctx) {
3458
3877
  return new IpcRegistry(ctx.senderPolicy).handle(SimulatorChannel.AttachNative, (_, ...args) => {
3459
3878
  const [simulatorUrl, simWidth] = validate(SimulatorChannel.AttachNative, SimulatorAttachNativeSchema, args);
3460
- ctx.views.attachNativeSimulator(simulatorUrl, simWidth);
3879
+ return ctx.views.attachNativeSimulator(simulatorUrl, simWidth);
3461
3880
  }).handle(SimulatorChannel.Detach, () => {
3462
3881
  ctx.views.detachSimulator();
3463
3882
  }).handle(SimulatorChannel.SetNativeBounds, (_, ...args) => {
@@ -3499,7 +3918,7 @@ import { app as app8, dialog } from "electron";
3499
3918
  import path13 from "path";
3500
3919
 
3501
3920
  // src/main/services/projects/create-project-service.ts
3502
- import fs6 from "node:fs";
3921
+ import fs7 from "node:fs";
3503
3922
  import path12 from "node:path";
3504
3923
  var DEFAULT_TEMPLATE_ID = "blank";
3505
3924
  async function createProject(input, ctx) {
@@ -3511,12 +3930,12 @@ async function createProject(input, ctx) {
3511
3930
  if (!target || typeof target !== "string") {
3512
3931
  throw new Error("Project path is required");
3513
3932
  }
3514
- if (fs6.existsSync(target)) {
3515
- const stat = fs6.statSync(target);
3933
+ if (fs7.existsSync(target)) {
3934
+ const stat = fs7.statSync(target);
3516
3935
  if (!stat.isDirectory()) {
3517
3936
  throw new Error(`Project path exists and is not a directory: ${target}`);
3518
3937
  }
3519
- const entries = fs6.readdirSync(target);
3938
+ const entries = fs7.readdirSync(target);
3520
3939
  if (entries.length > 0) {
3521
3940
  throw new Error(
3522
3941
  `Project path is not empty (refusing to overwrite): ${target}`
@@ -3533,31 +3952,31 @@ async function createProject(input, ctx) {
3533
3952
  `Template '${templateId}' has neither a source directory nor a generate function`
3534
3953
  );
3535
3954
  }
3536
- fs6.mkdirSync(target, { recursive: true });
3955
+ fs7.mkdirSync(target, { recursive: true });
3537
3956
  if (template.generate) {
3538
3957
  await template.generate(target, { name });
3539
3958
  } else if (template.source) {
3540
- if (!fs6.existsSync(template.source.path)) {
3959
+ if (!fs7.existsSync(template.source.path)) {
3541
3960
  throw new Error(
3542
3961
  `Template source missing on disk: ${template.source.path}`
3543
3962
  );
3544
3963
  }
3545
- fs6.cpSync(template.source.path, target, {
3964
+ fs7.cpSync(template.source.path, target, {
3546
3965
  recursive: true,
3547
3966
  force: true
3548
3967
  });
3549
3968
  }
3550
3969
  const cfgPath = path12.join(target, "project.config.json");
3551
3970
  let cfg = {};
3552
- if (fs6.existsSync(cfgPath)) {
3971
+ if (fs7.existsSync(cfgPath)) {
3553
3972
  try {
3554
- cfg = JSON.parse(fs6.readFileSync(cfgPath, "utf-8"));
3973
+ cfg = JSON.parse(fs7.readFileSync(cfgPath, "utf-8"));
3555
3974
  } catch {
3556
3975
  cfg = {};
3557
3976
  }
3558
3977
  }
3559
3978
  cfg.projectname = name;
3560
- fs6.writeFileSync(cfgPath, JSON.stringify(cfg, null, 2));
3979
+ fs7.writeFileSync(cfgPath, JSON.stringify(cfg, null, 2));
3561
3980
  const created = await ctx.projectsProvider.addProject(target);
3562
3981
  return created;
3563
3982
  }
@@ -3819,7 +4238,7 @@ import { createDebugTap } from "@dimina-kit/electron-deck/main";
3819
4238
 
3820
4239
  // src/main/services/dimina-resource-server.ts
3821
4240
  import http from "node:http";
3822
- import fs7 from "node:fs";
4241
+ import fs8 from "node:fs";
3823
4242
  import path14 from "node:path";
3824
4243
  var MIME_TYPES = {
3825
4244
  ".css": "text/css; charset=utf-8",
@@ -3877,7 +4296,7 @@ async function handleRequest(root, req, res) {
3877
4296
  return;
3878
4297
  }
3879
4298
  try {
3880
- const stat = await fs7.promises.stat(filePath);
4299
+ const stat = await fs8.promises.stat(filePath);
3881
4300
  if (!stat.isFile()) {
3882
4301
  res.writeHead(404);
3883
4302
  res.end("Not Found");
@@ -3892,7 +4311,7 @@ async function handleRequest(root, req, res) {
3892
4311
  res.end();
3893
4312
  return;
3894
4313
  }
3895
- fs7.createReadStream(filePath).pipe(res);
4314
+ fs8.createReadStream(filePath).pipe(res);
3896
4315
  } catch {
3897
4316
  res.writeHead(404);
3898
4317
  res.end("Not Found");
@@ -3942,6 +4361,7 @@ function buildServiceHostSpawnUrl(opts) {
3942
4361
  url.searchParams.set("appId", opts.appId);
3943
4362
  url.searchParams.set("pagePath", opts.pagePath);
3944
4363
  url.searchParams.set("pkgRoot", opts.pkgRoot);
4364
+ url.searchParams.set("root", opts.root || "main");
3945
4365
  url.searchParams.set("resourceBaseUrl", opts.resourceBaseUrl);
3946
4366
  if (opts.hostEnvSnapshot) {
3947
4367
  url.searchParams.set("hostEnv", encodeURIComponent(JSON.stringify(opts.hostEnvSnapshot)));
@@ -4301,7 +4721,8 @@ var FORWARDABLE_LEVELS = /* @__PURE__ */ new Set(["log", "warn", "error", "info"
4301
4721
  function buildForwardScript(level, args) {
4302
4722
  const method = FORWARDABLE_LEVELS.has(level) ? level : "log";
4303
4723
  const argsJson = JSON.stringify(args ?? []);
4304
- return `(()=>{try{const a=JSON.parse(${JSON.stringify(argsJson)});console[${JSON.stringify(method)}]('[\u89C6\u56FE]',...a)}catch(_){}})()`;
4724
+ return `(()=>{try{const a=JSON.parse(${JSON.stringify(argsJson)});console[${JSON.stringify(method)}]('[\u89C6\u56FE]',...a)}catch(_){}})()
4725
+ //# sourceURL=${RENDER_FORWARD_SOURCE_URL}`;
4305
4726
  }
4306
4727
  function createConsoleForwarder(bridge) {
4307
4728
  const sinks = /* @__PURE__ */ new Set();
@@ -4836,6 +5257,27 @@ function findSimulatorWebContents() {
4836
5257
  }
4837
5258
 
4838
5259
  // src/main/ipc/bridge-router.ts
5260
+ function rewriteSourceMappingUrl(source, scriptUrl) {
5261
+ if (typeof source !== "string" || !source) return source;
5262
+ const re = /(^|\n)[ \t]*\/\/[#@][ \t]*sourceMappingURL=([^\n]*)/g;
5263
+ let lastIndex = -1;
5264
+ let lastValue = "";
5265
+ let m;
5266
+ while ((m = re.exec(source)) !== null) {
5267
+ lastIndex = m.index + m[1].length;
5268
+ lastValue = (m[2] || "").trim();
5269
+ }
5270
+ if (lastIndex < 0 || !lastValue) return source;
5271
+ if (/^(?:[a-z][a-z0-9+.-]*:)?\/\//i.test(lastValue) || /^data:/i.test(lastValue)) return source;
5272
+ let absolute;
5273
+ try {
5274
+ absolute = new URL(lastValue, scriptUrl).toString();
5275
+ } catch {
5276
+ return source;
5277
+ }
5278
+ return `${source.slice(0, lastIndex)}
5279
+ //# sourceMappingURL=${absolute}`;
5280
+ }
4839
5281
  var STACK_ID = "stack_0";
4840
5282
  var PREWARM_MAX_POOL_SIZE = 4;
4841
5283
  function resolvePrewarmPoolSize() {
@@ -5158,7 +5600,8 @@ async function handleSpawn(state, ctx, event, opts) {
5158
5600
  const appSessionId = bridgeId;
5159
5601
  const simulatorWc = resolveSimulatorWebContents(ctx, opts.simulatorWcId, event.sender);
5160
5602
  const pagePath = normalizePagePath(opts.pagePath || "pages/index/index");
5161
- const pkgRoot = path16.resolve(opts.pkgRoot || process.cwd());
5603
+ const workspaceProjectPath = typeof ctx.workspace.getProjectPath === "function" ? ctx.workspace.getProjectPath() : "";
5604
+ const pkgRoot = path16.resolve(opts.pkgRoot || workspaceProjectPath || process.cwd());
5162
5605
  const root = opts.root || "main";
5163
5606
  let resourceServer = null;
5164
5607
  let resourceBaseUrl;
@@ -5192,6 +5635,7 @@ async function handleSpawn(state, ctx, event, opts) {
5192
5635
  appId,
5193
5636
  pagePath,
5194
5637
  pkgRoot,
5638
+ root,
5195
5639
  resourceBaseUrl,
5196
5640
  hostEnvSnapshot: hostEnv
5197
5641
  });
@@ -5269,6 +5713,7 @@ async function handleSpawn(state, ctx, event, opts) {
5269
5713
  appId,
5270
5714
  pagePath,
5271
5715
  pkgRoot,
5716
+ root,
5272
5717
  resourceBaseUrl,
5273
5718
  hostEnvSnapshot: hostEnv
5274
5719
  })
@@ -5365,7 +5810,7 @@ async function injectLogicBundle(ap) {
5365
5810
  try {
5366
5811
  const res = await fetch(logicUrl);
5367
5812
  if (!res.ok) throw new Error(`logic.js fetch ${res.status} at ${logicUrl}`);
5368
- const logicContent = await res.text();
5813
+ const logicContent = rewriteSourceMappingUrl(await res.text(), logicUrl);
5369
5814
  await ap.serviceWc.executeJavaScript(`${logicContent}
5370
5815
  //# sourceURL=${logicUrl}`, true);
5371
5816
  } catch (error) {
@@ -5660,13 +6105,13 @@ function makeLoadResource(ap, page, target) {
5660
6105
  // dimina's service runtime reads hostEnv as `{ systemInfo, menuRect }`
5661
6106
  // (core/host-env.js init → getSystemInfo/getMenuRect; invokeAPI resolves
5662
6107
  // getSystemInfoSync/getWindowInfo/getDeviceInfo from hostEnv.systemInfo).
5663
- // We previously sent the FLAT HostEnvSnapshot, so `systemInfo` was null
5664
- // `wx.getSystemInfoSync()` returned null and pages reading
5665
- // `.screenWidth` threw. Nest it under `systemInfo`. (render does NOT read
5666
- // hostEnv, so this is service-only; the devtools sync-api-patch reads the
5667
- // separate __diminaSpawnContext.hostEnvSnapshot and is unaffected.)
5668
- // menuRect stays null as before — getMenuButtonBoundingClientRect is
5669
- // served by the sync-api-patch / DeviceShell capsule, not this path.
6108
+ // The snapshot must be nested under `systemInfo`: a FLAT HostEnvSnapshot
6109
+ // leaves `systemInfo` null → `wx.getSystemInfoSync()` returns null and
6110
+ // pages reading `.screenWidth` throw. (render does NOT read hostEnv, so
6111
+ // this is service-only; the devtools sync-api-patch reads the separate
6112
+ // __diminaSpawnContext.hostEnvSnapshot and is unaffected.)
6113
+ // menuRect stays null — getMenuButtonBoundingClientRect is served by the
6114
+ // sync-api-patch / DeviceShell capsule, not this path.
5670
6115
  hostEnv: { systemInfo: ap.hostEnv, menuRect: null }
5671
6116
  }
5672
6117
  };
@@ -7896,7 +8341,7 @@ var AppDataAccumulator = class {
7896
8341
  }
7897
8342
  /**
7898
8343
  * Apply one entry. Returns true if it was accepted (a mutation worth
7899
- * republishing), false if dropped (missing ids, or the R6 gate).
8344
+ * republishing), false if dropped (missing ids, or the init-gate).
7900
8345
  */
7901
8346
  apply(input) {
7902
8347
  if (!input.bridgeId || !input.moduleId) return false;
@@ -8179,7 +8624,7 @@ function resolveVPath(url) {
8179
8624
  }
8180
8625
 
8181
8626
  // src/main/services/simulator-temp-files/disk.ts
8182
- import fs8 from "node:fs/promises";
8627
+ import fs9 from "node:fs/promises";
8183
8628
  import path19 from "node:path";
8184
8629
  var EXT_MIME = {
8185
8630
  ".txt": "text/plain",
@@ -8260,7 +8705,7 @@ function etagOf(mtimeMs, size) {
8260
8705
  return `W/"${Math.floor(mtimeMs)}-${size}"`;
8261
8706
  }
8262
8707
  async function readDiskFile(realPath, opts) {
8263
- const handle = await fs8.open(realPath, "r");
8708
+ const handle = await fs9.open(realPath, "r");
8264
8709
  try {
8265
8710
  const st = await handle.stat();
8266
8711
  const totalSize = st.size;
@@ -8315,15 +8760,15 @@ async function readDiskFile(realPath, opts) {
8315
8760
  }
8316
8761
  async function writeDiskFile(realPath, bytes) {
8317
8762
  const buf = Buffer.isBuffer(bytes) ? bytes : Buffer.from(new Uint8Array(bytes));
8318
- await fs8.mkdir(path19.dirname(realPath), { recursive: true });
8319
- await fs8.writeFile(realPath, buf);
8763
+ await fs9.mkdir(path19.dirname(realPath), { recursive: true });
8764
+ await fs9.writeFile(realPath, buf);
8320
8765
  }
8321
8766
  async function readDiskDir(realPath) {
8322
- const entries = await fs8.readdir(realPath);
8767
+ const entries = await fs9.readdir(realPath);
8323
8768
  return entries;
8324
8769
  }
8325
8770
  async function statDiskFile(realPath) {
8326
- const st = await fs8.stat(realPath);
8771
+ const st = await fs9.stat(realPath);
8327
8772
  return {
8328
8773
  size: st.size,
8329
8774
  mtime: Math.floor(st.mtimeMs),
@@ -8456,14 +8901,14 @@ async function handleDifileRequest(ctx, req) {
8456
8901
  }
8457
8902
 
8458
8903
  // src/main/services/simulator-temp-files/fs-channels.ts
8459
- import fs9 from "node:fs/promises";
8904
+ import fs10 from "node:fs/promises";
8460
8905
  import path20 from "node:path";
8461
8906
  async function enforceSandbox(realPath) {
8462
8907
  if (typeof realPath !== "string" || realPath.length === 0) {
8463
8908
  throw new Error("sandbox: realPath must be a non-empty string");
8464
8909
  }
8465
8910
  const base = sandboxBase();
8466
- const baseReal = await fs9.realpath(base).catch(() => base);
8911
+ const baseReal = await fs10.realpath(base).catch(() => base);
8467
8912
  const normalized = path20.normalize(realPath);
8468
8913
  if (normalized !== base && !normalized.startsWith(base + path20.sep)) {
8469
8914
  throw new Error("sandbox: realPath escapes the user-data base");
@@ -8471,7 +8916,7 @@ async function enforceSandbox(realPath) {
8471
8916
  let probe = normalized;
8472
8917
  while (probe !== path20.parse(probe).root) {
8473
8918
  try {
8474
- const resolved = await fs9.realpath(probe);
8919
+ const resolved = await fs10.realpath(probe);
8475
8920
  if (resolved !== baseReal && !resolved.startsWith(baseReal + path20.sep)) {
8476
8921
  throw new Error("sandbox: realPath escapes the user-data base via symlink");
8477
8922
  }
@@ -8511,12 +8956,12 @@ async function handleFsReaddir(req) {
8511
8956
  }
8512
8957
  async function handleFsUnlink(req) {
8513
8958
  const safe = await enforceSandbox(req.realPath);
8514
- await fs9.unlink(safe);
8959
+ await fs10.unlink(safe);
8515
8960
  return { ok: true };
8516
8961
  }
8517
8962
  async function handleFsMkdir(req) {
8518
8963
  const safe = await enforceSandbox(req.realPath);
8519
- await fs9.mkdir(safe, { recursive: !!req.recursive });
8964
+ await fs10.mkdir(safe, { recursive: !!req.recursive });
8520
8965
  return { ok: true };
8521
8966
  }
8522
8967
 
@@ -8702,7 +9147,7 @@ var UpdateManager = class {
8702
9147
  downloadedPath = null;
8703
9148
  /**
8704
9149
  * Whether this instance has already emitted `Available` once. The periodic
8705
- * check fires forever (interval default 1h), and downstream UI (qdmp shell
9150
+ * check fires forever (interval default 1h), and downstream UI (a downstream host shell
8706
9151
  * renders a native toast / Notification) is not idempotent — every event
8707
9152
  * stacks. We dedupe at the source: at most one Available per instance
8708
9153
  * lifetime, regardless of how the upstream `info.version` shifts. The user
@@ -8949,9 +9394,12 @@ function wireAppWindowEvents(config, instance) {
8949
9394
  onResize: () => context.views.repositionAll(),
8950
9395
  onClose: async (e) => {
8951
9396
  if (isAppQuitting()) return;
9397
+ if (closing) {
9398
+ e.preventDefault();
9399
+ return;
9400
+ }
8952
9401
  if (!context.workspace.hasActiveSession()) return;
8953
9402
  e.preventDefault();
8954
- if (closing) return;
8955
9403
  closing = true;
8956
9404
  try {
8957
9405
  if (config.onBeforeClose) {
@@ -8971,7 +9419,7 @@ function enableDevRendererAutoReload(rendererDir2) {
8971
9419
  });
8972
9420
  }
8973
9421
  let reloadTimer = null;
8974
- const watcher = fs10.watch(rendererDir2, { recursive: true }, () => {
9422
+ const watcher = fs11.watch(rendererDir2, { recursive: true }, () => {
8975
9423
  if (reloadTimer) clearTimeout(reloadTimer);
8976
9424
  reloadTimer = setTimeout(() => {
8977
9425
  for (const win of BrowserWindow8.getAllWindows()) {