@dimina-kit/devtools 0.3.0 → 0.3.1-dev.20260515105504
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.
- package/README.md +103 -41
- package/dist/main/api.d.ts +6 -2
- package/dist/main/api.js +5 -2
- package/dist/main/app/app.d.ts +1 -1
- package/dist/main/app/app.js +71 -36
- package/dist/main/app/launch.d.ts +2 -2
- package/dist/main/app/launch.js +6 -3
- package/dist/main/index.bundle.js +1134 -300
- package/dist/main/ipc/app.d.ts +2 -1
- package/dist/main/ipc/app.js +5 -4
- package/dist/main/ipc/index.d.ts +5 -4
- package/dist/main/ipc/index.js +5 -4
- package/dist/main/ipc/panels.d.ts +2 -1
- package/dist/main/ipc/panels.js +14 -9
- package/dist/main/ipc/popover.d.ts +4 -1
- package/dist/main/ipc/popover.js +15 -5
- package/dist/main/ipc/projects.d.ts +4 -1
- package/dist/main/ipc/projects.js +42 -5
- package/dist/main/ipc/session.d.ts +4 -1
- package/dist/main/ipc/session.js +26 -6
- package/dist/main/ipc/settings.d.ts +4 -1
- package/dist/main/ipc/settings.js +30 -17
- package/dist/main/ipc/simulator-module.d.ts +8 -0
- package/dist/main/ipc/simulator-module.js +19 -0
- package/dist/main/ipc/simulator.d.ts +2 -1
- package/dist/main/ipc/simulator.js +29 -15
- package/dist/main/ipc/toolbar.d.ts +2 -1
- package/dist/main/ipc/toolbar.js +3 -2
- package/dist/main/services/automation/index.js +88 -13
- package/dist/main/services/default-adapter.js +1 -3
- package/dist/main/services/mcp/server.d.ts +2 -1
- package/dist/main/services/mcp/server.js +5 -0
- package/dist/main/services/module.d.ts +18 -0
- package/dist/main/services/module.js +2 -0
- package/dist/main/services/notifications/renderer-notifier.d.ts +2 -0
- package/dist/main/services/projects/project-repository.d.ts +1 -0
- package/dist/main/services/projects/project-repository.js +3 -0
- package/dist/main/services/settings/index.d.ts +4 -0
- package/dist/main/services/settings/index.js +12 -1
- package/dist/main/services/simulator/custom-apis.d.ts +10 -0
- package/dist/main/services/simulator/custom-apis.js +26 -0
- package/dist/main/services/simulator/dir.d.ts +1 -1
- package/dist/main/services/simulator/dir.js +1 -4
- package/dist/main/services/simulator-storage/index.d.ts +22 -1
- package/dist/main/services/simulator-storage/index.js +390 -84
- package/dist/main/services/update/update-manager.d.ts +16 -1
- package/dist/main/services/update/update-manager.js +18 -15
- package/dist/main/services/views/view-manager.d.ts +4 -0
- package/dist/main/services/views/view-manager.js +33 -2
- package/dist/main/services/window-service.d.ts +24 -0
- package/dist/main/services/window-service.js +26 -0
- package/dist/main/services/workbench-context.d.ts +15 -0
- package/dist/main/services/workbench-context.js +6 -0
- package/dist/main/services/workspace/workspace-service.d.ts +1 -0
- package/dist/main/services/workspace/workspace-service.js +7 -3
- package/dist/main/simulator-apis.d.ts +23 -0
- package/dist/main/simulator-apis.js +24 -0
- package/dist/main/utils/disposable.d.ts +13 -0
- package/dist/main/utils/disposable.js +60 -0
- package/dist/main/utils/ipc-registry.d.ts +39 -0
- package/dist/main/utils/ipc-registry.js +109 -0
- package/dist/main/utils/ipc-schema.d.ts +28 -0
- package/dist/main/utils/ipc-schema.js +38 -0
- package/dist/main/utils/paths.d.ts +8 -0
- package/dist/main/utils/paths.js +33 -4
- package/dist/main/utils/sender-policy.d.ts +23 -0
- package/dist/main/utils/sender-policy.js +42 -0
- package/dist/main/windows/main-window/create.d.ts +6 -0
- package/dist/main/windows/main-window/create.js +65 -9
- package/dist/main/windows/main-window/events.d.ts +2 -1
- package/dist/main/windows/main-window/events.js +25 -2
- package/dist/main/windows/navigation-hardening.d.ts +24 -0
- package/dist/main/windows/navigation-hardening.js +55 -0
- package/dist/main/windows/settings-window/create.js +11 -1
- package/dist/preload/index.d.ts +17 -0
- package/dist/preload/index.js +17 -0
- package/dist/preload/instrumentation/app-data.js +178 -19
- package/dist/preload/instrumentation/wxml-extract.js +134 -3
- package/dist/preload/runtime/bridge.d.ts +3 -1
- package/dist/preload/runtime/bridge.js +55 -4
- package/dist/preload/runtime/custom-apis.d.ts +6 -0
- package/dist/preload/runtime/custom-apis.js +18 -0
- package/dist/preload/runtime/host.d.ts +1 -0
- package/dist/preload/runtime/host.js +13 -0
- package/dist/preload/shared/types.d.ts +2 -1
- package/dist/preload/windows/main.cjs +47 -0
- package/dist/preload/windows/main.cjs.map +7 -0
- package/dist/preload/windows/simulator.js +274 -25
- package/dist/renderer/assets/index-DW_0thr-.js +46 -0
- package/dist/renderer/assets/{input-VLotwer2.js → input-C5M5Wxn6.js} +2 -2
- package/dist/renderer/assets/{ipc-transport-COKIC6Ny.js → ipc-transport-CUsl-fS2.js} +6 -6
- package/dist/renderer/assets/ipc-transport-CltRuvhi.css +1 -0
- package/dist/renderer/assets/{popover-Dn0RwMLI.js → popover-BSBPVO0o.js} +2 -2
- package/dist/renderer/assets/{select-DzIsLaKX.js → select-B1tF3UAc.js} +2 -2
- package/dist/renderer/assets/{settings-CD-dacWB.js → settings-7w54H6p-.js} +2 -2
- package/dist/renderer/assets/settings-api-BjJalghB.js +2 -0
- package/dist/renderer/assets/workbenchSettings-q2_-nc8t.js +8 -0
- package/dist/renderer/entries/main/index.html +12 -5
- package/dist/renderer/entries/popover/index.html +7 -5
- package/dist/renderer/entries/settings/index.html +7 -5
- package/dist/renderer/entries/workbench-settings/index.html +6 -4
- package/dist/shared/ipc-channels.d.ts +45 -0
- package/dist/shared/ipc-channels.js +28 -0
- package/dist/shared/ipc-schemas.d.ts +113 -0
- package/dist/shared/ipc-schemas.js +128 -0
- package/dist/shared/types.d.ts +2 -0
- package/dist/simulator/assets/simulator-DL6kOCq-.js +9 -0
- package/dist/simulator/simulator.html +1 -1
- package/package.json +11 -27
- package/dist/preload/windows/main.d.ts +0 -6
- package/dist/preload/windows/main.js +0 -6
- package/dist/renderer/assets/index-D_HFRqZA.js +0 -46
- package/dist/renderer/assets/ipc-transport-6Gy3FXIL.css +0 -1
- package/dist/renderer/assets/settings-api-BV9MPckG.js +0 -2
- package/dist/renderer/assets/workbenchSettings-ClwgsvJL.js +0 -8
- package/dist/simulator/assets/simulator-C1eHXnuq.js +0 -9
|
@@ -14,6 +14,9 @@ var DEFAULTS = {
|
|
|
14
14
|
enabled: false,
|
|
15
15
|
port: 7789
|
|
16
16
|
},
|
|
17
|
+
compile: {
|
|
18
|
+
watch: true
|
|
19
|
+
},
|
|
17
20
|
theme: "system"
|
|
18
21
|
};
|
|
19
22
|
function getSettingsFile() {
|
|
@@ -32,10 +35,18 @@ function loadWorkbenchSettings() {
|
|
|
32
35
|
enabled: data.mcp?.enabled ?? DEFAULTS.mcp.enabled,
|
|
33
36
|
port: data.mcp?.port ?? DEFAULTS.mcp.port
|
|
34
37
|
},
|
|
38
|
+
compile: {
|
|
39
|
+
watch: data.compile?.watch ?? DEFAULTS.compile.watch
|
|
40
|
+
},
|
|
35
41
|
theme
|
|
36
42
|
};
|
|
37
43
|
} catch {
|
|
38
|
-
return {
|
|
44
|
+
return {
|
|
45
|
+
...DEFAULTS,
|
|
46
|
+
cdp: { ...DEFAULTS.cdp },
|
|
47
|
+
mcp: { ...DEFAULTS.mcp },
|
|
48
|
+
compile: { ...DEFAULTS.compile }
|
|
49
|
+
};
|
|
39
50
|
}
|
|
40
51
|
}
|
|
41
52
|
function saveWorkbenchSettings(settings) {
|
|
@@ -63,15 +74,32 @@ function setupCdpPort() {
|
|
|
63
74
|
|
|
64
75
|
// src/main/app/app.ts
|
|
65
76
|
import { app as app11, BrowserWindow as BrowserWindow3, nativeImage } from "electron";
|
|
66
|
-
import
|
|
67
|
-
import
|
|
77
|
+
import fs5 from "fs";
|
|
78
|
+
import path8 from "path";
|
|
68
79
|
|
|
69
80
|
// src/main/utils/paths.ts
|
|
81
|
+
import fs2 from "fs";
|
|
70
82
|
import path2 from "path";
|
|
71
83
|
import { fileURLToPath } from "url";
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
84
|
+
function resolveDevtoolsPackageRoot() {
|
|
85
|
+
let dir = path2.dirname(fileURLToPath(import.meta.url));
|
|
86
|
+
const root = path2.parse(dir).root;
|
|
87
|
+
while (dir !== root) {
|
|
88
|
+
const pkgPath = path2.join(dir, "package.json");
|
|
89
|
+
try {
|
|
90
|
+
const pkg2 = JSON.parse(fs2.readFileSync(pkgPath, "utf8"));
|
|
91
|
+
if (pkg2.name === "@dimina-kit/devtools") return dir;
|
|
92
|
+
} catch {
|
|
93
|
+
}
|
|
94
|
+
dir = path2.dirname(dir);
|
|
95
|
+
}
|
|
96
|
+
throw new Error("@dimina-kit/devtools package root not found from " + fileURLToPath(import.meta.url));
|
|
97
|
+
}
|
|
98
|
+
var devtoolsPackageRoot = resolveDevtoolsPackageRoot();
|
|
99
|
+
var rendererDir = path2.join(devtoolsPackageRoot, "dist/renderer");
|
|
100
|
+
var defaultPreloadPath = path2.join(devtoolsPackageRoot, "dist/preload/windows/simulator.js");
|
|
101
|
+
var mainPreloadPath = path2.join(devtoolsPackageRoot, "dist/preload/windows/main.cjs");
|
|
102
|
+
var simulatorDir = path2.join(devtoolsPackageRoot, "dist/simulator");
|
|
75
103
|
|
|
76
104
|
// src/main/app/lifecycle.ts
|
|
77
105
|
import { app as app3, globalShortcut } from "electron";
|
|
@@ -86,7 +114,8 @@ function registerAppLifecycle() {
|
|
|
86
114
|
}
|
|
87
115
|
|
|
88
116
|
// src/main/windows/main-window/create.ts
|
|
89
|
-
import { app as app4, BrowserWindow, View,
|
|
117
|
+
import { app as app4, BrowserWindow, View, session, shell as shell2 } from "electron";
|
|
118
|
+
import path4 from "path";
|
|
90
119
|
|
|
91
120
|
// src/main/services/simulator/referer.ts
|
|
92
121
|
var DEFAULT_VERSION = "develop";
|
|
@@ -113,12 +142,51 @@ function themeBg() {
|
|
|
113
142
|
return nativeTheme2.shouldUseDarkColors ? "#1a1a1a" : "#fafafa";
|
|
114
143
|
}
|
|
115
144
|
|
|
145
|
+
// src/main/windows/navigation-hardening.ts
|
|
146
|
+
import { shell } from "electron";
|
|
147
|
+
import path3 from "path";
|
|
148
|
+
import { pathToFileURL } from "url";
|
|
149
|
+
function handleWindowOpenExternal(url) {
|
|
150
|
+
try {
|
|
151
|
+
const u = new URL(url);
|
|
152
|
+
if (u.protocol === "http:" || u.protocol === "https:") {
|
|
153
|
+
void shell.openExternal(url);
|
|
154
|
+
}
|
|
155
|
+
} catch {
|
|
156
|
+
}
|
|
157
|
+
return { action: "deny" };
|
|
158
|
+
}
|
|
159
|
+
function applyNavigationHardening(wc, rendererDir2) {
|
|
160
|
+
const rendererPrefix = pathToFileURL(rendererDir2 + path3.sep).href;
|
|
161
|
+
wc.setWindowOpenHandler(({ url }) => handleWindowOpenExternal(url));
|
|
162
|
+
wc.on("will-navigate", (event, url) => {
|
|
163
|
+
let parsed;
|
|
164
|
+
try {
|
|
165
|
+
parsed = new URL(url);
|
|
166
|
+
} catch {
|
|
167
|
+
event.preventDefault();
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
if (parsed.protocol === "file:" && parsed.href.startsWith(rendererPrefix)) {
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
event.preventDefault();
|
|
174
|
+
if (parsed.protocol === "http:" || parsed.protocol === "https:") {
|
|
175
|
+
void shell.openExternal(url);
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
|
|
116
180
|
// src/main/windows/main-window/create.ts
|
|
117
181
|
var simulatorSessionConfigured = false;
|
|
118
|
-
function configureSimulatorSession() {
|
|
182
|
+
function configureSimulatorSession(simulatorPreloadPath) {
|
|
119
183
|
if (simulatorSessionConfigured) return;
|
|
120
184
|
simulatorSessionConfigured = true;
|
|
121
185
|
const simulatorSession = session.fromPartition("persist:simulator");
|
|
186
|
+
simulatorSession.registerPreloadScript({
|
|
187
|
+
type: "frame",
|
|
188
|
+
filePath: simulatorPreloadPath
|
|
189
|
+
});
|
|
122
190
|
simulatorSession.webRequest.onBeforeSendHeaders((details, callback) => {
|
|
123
191
|
const forcedReferer = getSimulatorServicewechatReferer();
|
|
124
192
|
if (forcedReferer) {
|
|
@@ -137,7 +205,7 @@ function configureSimulatorSession() {
|
|
|
137
205
|
});
|
|
138
206
|
}
|
|
139
207
|
function createMainWindow(opts) {
|
|
140
|
-
configureSimulatorSession();
|
|
208
|
+
configureSimulatorSession(opts.simulatorPreloadPath);
|
|
141
209
|
const mainWindow = new BrowserWindow({
|
|
142
210
|
width: opts.width ?? 1280,
|
|
143
211
|
height: opts.height ?? 980,
|
|
@@ -147,8 +215,13 @@ function createMainWindow(opts) {
|
|
|
147
215
|
show: false,
|
|
148
216
|
backgroundColor: themeBg(),
|
|
149
217
|
webPreferences: {
|
|
150
|
-
nodeIntegration:
|
|
151
|
-
contextIsolation:
|
|
218
|
+
nodeIntegration: false,
|
|
219
|
+
contextIsolation: true,
|
|
220
|
+
// `sandbox: false` is required so the preload bundle can `require('electron')`
|
|
221
|
+
// to access contextBridge/ipcRenderer. The renderer itself runs isolated.
|
|
222
|
+
sandbox: false,
|
|
223
|
+
preload: mainPreloadPath,
|
|
224
|
+
// The simulator <webview> still relies on the webview tag; keep it enabled.
|
|
152
225
|
webviewTag: true
|
|
153
226
|
}
|
|
154
227
|
});
|
|
@@ -162,22 +235,102 @@ function createMainWindow(opts) {
|
|
|
162
235
|
}
|
|
163
236
|
}
|
|
164
237
|
});
|
|
165
|
-
|
|
238
|
+
const rendererDir2 = path4.dirname(opts.indexHtml);
|
|
239
|
+
applyNavigationHardening(mainWindow.webContents, rendererDir2);
|
|
240
|
+
mainWindow.webContents.on("will-attach-webview", (event, webPreferences, params) => {
|
|
241
|
+
;
|
|
242
|
+
webPreferences.partition = "persist:simulator";
|
|
243
|
+
params.partition = "persist:simulator";
|
|
166
244
|
webPreferences.contextIsolation = false;
|
|
245
|
+
void event;
|
|
246
|
+
});
|
|
247
|
+
mainWindow.webContents.on("did-attach-webview", (_event, webviewWebContents) => {
|
|
248
|
+
webviewWebContents.setWindowOpenHandler(({ url }) => handleWindowOpenExternal(url));
|
|
249
|
+
webviewWebContents.on("will-navigate", (e, url) => {
|
|
250
|
+
try {
|
|
251
|
+
const u = new URL(url);
|
|
252
|
+
if (u.protocol === "about:") return;
|
|
253
|
+
if ((u.protocol === "http:" || u.protocol === "https:") && (u.hostname === "localhost" || u.hostname === "127.0.0.1")) {
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
e.preventDefault();
|
|
257
|
+
if (u.protocol === "http:" || u.protocol === "https:") {
|
|
258
|
+
void shell2.openExternal(url);
|
|
259
|
+
}
|
|
260
|
+
} catch {
|
|
261
|
+
e.preventDefault();
|
|
262
|
+
}
|
|
263
|
+
});
|
|
167
264
|
});
|
|
168
265
|
mainWindow.loadFile(opts.indexHtml);
|
|
169
266
|
const container = new View();
|
|
170
267
|
const mainWebView = mainWindow.contentView;
|
|
171
268
|
container.addChildView(mainWebView);
|
|
172
269
|
mainWindow.contentView = container;
|
|
173
|
-
globalShortcut2.register("CommandOrControl+Shift+I", () => {
|
|
174
|
-
mainWindow.webContents.openDevTools({ mode: "detach" });
|
|
175
|
-
});
|
|
176
270
|
return mainWindow;
|
|
177
271
|
}
|
|
178
272
|
|
|
273
|
+
// src/main/windows/main-window/events.ts
|
|
274
|
+
import { globalShortcut as globalShortcut2 } from "electron";
|
|
275
|
+
|
|
276
|
+
// src/main/utils/disposable.ts
|
|
277
|
+
function toDisposable(fn) {
|
|
278
|
+
let done = false;
|
|
279
|
+
return {
|
|
280
|
+
dispose() {
|
|
281
|
+
if (done) return;
|
|
282
|
+
done = true;
|
|
283
|
+
return fn();
|
|
284
|
+
}
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
var DisposableRegistry = class {
|
|
288
|
+
entries = [];
|
|
289
|
+
_disposed = false;
|
|
290
|
+
add(d) {
|
|
291
|
+
if (this._disposed) {
|
|
292
|
+
throw new Error("cannot add to disposed registry");
|
|
293
|
+
}
|
|
294
|
+
const fn = typeof d === "function" ? d : () => d.dispose();
|
|
295
|
+
const entry = { fn, released: false };
|
|
296
|
+
this.entries.push(entry);
|
|
297
|
+
return {
|
|
298
|
+
dispose: () => {
|
|
299
|
+
if (entry.released) return;
|
|
300
|
+
entry.released = true;
|
|
301
|
+
const i = this.entries.indexOf(entry);
|
|
302
|
+
if (i >= 0) this.entries.splice(i, 1);
|
|
303
|
+
return fn();
|
|
304
|
+
}
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
async disposeAll() {
|
|
308
|
+
if (this._disposed) return;
|
|
309
|
+
this._disposed = true;
|
|
310
|
+
const items = this.entries.slice().reverse();
|
|
311
|
+
this.entries = [];
|
|
312
|
+
const errors = [];
|
|
313
|
+
for (const entry of items) {
|
|
314
|
+
if (entry.released) continue;
|
|
315
|
+
entry.released = true;
|
|
316
|
+
try {
|
|
317
|
+
await entry.fn();
|
|
318
|
+
} catch (e) {
|
|
319
|
+
errors.push(e);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
if (errors.length > 0) {
|
|
323
|
+
throw new AggregateError(errors, "DisposableRegistry encountered errors during disposeAll");
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
dispose() {
|
|
327
|
+
return this.disposeAll();
|
|
328
|
+
}
|
|
329
|
+
};
|
|
330
|
+
|
|
179
331
|
// src/main/windows/main-window/events.ts
|
|
180
332
|
function wireMainWindowEvents(win, state = {}) {
|
|
333
|
+
const registry = new DisposableRegistry();
|
|
181
334
|
const mainWebView = win.contentView.children[0];
|
|
182
335
|
const resizeMainWebView = () => {
|
|
183
336
|
if (mainWebView) {
|
|
@@ -188,25 +341,53 @@ function wireMainWindowEvents(win, state = {}) {
|
|
|
188
341
|
};
|
|
189
342
|
resizeMainWebView();
|
|
190
343
|
win.on("resize", resizeMainWebView);
|
|
344
|
+
registry.add(toDisposable(() => {
|
|
345
|
+
win.removeListener("resize", resizeMainWebView);
|
|
346
|
+
}));
|
|
191
347
|
if (state.onClose) {
|
|
192
|
-
|
|
348
|
+
const onCloseHandler = (event) => {
|
|
193
349
|
void state.onClose?.(event);
|
|
194
|
-
}
|
|
350
|
+
};
|
|
351
|
+
win.on("close", onCloseHandler);
|
|
352
|
+
registry.add(toDisposable(() => {
|
|
353
|
+
win.removeListener("close", onCloseHandler);
|
|
354
|
+
}));
|
|
355
|
+
}
|
|
356
|
+
const devToolsAccelerator = "CommandOrControl+Shift+I";
|
|
357
|
+
const registered = globalShortcut2.register(devToolsAccelerator, () => {
|
|
358
|
+
win.webContents.openDevTools({ mode: "detach" });
|
|
359
|
+
});
|
|
360
|
+
if (registered) {
|
|
361
|
+
registry.add(toDisposable(() => {
|
|
362
|
+
globalShortcut2.unregister(devToolsAccelerator);
|
|
363
|
+
}));
|
|
195
364
|
}
|
|
365
|
+
return registry;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// src/main/utils/sender-policy.ts
|
|
369
|
+
function createWorkbenchSenderPolicy(ctx) {
|
|
370
|
+
return (sender) => {
|
|
371
|
+
if (sender.isDestroyed()) return false;
|
|
372
|
+
if (ctx.windows.isMainSender(sender.id)) return true;
|
|
373
|
+
if (ctx.windows.isSettingsWindowSender(sender.id)) return true;
|
|
374
|
+
const settingsViewId = ctx.views.getSettingsWebContentsId();
|
|
375
|
+
if (settingsViewId != null && sender.id === settingsViewId) return true;
|
|
376
|
+
const popoverViewId = ctx.views.getPopoverWebContentsId();
|
|
377
|
+
if (popoverViewId != null && sender.id === popoverViewId) return true;
|
|
378
|
+
return false;
|
|
379
|
+
};
|
|
196
380
|
}
|
|
197
381
|
|
|
198
382
|
// src/main/services/default-adapter.ts
|
|
199
|
-
import
|
|
200
|
-
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
383
|
+
import path5 from "path";
|
|
201
384
|
import { app as app5 } from "electron";
|
|
202
|
-
var __dirname2 = path3.dirname(fileURLToPath2(import.meta.url));
|
|
203
|
-
var simulatorDir = path3.resolve(__dirname2, "../../simulator");
|
|
204
385
|
var defaultAdapter = {
|
|
205
386
|
async openProject(opts) {
|
|
206
387
|
const diminaKit = await import("@dimina-kit/devkit");
|
|
207
388
|
const openProject = diminaKit.openProject;
|
|
208
389
|
return openProject({
|
|
209
|
-
outputDir:
|
|
390
|
+
outputDir: path5.join(app5.getPath("userData"), "dimina-fe-output"),
|
|
210
391
|
...opts,
|
|
211
392
|
simulatorDir
|
|
212
393
|
});
|
|
@@ -224,10 +405,23 @@ var SimulatorChannel = {
|
|
|
224
405
|
AppData: "simulator:appdata",
|
|
225
406
|
AppDataAll: "simulator:appdata-all"
|
|
226
407
|
};
|
|
408
|
+
var SimulatorCustomApiChannel = {
|
|
409
|
+
List: "simulator:custom-apis:list",
|
|
410
|
+
Invoke: "simulator:custom-apis:invoke"
|
|
411
|
+
};
|
|
227
412
|
var SimulatorStorageChannel = {
|
|
228
413
|
GetSnapshot: "simulator:storage:snapshot",
|
|
414
|
+
GetActivePrefix: "simulator:storage:activePrefix",
|
|
415
|
+
Set: "simulator:storage:set",
|
|
416
|
+
Remove: "simulator:storage:remove",
|
|
417
|
+
Clear: "simulator:storage:clear",
|
|
418
|
+
ClearAll: "simulator:storage:clearAll",
|
|
229
419
|
Event: "simulator:storage:event"
|
|
230
420
|
};
|
|
421
|
+
var SimulatorElementChannel = {
|
|
422
|
+
Inspect: "simulator:element:inspect",
|
|
423
|
+
Clear: "simulator:element:clear"
|
|
424
|
+
};
|
|
231
425
|
var WorkbenchChannel = {
|
|
232
426
|
GetPanelConfig: "workbench:getPanelConfig",
|
|
233
427
|
GetApiNamespaces: "workbench:getApiNamespaces",
|
|
@@ -294,6 +488,13 @@ var SettingsChannel = {
|
|
|
294
488
|
Closed: "settings:closed",
|
|
295
489
|
Changed: "settings:changed"
|
|
296
490
|
};
|
|
491
|
+
var UpdateChannel = {
|
|
492
|
+
Check: "updates:check",
|
|
493
|
+
Download: "updates:download",
|
|
494
|
+
Install: "updates:install",
|
|
495
|
+
DownloadProgress: "updates:downloadProgress",
|
|
496
|
+
Available: "updates:available"
|
|
497
|
+
};
|
|
297
498
|
|
|
298
499
|
// src/main/services/notifications/renderer-notifier.ts
|
|
299
500
|
function liveWebContents(wc) {
|
|
@@ -354,7 +555,7 @@ function createRendererNotifier(ctx) {
|
|
|
354
555
|
|
|
355
556
|
// src/main/services/views/view-manager.ts
|
|
356
557
|
import { WebContentsView as WebContentsView2, webContents } from "electron";
|
|
357
|
-
import
|
|
558
|
+
import path6 from "path";
|
|
358
559
|
|
|
359
560
|
// src/main/services/layout/index.ts
|
|
360
561
|
var HEADER_H = 40;
|
|
@@ -513,10 +714,16 @@ function createViewManager(ctx) {
|
|
|
513
714
|
async function showSettings() {
|
|
514
715
|
if (!settingsView) {
|
|
515
716
|
settingsView = new WebContentsView2({
|
|
516
|
-
webPreferences: {
|
|
717
|
+
webPreferences: {
|
|
718
|
+
nodeIntegration: false,
|
|
719
|
+
contextIsolation: true,
|
|
720
|
+
sandbox: false,
|
|
721
|
+
preload: mainPreloadPath
|
|
722
|
+
}
|
|
517
723
|
});
|
|
724
|
+
applyNavigationHardening(settingsView.webContents, ctx.rendererDir);
|
|
518
725
|
await settingsView.webContents.loadFile(
|
|
519
|
-
|
|
726
|
+
path6.join(ctx.rendererDir, "entries/settings/index.html")
|
|
520
727
|
);
|
|
521
728
|
}
|
|
522
729
|
if (!settingsViewAdded) {
|
|
@@ -537,8 +744,14 @@ function createViewManager(ctx) {
|
|
|
537
744
|
function showPopover(data) {
|
|
538
745
|
hidePopover();
|
|
539
746
|
const popover = new WebContentsView2({
|
|
540
|
-
webPreferences: {
|
|
747
|
+
webPreferences: {
|
|
748
|
+
nodeIntegration: false,
|
|
749
|
+
contextIsolation: true,
|
|
750
|
+
sandbox: false,
|
|
751
|
+
preload: mainPreloadPath
|
|
752
|
+
}
|
|
541
753
|
});
|
|
754
|
+
applyNavigationHardening(popover.webContents, ctx.rendererDir);
|
|
542
755
|
popoverView = popover;
|
|
543
756
|
popover.setBackgroundColor("#00000000");
|
|
544
757
|
ctx.mainWindow.contentView.addChildView(popover);
|
|
@@ -547,7 +760,7 @@ function createViewManager(ctx) {
|
|
|
547
760
|
ctx.notify.popoverInit(popover, data);
|
|
548
761
|
});
|
|
549
762
|
popover.webContents.loadFile(
|
|
550
|
-
|
|
763
|
+
path6.join(ctx.rendererDir, "entries/popover/index.html")
|
|
551
764
|
);
|
|
552
765
|
}
|
|
553
766
|
function hidePopover() {
|
|
@@ -613,15 +826,51 @@ function createViewManager(ctx) {
|
|
|
613
826
|
if (settingsView.webContents.isDestroyed()) return null;
|
|
614
827
|
return settingsView.webContents;
|
|
615
828
|
},
|
|
829
|
+
getSettingsWebContentsId: () => {
|
|
830
|
+
if (!settingsView) return null;
|
|
831
|
+
if (settingsView.webContents.isDestroyed()) return null;
|
|
832
|
+
return settingsView.webContents.id;
|
|
833
|
+
},
|
|
834
|
+
getPopoverWebContentsId: () => {
|
|
835
|
+
if (!popoverView) return null;
|
|
836
|
+
if (popoverView.webContents.isDestroyed()) return null;
|
|
837
|
+
return popoverView.webContents.id;
|
|
838
|
+
},
|
|
616
839
|
resize,
|
|
617
840
|
setVisible
|
|
618
841
|
};
|
|
619
842
|
}
|
|
620
843
|
|
|
844
|
+
// src/main/services/window-service.ts
|
|
845
|
+
function createWindowService(mainWindow) {
|
|
846
|
+
let settingsWin = null;
|
|
847
|
+
return {
|
|
848
|
+
get mainWindow() {
|
|
849
|
+
return mainWindow;
|
|
850
|
+
},
|
|
851
|
+
get settingsWindow() {
|
|
852
|
+
return settingsWin;
|
|
853
|
+
},
|
|
854
|
+
setSettingsWindow(win) {
|
|
855
|
+
settingsWin = win;
|
|
856
|
+
},
|
|
857
|
+
closeSettingsWindow() {
|
|
858
|
+
if (settingsWin && !settingsWin.isDestroyed()) settingsWin.close();
|
|
859
|
+
settingsWin = null;
|
|
860
|
+
},
|
|
861
|
+
isMainSender(id) {
|
|
862
|
+
return !mainWindow.isDestroyed() && mainWindow.webContents.id === id;
|
|
863
|
+
},
|
|
864
|
+
isSettingsWindowSender(id) {
|
|
865
|
+
return !!settingsWin && !settingsWin.isDestroyed() && settingsWin.webContents.id === id;
|
|
866
|
+
}
|
|
867
|
+
};
|
|
868
|
+
}
|
|
869
|
+
|
|
621
870
|
// src/main/services/projects/project-repository.ts
|
|
622
871
|
import { app as app6 } from "electron";
|
|
623
|
-
import
|
|
624
|
-
import
|
|
872
|
+
import path7 from "path";
|
|
873
|
+
import fs3 from "fs";
|
|
625
874
|
|
|
626
875
|
// src/shared/constants.ts
|
|
627
876
|
var DEFAULT_SCENE = 1001;
|
|
@@ -667,17 +916,17 @@ function createLogger(tag) {
|
|
|
667
916
|
// src/main/services/projects/project-repository.ts
|
|
668
917
|
var log = createLogger("projects");
|
|
669
918
|
function getProjectsFile() {
|
|
670
|
-
return
|
|
919
|
+
return path7.join(app6.getPath("userData"), "dimina-projects.json");
|
|
671
920
|
}
|
|
672
921
|
function load() {
|
|
673
922
|
try {
|
|
674
|
-
return JSON.parse(
|
|
923
|
+
return JSON.parse(fs3.readFileSync(getProjectsFile(), "utf-8"));
|
|
675
924
|
} catch {
|
|
676
925
|
return [];
|
|
677
926
|
}
|
|
678
927
|
}
|
|
679
928
|
function save(projects) {
|
|
680
|
-
|
|
929
|
+
fs3.writeFileSync(getProjectsFile(), JSON.stringify(projects, null, 2));
|
|
681
930
|
}
|
|
682
931
|
function listProjects() {
|
|
683
932
|
return load();
|
|
@@ -686,16 +935,16 @@ function validateProjectDir(dirPath) {
|
|
|
686
935
|
if (!dirPath) {
|
|
687
936
|
return "\u5C0F\u7A0B\u5E8F\u76EE\u5F55\u8DEF\u5F84\u4E3A\u7A7A\uFF0C\u8BF7\u9009\u62E9\u5305\u542B\u5C0F\u7A0B\u5E8F\u6E90\u7801\u7684\u76EE\u5F55";
|
|
688
937
|
}
|
|
689
|
-
if (!
|
|
938
|
+
if (!fs3.existsSync(dirPath)) {
|
|
690
939
|
return `\u5C0F\u7A0B\u5E8F\u76EE\u5F55\u4E0D\u5B58\u5728\uFF1A${dirPath}`;
|
|
691
940
|
}
|
|
692
|
-
if (!
|
|
693
|
-
const configPath =
|
|
694
|
-
if (
|
|
941
|
+
if (!fs3.existsSync(path7.join(dirPath, "app.json"))) {
|
|
942
|
+
const configPath = path7.join(dirPath, "project.config.json");
|
|
943
|
+
if (fs3.existsSync(configPath)) {
|
|
695
944
|
try {
|
|
696
|
-
const cfg = JSON.parse(
|
|
945
|
+
const cfg = JSON.parse(fs3.readFileSync(configPath, "utf-8"));
|
|
697
946
|
if (cfg.miniprogramRoot) {
|
|
698
|
-
const resolvedRoot =
|
|
947
|
+
const resolvedRoot = path7.resolve(dirPath, cfg.miniprogramRoot);
|
|
699
948
|
return `\u8BE5\u76EE\u5F55\u7F3A\u5C11 app.json\uFF0Cproject.config.json \u4E2D\u6307\u5B9A\u4E86 miniprogramRoot: "${cfg.miniprogramRoot}"\uFF0C\u8BF7\u5BFC\u5165 ${resolvedRoot}`;
|
|
700
949
|
}
|
|
701
950
|
} catch (err) {
|
|
@@ -706,13 +955,16 @@ function validateProjectDir(dirPath) {
|
|
|
706
955
|
}
|
|
707
956
|
return null;
|
|
708
957
|
}
|
|
958
|
+
function hasProject(dirPath) {
|
|
959
|
+
return load().some((p) => p.path === dirPath);
|
|
960
|
+
}
|
|
709
961
|
function addProject(dirPath) {
|
|
710
962
|
const projects = load();
|
|
711
|
-
let name =
|
|
963
|
+
let name = path7.basename(dirPath);
|
|
712
964
|
try {
|
|
713
|
-
const configPath =
|
|
714
|
-
if (
|
|
715
|
-
const cfg = JSON.parse(
|
|
965
|
+
const configPath = path7.join(dirPath, "project.config.json");
|
|
966
|
+
if (fs3.existsSync(configPath)) {
|
|
967
|
+
const cfg = JSON.parse(fs3.readFileSync(configPath, "utf-8"));
|
|
716
968
|
if (cfg.projectname) name = cfg.projectname;
|
|
717
969
|
}
|
|
718
970
|
} catch (err) {
|
|
@@ -749,10 +1001,10 @@ function getCompileConfig(dirPath) {
|
|
|
749
1001
|
};
|
|
750
1002
|
}
|
|
751
1003
|
function getProjectPages(dirPath) {
|
|
752
|
-
const appJsonPath =
|
|
1004
|
+
const appJsonPath = path7.join(dirPath, "app.json");
|
|
753
1005
|
try {
|
|
754
1006
|
const appJson = JSON.parse(
|
|
755
|
-
|
|
1007
|
+
fs3.readFileSync(appJsonPath, "utf-8")
|
|
756
1008
|
);
|
|
757
1009
|
return {
|
|
758
1010
|
pages: appJson.pages || [],
|
|
@@ -775,8 +1027,8 @@ function getProjectSettings(projectPath) {
|
|
|
775
1027
|
return { uploadWithSourceMap: false };
|
|
776
1028
|
}
|
|
777
1029
|
try {
|
|
778
|
-
const configPath =
|
|
779
|
-
const config = JSON.parse(
|
|
1030
|
+
const configPath = path7.join(projectPath, "project.config.json");
|
|
1031
|
+
const config = JSON.parse(fs3.readFileSync(configPath, "utf-8"));
|
|
780
1032
|
return {
|
|
781
1033
|
uploadWithSourceMap: !!config.setting?.uploadWithSourceMap
|
|
782
1034
|
};
|
|
@@ -786,17 +1038,17 @@ function getProjectSettings(projectPath) {
|
|
|
786
1038
|
}
|
|
787
1039
|
function updateProjectSettings(projectPath, patch) {
|
|
788
1040
|
if (!projectPath) return;
|
|
789
|
-
const configPath =
|
|
1041
|
+
const configPath = path7.join(projectPath, "project.config.json");
|
|
790
1042
|
let config = {};
|
|
791
1043
|
try {
|
|
792
|
-
config = JSON.parse(
|
|
1044
|
+
config = JSON.parse(fs3.readFileSync(configPath, "utf-8"));
|
|
793
1045
|
} catch {
|
|
794
1046
|
}
|
|
795
1047
|
const nextSetting = {
|
|
796
1048
|
...config.setting ?? {},
|
|
797
1049
|
...patch.uploadWithSourceMap === void 0 ? {} : { uploadWithSourceMap: patch.uploadWithSourceMap }
|
|
798
1050
|
};
|
|
799
|
-
|
|
1051
|
+
fs3.writeFileSync(
|
|
800
1052
|
configPath,
|
|
801
1053
|
JSON.stringify({ ...config, setting: nextSetting }, null, 2)
|
|
802
1054
|
);
|
|
@@ -806,8 +1058,8 @@ function updateProjectSettings(projectPath, patch) {
|
|
|
806
1058
|
function createWorkspaceService(ctx) {
|
|
807
1059
|
let currentSession = null;
|
|
808
1060
|
let currentProjectPath = "";
|
|
809
|
-
function sendStatus(status, message) {
|
|
810
|
-
ctx.notify.projectStatus({ status, message });
|
|
1061
|
+
function sendStatus(status, message, hotReload) {
|
|
1062
|
+
ctx.notify.projectStatus(hotReload ? { status, message, hotReload: true } : { status, message });
|
|
811
1063
|
}
|
|
812
1064
|
function bestEffort(label, fn) {
|
|
813
1065
|
try {
|
|
@@ -844,6 +1096,7 @@ function createWorkspaceService(ctx) {
|
|
|
844
1096
|
listProjects: () => listProjects(),
|
|
845
1097
|
addProject: (dirPath) => addProject(dirPath),
|
|
846
1098
|
removeProject: (dirPath) => removeProject(dirPath),
|
|
1099
|
+
hasProject: (dirPath) => hasProject(dirPath),
|
|
847
1100
|
validateProjectDir: (dirPath) => validateProjectDir(dirPath),
|
|
848
1101
|
async openProject(projectPath) {
|
|
849
1102
|
clearSimulatorServicewechatReferer();
|
|
@@ -855,12 +1108,14 @@ function createWorkspaceService(ctx) {
|
|
|
855
1108
|
return { success: false, error: dirError };
|
|
856
1109
|
}
|
|
857
1110
|
sendStatus("compiling", "\u6B63\u5728\u7F16\u8BD1...");
|
|
1111
|
+
const { compile } = loadWorkbenchSettings();
|
|
858
1112
|
let session2;
|
|
859
1113
|
try {
|
|
860
1114
|
session2 = await ctx.adapter.openProject({
|
|
861
1115
|
projectPath,
|
|
862
1116
|
sourcemap: true,
|
|
863
|
-
|
|
1117
|
+
watch: compile.watch,
|
|
1118
|
+
onRebuild: () => sendStatus("ready", "\u7F16\u8BD1\u5B8C\u6210\uFF0C\u5DF2\u70ED\u66F4\u65B0", true),
|
|
864
1119
|
onBuildError: (err) => sendStatus("error", String(err))
|
|
865
1120
|
});
|
|
866
1121
|
} catch (err) {
|
|
@@ -918,9 +1173,12 @@ function createWorkbenchContext(opts) {
|
|
|
918
1173
|
brandingProvider: opts.brandingProvider,
|
|
919
1174
|
workbenchSettingsWindow: null
|
|
920
1175
|
};
|
|
1176
|
+
ctx.registry = new DisposableRegistry();
|
|
1177
|
+
ctx.windows = createWindowService(ctx.mainWindow);
|
|
921
1178
|
ctx.views = createViewManager(ctx);
|
|
922
1179
|
ctx.notify = createRendererNotifier(ctx);
|
|
923
1180
|
ctx.workspace = createWorkspaceService(ctx);
|
|
1181
|
+
ctx.senderPolicy = createWorkbenchSenderPolicy(ctx);
|
|
924
1182
|
return ctx;
|
|
925
1183
|
}
|
|
926
1184
|
|
|
@@ -991,56 +1249,246 @@ function installAppMenu(ctx) {
|
|
|
991
1249
|
}
|
|
992
1250
|
|
|
993
1251
|
// src/main/ipc/app.ts
|
|
1252
|
+
import fs4 from "fs";
|
|
1253
|
+
|
|
1254
|
+
// src/main/utils/ipc-registry.ts
|
|
994
1255
|
import { ipcMain } from "electron";
|
|
995
|
-
|
|
1256
|
+
|
|
1257
|
+
// src/main/utils/ipc-schema.ts
|
|
1258
|
+
var IpcValidationError = class extends Error {
|
|
1259
|
+
channel;
|
|
1260
|
+
paths;
|
|
1261
|
+
constructor(channel, issues) {
|
|
1262
|
+
const paths = issues.map((i) => i.path.map((p) => String(p)).join(".") || "<root>");
|
|
1263
|
+
super(`Invalid IPC arguments for ${channel}`);
|
|
1264
|
+
this.name = "IpcValidationError";
|
|
1265
|
+
this.channel = channel;
|
|
1266
|
+
this.paths = paths;
|
|
1267
|
+
}
|
|
1268
|
+
};
|
|
1269
|
+
function validate(channel, schema, args) {
|
|
1270
|
+
const r = schema.safeParse(args);
|
|
1271
|
+
if (!r.success) {
|
|
1272
|
+
console.warn("[ipc] schema reject", channel, r.error.issues);
|
|
1273
|
+
throw new IpcValidationError(channel, r.error.issues);
|
|
1274
|
+
}
|
|
1275
|
+
return r.data;
|
|
1276
|
+
}
|
|
1277
|
+
|
|
1278
|
+
// src/main/utils/ipc-registry.ts
|
|
1279
|
+
var log2 = createLogger("ipc");
|
|
1280
|
+
function reportListenerError(channel, err) {
|
|
1281
|
+
if (err instanceof IpcValidationError) {
|
|
1282
|
+
log2.warn(`schema reject on '${channel}' at [${err.paths.join(", ")}]`);
|
|
1283
|
+
return;
|
|
1284
|
+
}
|
|
1285
|
+
if (err instanceof Error) {
|
|
1286
|
+
log2.error(`listener threw on '${channel}': ${err.message}`, err.stack);
|
|
1287
|
+
return;
|
|
1288
|
+
}
|
|
1289
|
+
log2.error(`listener threw on '${channel}'`, err);
|
|
1290
|
+
}
|
|
1291
|
+
function isThenable(v) {
|
|
1292
|
+
return v != null && (typeof v === "object" || typeof v === "function") && typeof v.then === "function";
|
|
1293
|
+
}
|
|
1294
|
+
function summarizeSender(sender) {
|
|
1295
|
+
if (sender.isDestroyed()) return "<destroyed>";
|
|
1296
|
+
const url = sender.getURL();
|
|
1297
|
+
return `id=${sender.id} ${url.slice(0, 120)}`;
|
|
1298
|
+
}
|
|
1299
|
+
var IpcRegistry = class {
|
|
1300
|
+
constructor(policy) {
|
|
1301
|
+
this.policy = policy;
|
|
1302
|
+
}
|
|
1303
|
+
policy;
|
|
1304
|
+
registry = new DisposableRegistry();
|
|
1305
|
+
handle(channel, fn) {
|
|
1306
|
+
const policy = this.policy;
|
|
1307
|
+
const guarded = policy ? (event, ...args) => {
|
|
1308
|
+
const sender = event.sender;
|
|
1309
|
+
if (!policy(sender)) {
|
|
1310
|
+
console.warn(
|
|
1311
|
+
`[ipc] sender rejected for channel '${channel}' (${summarizeSender(sender)})`
|
|
1312
|
+
);
|
|
1313
|
+
throw new Error(`IPC sender rejected for channel ${channel}`);
|
|
1314
|
+
}
|
|
1315
|
+
return fn(event, ...args);
|
|
1316
|
+
} : fn;
|
|
1317
|
+
ipcMain.handle(channel, guarded);
|
|
1318
|
+
this.registry.add(() => ipcMain.removeHandler(channel));
|
|
1319
|
+
return this;
|
|
1320
|
+
}
|
|
1321
|
+
on(channel, fn) {
|
|
1322
|
+
const policy = this.policy;
|
|
1323
|
+
const raw = fn;
|
|
1324
|
+
const safeInvoke = (event, args) => {
|
|
1325
|
+
try {
|
|
1326
|
+
const ret = raw(event, ...args);
|
|
1327
|
+
if (isThenable(ret)) {
|
|
1328
|
+
Promise.resolve(ret).catch((err) => reportListenerError(channel, err));
|
|
1329
|
+
}
|
|
1330
|
+
} catch (err) {
|
|
1331
|
+
reportListenerError(channel, err);
|
|
1332
|
+
}
|
|
1333
|
+
};
|
|
1334
|
+
const guarded = policy ? (event, ...args) => {
|
|
1335
|
+
const sender = event.sender;
|
|
1336
|
+
if (!policy(sender)) {
|
|
1337
|
+
console.warn(
|
|
1338
|
+
`[ipc] sender rejected for channel '${channel}' (${summarizeSender(sender)})`
|
|
1339
|
+
);
|
|
1340
|
+
return;
|
|
1341
|
+
}
|
|
1342
|
+
safeInvoke(event, args);
|
|
1343
|
+
} : (event, ...args) => safeInvoke(event, args);
|
|
1344
|
+
ipcMain.on(channel, guarded);
|
|
1345
|
+
this.registry.add(() => {
|
|
1346
|
+
ipcMain.removeListener(channel, guarded);
|
|
1347
|
+
});
|
|
1348
|
+
return this;
|
|
1349
|
+
}
|
|
1350
|
+
dispose() {
|
|
1351
|
+
return this.registry.dispose();
|
|
1352
|
+
}
|
|
1353
|
+
};
|
|
1354
|
+
|
|
1355
|
+
// src/main/ipc/app.ts
|
|
996
1356
|
function registerAppIpc(ctx) {
|
|
997
|
-
|
|
998
|
-
return `file://${
|
|
999
|
-
})
|
|
1000
|
-
ipcMain.handle(AppChannel.GetBranding, async () => {
|
|
1357
|
+
return new IpcRegistry(ctx.senderPolicy).handle(AppChannel.GetPreloadPath, () => {
|
|
1358
|
+
return `file://${fs4.realpathSync(ctx.preloadPath)}`;
|
|
1359
|
+
}).handle(AppChannel.GetBranding, async () => {
|
|
1001
1360
|
if (ctx.brandingProvider) return ctx.brandingProvider();
|
|
1002
1361
|
return { appName: ctx.appName };
|
|
1003
1362
|
});
|
|
1004
1363
|
}
|
|
1005
1364
|
|
|
1365
|
+
// src/shared/ipc-schemas.ts
|
|
1366
|
+
import { z } from "zod";
|
|
1367
|
+
var AbsolutePath = z.string().min(1).refine(
|
|
1368
|
+
(p) => p.startsWith("/") || /^[a-zA-Z]:\\/.test(p) || /^[a-zA-Z]:\//.test(p),
|
|
1369
|
+
"must be an absolute path"
|
|
1370
|
+
);
|
|
1371
|
+
var PanelEvalSchema = z.tuple([z.string().min(1).max(5e4)]);
|
|
1372
|
+
var ProjectsAddSchema = z.tuple([AbsolutePath]);
|
|
1373
|
+
var ProjectOpenSchema = z.tuple([AbsolutePath]);
|
|
1374
|
+
var CompileConfigShape = z.looseObject({
|
|
1375
|
+
startPage: z.string().optional(),
|
|
1376
|
+
scene: z.number().optional(),
|
|
1377
|
+
queryParams: z.array(z.looseObject({ key: z.string(), value: z.string() })).optional()
|
|
1378
|
+
});
|
|
1379
|
+
var ProjectSaveCompileConfigSchema = z.tuple([
|
|
1380
|
+
AbsolutePath,
|
|
1381
|
+
CompileConfigShape
|
|
1382
|
+
]);
|
|
1383
|
+
var PopoverShowSchema = z.tuple([z.looseObject({})]);
|
|
1384
|
+
var SimWidth = z.number().int().min(100).max(2e3);
|
|
1385
|
+
var SimulatorAttachSchema = z.tuple([
|
|
1386
|
+
z.number().int().positive(),
|
|
1387
|
+
SimWidth
|
|
1388
|
+
]);
|
|
1389
|
+
var SimulatorResizeSchema = z.tuple([SimWidth]);
|
|
1390
|
+
var SimulatorSetVisibleSchema = z.tuple([z.boolean(), SimWidth]);
|
|
1391
|
+
var SimulatorCustomApiInvokeSchema = z.tuple([
|
|
1392
|
+
z.string().min(1).max(256),
|
|
1393
|
+
z.unknown()
|
|
1394
|
+
]);
|
|
1395
|
+
var ProjectGetPagesSchema = z.tuple([AbsolutePath]);
|
|
1396
|
+
var ProjectGetCompileConfigSchema = z.tuple([AbsolutePath]);
|
|
1397
|
+
var ProjectsRemoveSchema = z.tuple([AbsolutePath]);
|
|
1398
|
+
var WorkbenchSettingsSaveSchema = z.tuple([
|
|
1399
|
+
z.looseObject({
|
|
1400
|
+
cdp: z.looseObject({
|
|
1401
|
+
enabled: z.boolean(),
|
|
1402
|
+
port: z.number().int().min(0).max(65535)
|
|
1403
|
+
}),
|
|
1404
|
+
mcp: z.looseObject({
|
|
1405
|
+
enabled: z.boolean(),
|
|
1406
|
+
port: z.number().int().min(0).max(65535)
|
|
1407
|
+
}),
|
|
1408
|
+
compile: z.looseObject({
|
|
1409
|
+
watch: z.boolean()
|
|
1410
|
+
}),
|
|
1411
|
+
theme: z.enum(["system", "light", "dark"])
|
|
1412
|
+
})
|
|
1413
|
+
]);
|
|
1414
|
+
var WorkbenchSettingsSetThemeSchema = z.tuple([
|
|
1415
|
+
z.enum(["system", "light", "dark"])
|
|
1416
|
+
]);
|
|
1417
|
+
var WorkbenchSettingsSetVisibleSchema = z.tuple([z.boolean()]);
|
|
1418
|
+
var SettingsSetVisibleSchema = z.tuple([z.boolean()]);
|
|
1419
|
+
var SettingsConfigChangedSchema = z.tuple([CompileConfigShape]);
|
|
1420
|
+
var PopoverRelaunchSchema = z.tuple([CompileConfigShape]);
|
|
1421
|
+
var SettingsProjectSettingsChangedSchema = z.tuple([
|
|
1422
|
+
z.looseObject({
|
|
1423
|
+
uploadWithSourceMap: z.boolean().optional()
|
|
1424
|
+
})
|
|
1425
|
+
]);
|
|
1426
|
+
var PanelSelectSchema = z.tuple([z.string().min(1).max(200)]);
|
|
1427
|
+
|
|
1428
|
+
// src/main/services/simulator/custom-apis.ts
|
|
1429
|
+
function createSimulatorApiRegistry() {
|
|
1430
|
+
const handlers2 = /* @__PURE__ */ new Map();
|
|
1431
|
+
return {
|
|
1432
|
+
register(name, handler) {
|
|
1433
|
+
handlers2.set(name, handler);
|
|
1434
|
+
return () => {
|
|
1435
|
+
if (handlers2.get(name) === handler) handlers2.delete(name);
|
|
1436
|
+
};
|
|
1437
|
+
},
|
|
1438
|
+
list() {
|
|
1439
|
+
return Array.from(handlers2.keys());
|
|
1440
|
+
},
|
|
1441
|
+
async invoke(name, params) {
|
|
1442
|
+
const handler = handlers2.get(name);
|
|
1443
|
+
if (!handler) throw new Error(`Simulator API "${name}" is not registered`);
|
|
1444
|
+
return await handler(params);
|
|
1445
|
+
},
|
|
1446
|
+
clear() {
|
|
1447
|
+
handlers2.clear();
|
|
1448
|
+
}
|
|
1449
|
+
};
|
|
1450
|
+
}
|
|
1451
|
+
var simulatorApiRegistry = createSimulatorApiRegistry();
|
|
1452
|
+
|
|
1006
1453
|
// src/main/ipc/simulator.ts
|
|
1007
|
-
import { ipcMain as ipcMain2 } from "electron";
|
|
1008
1454
|
function registerSimulatorIpc(ctx) {
|
|
1009
|
-
|
|
1455
|
+
return new IpcRegistry(ctx.senderPolicy).handle(SimulatorChannel.Attach, (_, ...args) => {
|
|
1456
|
+
const [simWcId, simWidth] = validate(SimulatorChannel.Attach, SimulatorAttachSchema, args);
|
|
1010
1457
|
ctx.views.attachSimulator(simWcId, simWidth);
|
|
1011
|
-
})
|
|
1012
|
-
ipcMain2.handle(SimulatorChannel.Detach, () => {
|
|
1458
|
+
}).handle(SimulatorChannel.Detach, () => {
|
|
1013
1459
|
ctx.views.detachSimulator();
|
|
1014
|
-
})
|
|
1015
|
-
|
|
1460
|
+
}).handle(SimulatorChannel.Resize, (_, ...args) => {
|
|
1461
|
+
const [simWidth] = validate(SimulatorChannel.Resize, SimulatorResizeSchema, args);
|
|
1016
1462
|
ctx.views.resize(simWidth);
|
|
1017
|
-
})
|
|
1018
|
-
|
|
1463
|
+
}).handle(SimulatorChannel.SetVisible, (_, ...args) => {
|
|
1464
|
+
const [visible, simWidth] = validate(SimulatorChannel.SetVisible, SimulatorSetVisibleSchema, args);
|
|
1019
1465
|
ctx.views.setVisible(visible, simWidth);
|
|
1020
|
-
})
|
|
1021
|
-
|
|
1466
|
+
}).handle(SimulatorCustomApiChannel.List, () => {
|
|
1467
|
+
return simulatorApiRegistry.list();
|
|
1468
|
+
}).handle(SimulatorCustomApiChannel.Invoke, (_, ...args) => {
|
|
1469
|
+
const [name, params] = validate(SimulatorCustomApiChannel.Invoke, SimulatorCustomApiInvokeSchema, args);
|
|
1470
|
+
return simulatorApiRegistry.invoke(name, params);
|
|
1471
|
+
}).handle(WorkbenchChannel.GetPanelConfig, () => {
|
|
1022
1472
|
return ctx.panels;
|
|
1023
|
-
})
|
|
1024
|
-
ipcMain2.handle(WorkbenchChannel.GetApiNamespaces, () => {
|
|
1473
|
+
}).handle(WorkbenchChannel.GetApiNamespaces, () => {
|
|
1025
1474
|
return ctx.apiNamespaces;
|
|
1026
|
-
})
|
|
1027
|
-
ipcMain2.on(WorkbenchChannel.Reset, () => {
|
|
1475
|
+
}).on(WorkbenchChannel.Reset, () => {
|
|
1028
1476
|
ctx.notify.workbenchReset();
|
|
1029
1477
|
});
|
|
1030
1478
|
}
|
|
1031
1479
|
|
|
1032
1480
|
// src/main/ipc/panels.ts
|
|
1033
|
-
import {
|
|
1481
|
+
import { webContents as webContents2 } from "electron";
|
|
1034
1482
|
var BUILTIN_PANELS = [
|
|
1035
1483
|
{ id: "wxml", label: "WXML" },
|
|
1036
1484
|
{ id: "appdata", label: "AppData" },
|
|
1037
1485
|
{ id: "storage", label: "Storage" }
|
|
1038
1486
|
];
|
|
1039
1487
|
function registerPanelsIpc(ctx) {
|
|
1040
|
-
|
|
1488
|
+
return new IpcRegistry(ctx.senderPolicy).handle(PanelChannel.List, () => {
|
|
1041
1489
|
return BUILTIN_PANELS.filter((p) => ctx.panels.includes(p.id));
|
|
1042
|
-
})
|
|
1043
|
-
|
|
1490
|
+
}).handle(PanelChannel.Eval, async (_event, ...args) => {
|
|
1491
|
+
const [expression] = validate(PanelChannel.Eval, PanelEvalSchema, args);
|
|
1044
1492
|
const simWcId = ctx.views.getSimulatorWebContentsId();
|
|
1045
1493
|
if (!ctx.workspace.hasActiveSession() || simWcId == null) return void 0;
|
|
1046
1494
|
const sim = webContents2.fromId(simWcId);
|
|
@@ -1050,13 +1498,12 @@ function registerPanelsIpc(ctx) {
|
|
|
1050
1498
|
} catch {
|
|
1051
1499
|
return void 0;
|
|
1052
1500
|
}
|
|
1053
|
-
})
|
|
1054
|
-
|
|
1501
|
+
}).handle(PanelChannel.Select, (_event, ...args) => {
|
|
1502
|
+
validate(PanelChannel.Select, PanelSelectSchema, args);
|
|
1055
1503
|
if (ctx.views.hasSimulatorView() && ctx.views.isSimulatorAdded()) {
|
|
1056
1504
|
ctx.views.hideSimulator();
|
|
1057
1505
|
}
|
|
1058
|
-
})
|
|
1059
|
-
ipcMain3.handle(PanelChannel.SelectSimulator, () => {
|
|
1506
|
+
}).handle(PanelChannel.SelectSimulator, () => {
|
|
1060
1507
|
if (ctx.views.hasSimulatorView() && !ctx.views.isSimulatorAdded()) {
|
|
1061
1508
|
ctx.views.showSimulator(ctx.views.getLastSimWidth());
|
|
1062
1509
|
}
|
|
@@ -1064,76 +1511,119 @@ function registerPanelsIpc(ctx) {
|
|
|
1064
1511
|
}
|
|
1065
1512
|
|
|
1066
1513
|
// src/main/ipc/popover.ts
|
|
1067
|
-
import { ipcMain as ipcMain4 } from "electron";
|
|
1068
1514
|
function registerPopoverIpc(ctx) {
|
|
1069
|
-
|
|
1515
|
+
return new IpcRegistry(ctx.senderPolicy).handle(PopoverChannel.Show, (_event, ...args) => {
|
|
1516
|
+
const [data] = validate(PopoverChannel.Show, PopoverShowSchema, args);
|
|
1070
1517
|
ctx.views.showPopover(data);
|
|
1071
|
-
})
|
|
1072
|
-
|
|
1073
|
-
|
|
1518
|
+
}).handle(PopoverChannel.Hide, () => {
|
|
1519
|
+
ctx.views.hidePopover();
|
|
1520
|
+
}).on(PopoverChannel.Relaunch, (_event, ...args) => {
|
|
1521
|
+
const [newConfig] = validate(PopoverChannel.Relaunch, PopoverRelaunchSchema, args);
|
|
1074
1522
|
ctx.views.hidePopover();
|
|
1075
1523
|
ctx.notify.popoverRelaunch(newConfig);
|
|
1076
1524
|
});
|
|
1077
1525
|
}
|
|
1526
|
+
var popoverModule = {
|
|
1527
|
+
setup: (ctx) => registerPopoverIpc(ctx)
|
|
1528
|
+
};
|
|
1078
1529
|
|
|
1079
1530
|
// src/main/ipc/projects.ts
|
|
1080
|
-
import {
|
|
1531
|
+
import { dialog } from "electron";
|
|
1081
1532
|
function registerProjectsIpc(ctx) {
|
|
1082
|
-
|
|
1083
|
-
|
|
1533
|
+
return new IpcRegistry(ctx.senderPolicy).handle(ProjectsChannel.List, () => {
|
|
1534
|
+
return ctx.workspace.listProjects();
|
|
1535
|
+
}).handle(DialogChannel.OpenDirectory, async () => {
|
|
1084
1536
|
const result = await dialog.showOpenDialog(ctx.mainWindow, {
|
|
1085
1537
|
properties: ["openDirectory"],
|
|
1086
1538
|
title: "\u9009\u62E9\u5C0F\u7A0B\u5E8F\u9879\u76EE\u76EE\u5F55"
|
|
1087
1539
|
});
|
|
1088
1540
|
return result.canceled ? null : result.filePaths[0];
|
|
1541
|
+
}).handle(ProjectsChannel.Add, async (_event, ...args) => {
|
|
1542
|
+
const [dirPath] = validate(ProjectsChannel.Add, ProjectsAddSchema, args);
|
|
1543
|
+
const dirError = ctx.workspace.validateProjectDir(dirPath);
|
|
1544
|
+
if (dirError) {
|
|
1545
|
+
await dialog.showMessageBox(ctx.mainWindow, {
|
|
1546
|
+
type: "error",
|
|
1547
|
+
title: "\u65E0\u6CD5\u5BFC\u5165\u9879\u76EE",
|
|
1548
|
+
message: "\u8BE5\u76EE\u5F55\u4E0D\u662F\u6709\u6548\u7684\u5C0F\u7A0B\u5E8F\u9879\u76EE",
|
|
1549
|
+
detail: dirError,
|
|
1550
|
+
buttons: ["\u786E\u5B9A"]
|
|
1551
|
+
});
|
|
1552
|
+
throw new Error(dirError);
|
|
1553
|
+
}
|
|
1554
|
+
const duplicate = ctx.workspace.hasProject(dirPath);
|
|
1555
|
+
const project = ctx.workspace.addProject(dirPath);
|
|
1556
|
+
if (duplicate) {
|
|
1557
|
+
await dialog.showMessageBox(ctx.mainWindow, {
|
|
1558
|
+
type: "info",
|
|
1559
|
+
title: "\u9879\u76EE\u5DF2\u5B58\u5728",
|
|
1560
|
+
message: "\u8BE5\u9879\u76EE\u5DF2\u5728\u5217\u8868\u4E2D",
|
|
1561
|
+
detail: dirPath,
|
|
1562
|
+
buttons: ["\u786E\u5B9A"]
|
|
1563
|
+
});
|
|
1564
|
+
}
|
|
1565
|
+
return project;
|
|
1566
|
+
}).handle(ProjectsChannel.Remove, (_event, ...args) => {
|
|
1567
|
+
const [dirPath] = validate(ProjectsChannel.Remove, ProjectsRemoveSchema, args);
|
|
1568
|
+
return ctx.workspace.removeProject(dirPath);
|
|
1089
1569
|
});
|
|
1090
|
-
ipcMain5.handle(
|
|
1091
|
-
ProjectsChannel.Add,
|
|
1092
|
-
(_, dirPath) => ctx.workspace.addProject(dirPath)
|
|
1093
|
-
);
|
|
1094
|
-
ipcMain5.handle(
|
|
1095
|
-
ProjectsChannel.Remove,
|
|
1096
|
-
(_, dirPath) => ctx.workspace.removeProject(dirPath)
|
|
1097
|
-
);
|
|
1098
1570
|
}
|
|
1571
|
+
var projectsModule = {
|
|
1572
|
+
setup: (ctx) => registerProjectsIpc(ctx)
|
|
1573
|
+
};
|
|
1099
1574
|
|
|
1100
1575
|
// src/main/ipc/session.ts
|
|
1101
|
-
import { ipcMain as ipcMain6 } from "electron";
|
|
1102
1576
|
function registerSessionIpc(ctx) {
|
|
1103
|
-
|
|
1104
|
-
ProjectChannel.Open,
|
|
1105
|
-
|
|
1106
|
-
)
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1577
|
+
return new IpcRegistry(ctx.senderPolicy).handle(ProjectChannel.Open, (_, ...args) => {
|
|
1578
|
+
const [projectPath] = validate(ProjectChannel.Open, ProjectOpenSchema, args);
|
|
1579
|
+
return ctx.workspace.openProject(projectPath);
|
|
1580
|
+
}).handle(ProjectChannel.GetPages, (_, ...args) => {
|
|
1581
|
+
const [projectPath] = validate(ProjectChannel.GetPages, ProjectGetPagesSchema, args);
|
|
1582
|
+
return ctx.workspace.getProjectPages(projectPath);
|
|
1583
|
+
}).handle(ProjectChannel.GetCompileConfig, (_, ...args) => {
|
|
1584
|
+
const [projectPath] = validate(
|
|
1585
|
+
ProjectChannel.GetCompileConfig,
|
|
1586
|
+
ProjectGetCompileConfigSchema,
|
|
1587
|
+
args
|
|
1588
|
+
);
|
|
1589
|
+
return ctx.workspace.getCompileConfig(projectPath);
|
|
1590
|
+
}).handle(ProjectChannel.SaveCompileConfig, (_, ...args) => {
|
|
1591
|
+
const [projectPath, config] = validate(
|
|
1592
|
+
ProjectChannel.SaveCompileConfig,
|
|
1593
|
+
ProjectSaveCompileConfigSchema,
|
|
1594
|
+
args
|
|
1595
|
+
);
|
|
1596
|
+
return ctx.workspace.saveCompileConfig(projectPath, config);
|
|
1597
|
+
}).handle(ProjectChannel.Close, () => {
|
|
1598
|
+
return ctx.workspace.closeProject();
|
|
1599
|
+
});
|
|
1120
1600
|
}
|
|
1601
|
+
var sessionModule = {
|
|
1602
|
+
setup: (ctx) => registerSessionIpc(ctx)
|
|
1603
|
+
};
|
|
1121
1604
|
|
|
1122
1605
|
// src/main/ipc/settings.ts
|
|
1123
|
-
import { app as app7
|
|
1606
|
+
import { app as app7 } from "electron";
|
|
1124
1607
|
function registerSettingsIpc(ctx) {
|
|
1125
|
-
|
|
1608
|
+
return new IpcRegistry(ctx.senderPolicy).handle(WorkbenchSettingsChannel.Get, () => {
|
|
1126
1609
|
return loadWorkbenchSettings();
|
|
1127
|
-
})
|
|
1128
|
-
|
|
1610
|
+
}).handle(WorkbenchSettingsChannel.Save, (_, ...args) => {
|
|
1611
|
+
const [settings] = validate(
|
|
1612
|
+
WorkbenchSettingsChannel.Save,
|
|
1613
|
+
WorkbenchSettingsSaveSchema,
|
|
1614
|
+
args
|
|
1615
|
+
);
|
|
1129
1616
|
saveWorkbenchSettings(settings);
|
|
1130
1617
|
applyTheme(settings.theme ?? "system");
|
|
1131
1618
|
return { success: true };
|
|
1132
|
-
})
|
|
1133
|
-
|
|
1619
|
+
}).handle(WorkbenchSettingsChannel.SetTheme, (_, ...args) => {
|
|
1620
|
+
const [theme] = validate(
|
|
1621
|
+
WorkbenchSettingsChannel.SetTheme,
|
|
1622
|
+
WorkbenchSettingsSetThemeSchema,
|
|
1623
|
+
args
|
|
1624
|
+
);
|
|
1134
1625
|
applyTheme(theme);
|
|
1135
|
-
})
|
|
1136
|
-
ipcMain7.handle(WorkbenchSettingsChannel.GetCdpStatus, () => {
|
|
1626
|
+
}).handle(WorkbenchSettingsChannel.GetCdpStatus, () => {
|
|
1137
1627
|
const settings = loadWorkbenchSettings();
|
|
1138
1628
|
const switchValue = app7.commandLine.getSwitchValue("remote-debugging-port");
|
|
1139
1629
|
const implicitDevDefault = !app7.isPackaged && !settings.cdp.enabled && switchValue === "9222";
|
|
@@ -1144,15 +1634,19 @@ function registerSettingsIpc(ctx) {
|
|
|
1144
1634
|
activePort: switchValue ? parseInt(switchValue, 10) : null,
|
|
1145
1635
|
implicitDevDefault
|
|
1146
1636
|
};
|
|
1147
|
-
})
|
|
1148
|
-
|
|
1637
|
+
}).handle(WorkbenchSettingsChannel.SetVisible, async (_, ...args) => {
|
|
1638
|
+
const [visible] = validate(
|
|
1639
|
+
WorkbenchSettingsChannel.SetVisible,
|
|
1640
|
+
WorkbenchSettingsSetVisibleSchema,
|
|
1641
|
+
args
|
|
1642
|
+
);
|
|
1149
1643
|
if (visible) {
|
|
1150
1644
|
await openSettingsWindow(ctx);
|
|
1151
1645
|
} else {
|
|
1152
|
-
ctx.
|
|
1646
|
+
ctx.windows.closeSettingsWindow();
|
|
1153
1647
|
}
|
|
1154
|
-
})
|
|
1155
|
-
|
|
1648
|
+
}).handle(SettingsChannel.SetVisible, async (_, ...args) => {
|
|
1649
|
+
const [visible] = validate(SettingsChannel.SetVisible, SettingsSetVisibleSchema, args);
|
|
1156
1650
|
if (visible) {
|
|
1157
1651
|
await ctx.views.showSettings();
|
|
1158
1652
|
ctx.notify.settingsInit({
|
|
@@ -1164,32 +1658,55 @@ function registerSettingsIpc(ctx) {
|
|
|
1164
1658
|
ctx.views.hideSettings();
|
|
1165
1659
|
ctx.notify.settingsClosed();
|
|
1166
1660
|
}
|
|
1167
|
-
})
|
|
1168
|
-
|
|
1661
|
+
}).on(SettingsChannel.ConfigChanged, (_, ...args) => {
|
|
1662
|
+
const [config] = validate(
|
|
1663
|
+
SettingsChannel.ConfigChanged,
|
|
1664
|
+
SettingsConfigChangedSchema,
|
|
1665
|
+
args
|
|
1666
|
+
);
|
|
1169
1667
|
if (ctx.workspace.getProjectPath()) {
|
|
1170
|
-
ctx.workspace.saveCompileConfig(
|
|
1668
|
+
ctx.workspace.saveCompileConfig(
|
|
1669
|
+
ctx.workspace.getProjectPath(),
|
|
1670
|
+
config
|
|
1671
|
+
);
|
|
1171
1672
|
}
|
|
1172
1673
|
ctx.notify.settingsChanged(config);
|
|
1674
|
+
}).on(SettingsChannel.ProjectSettingsChanged, (_, ...args) => {
|
|
1675
|
+
const [patch] = validate(
|
|
1676
|
+
SettingsChannel.ProjectSettingsChanged,
|
|
1677
|
+
SettingsProjectSettingsChangedSchema,
|
|
1678
|
+
args
|
|
1679
|
+
);
|
|
1680
|
+
ctx.workspace.updateProjectSettings(
|
|
1681
|
+
ctx.workspace.getProjectPath(),
|
|
1682
|
+
patch
|
|
1683
|
+
);
|
|
1173
1684
|
});
|
|
1174
|
-
ipcMain7.on(
|
|
1175
|
-
SettingsChannel.ProjectSettingsChanged,
|
|
1176
|
-
(_, patch) => {
|
|
1177
|
-
ctx.workspace.updateProjectSettings(ctx.workspace.getProjectPath(), patch);
|
|
1178
|
-
}
|
|
1179
|
-
);
|
|
1180
1685
|
}
|
|
1686
|
+
var settingsModule = {
|
|
1687
|
+
setup: (ctx) => registerSettingsIpc(ctx)
|
|
1688
|
+
};
|
|
1181
1689
|
|
|
1182
1690
|
// src/main/ipc/toolbar.ts
|
|
1183
|
-
import { ipcMain as ipcMain8 } from "electron";
|
|
1184
1691
|
function registerToolbarIpc(ctx) {
|
|
1185
|
-
|
|
1692
|
+
return new IpcRegistry(ctx.senderPolicy).handle(ToolbarChannel.GetActions, async () => {
|
|
1186
1693
|
if (ctx.toolbarActions) return ctx.toolbarActions();
|
|
1187
1694
|
return [];
|
|
1188
1695
|
});
|
|
1189
1696
|
}
|
|
1190
1697
|
|
|
1698
|
+
// src/main/ipc/simulator-module.ts
|
|
1699
|
+
var simulatorModule = {
|
|
1700
|
+
setup: (ctx) => {
|
|
1701
|
+
const reg = new DisposableRegistry();
|
|
1702
|
+
reg.add(registerSimulatorIpc(ctx));
|
|
1703
|
+
reg.add(registerPanelsIpc(ctx));
|
|
1704
|
+
reg.add(registerToolbarIpc(ctx));
|
|
1705
|
+
return reg;
|
|
1706
|
+
}
|
|
1707
|
+
};
|
|
1708
|
+
|
|
1191
1709
|
// src/main/services/automation/index.ts
|
|
1192
|
-
import { ipcMain as ipcMain9 } from "electron";
|
|
1193
1710
|
import { WebSocketServer } from "ws";
|
|
1194
1711
|
|
|
1195
1712
|
// src/main/services/automation/exec.ts
|
|
@@ -1578,7 +2095,6 @@ var handlers = {
|
|
|
1578
2095
|
...elementHandlers
|
|
1579
2096
|
};
|
|
1580
2097
|
var currentPort = null;
|
|
1581
|
-
var portIpcRegistered = false;
|
|
1582
2098
|
async function startAutomationServer(ctx, port = 0) {
|
|
1583
2099
|
const wss = new WebSocketServer({ port });
|
|
1584
2100
|
const clients = /* @__PURE__ */ new Set();
|
|
@@ -1589,10 +2105,10 @@ async function startAutomationServer(ctx, port = 0) {
|
|
|
1589
2105
|
const addr = wss.address();
|
|
1590
2106
|
const resolvedPort = typeof addr === "object" && addr ? addr.port : port;
|
|
1591
2107
|
currentPort = resolvedPort;
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
}
|
|
2108
|
+
const portIpc = new IpcRegistry(ctx.senderPolicy);
|
|
2109
|
+
portIpc.handle(AutomationChannel.GetPort, () => {
|
|
2110
|
+
return currentPort;
|
|
2111
|
+
});
|
|
1596
2112
|
function broadcast(event) {
|
|
1597
2113
|
const msg = JSON.stringify(event);
|
|
1598
2114
|
for (const ws of clients) {
|
|
@@ -1600,14 +2116,46 @@ async function startAutomationServer(ctx, port = 0) {
|
|
|
1600
2116
|
}
|
|
1601
2117
|
}
|
|
1602
2118
|
let consoleForwardingSetup = false;
|
|
2119
|
+
let pollInterval = null;
|
|
2120
|
+
let pollStopTimer = null;
|
|
2121
|
+
let attachedSim = null;
|
|
2122
|
+
let ipcMessageHostHandler = null;
|
|
2123
|
+
let simDestroyedHandler = null;
|
|
2124
|
+
function detachConsoleForwarding() {
|
|
2125
|
+
if (attachedSim) {
|
|
2126
|
+
if (ipcMessageHostHandler) {
|
|
2127
|
+
try {
|
|
2128
|
+
if (!attachedSim.isDestroyed()) {
|
|
2129
|
+
;
|
|
2130
|
+
attachedSim.removeListener("ipc-message-host", ipcMessageHostHandler);
|
|
2131
|
+
}
|
|
2132
|
+
} catch {
|
|
2133
|
+
}
|
|
2134
|
+
}
|
|
2135
|
+
if (simDestroyedHandler) {
|
|
2136
|
+
try {
|
|
2137
|
+
if (!attachedSim.isDestroyed()) {
|
|
2138
|
+
attachedSim.removeListener("destroyed", simDestroyedHandler);
|
|
2139
|
+
}
|
|
2140
|
+
} catch {
|
|
2141
|
+
}
|
|
2142
|
+
}
|
|
2143
|
+
}
|
|
2144
|
+
attachedSim = null;
|
|
2145
|
+
ipcMessageHostHandler = null;
|
|
2146
|
+
simDestroyedHandler = null;
|
|
2147
|
+
}
|
|
1603
2148
|
function setupConsoleForwarding() {
|
|
1604
2149
|
if (consoleForwardingSetup) return;
|
|
1605
2150
|
consoleForwardingSetup = true;
|
|
1606
|
-
|
|
2151
|
+
pollInterval = setInterval(() => {
|
|
1607
2152
|
const sim = getSimulator(ctx);
|
|
1608
2153
|
if (!sim) return;
|
|
1609
|
-
|
|
1610
|
-
|
|
2154
|
+
if (pollInterval) {
|
|
2155
|
+
clearInterval(pollInterval);
|
|
2156
|
+
pollInterval = null;
|
|
2157
|
+
}
|
|
2158
|
+
const onIpcMessageHost = (_event, channel, data) => {
|
|
1611
2159
|
if (channel === SimulatorChannel.Console) {
|
|
1612
2160
|
const logData = data;
|
|
1613
2161
|
broadcast({
|
|
@@ -1615,9 +2163,26 @@ async function startAutomationServer(ctx, port = 0) {
|
|
|
1615
2163
|
params: { type: logData.level || "log", args: logData.args || [] }
|
|
1616
2164
|
});
|
|
1617
2165
|
}
|
|
1618
|
-
}
|
|
2166
|
+
};
|
|
2167
|
+
const onSimDestroyed = () => {
|
|
2168
|
+
attachedSim = null;
|
|
2169
|
+
ipcMessageHostHandler = null;
|
|
2170
|
+
simDestroyedHandler = null;
|
|
2171
|
+
consoleForwardingSetup = false;
|
|
2172
|
+
};
|
|
2173
|
+
attachedSim = sim;
|
|
2174
|
+
ipcMessageHostHandler = onIpcMessageHost;
|
|
2175
|
+
simDestroyedHandler = onSimDestroyed;
|
|
2176
|
+
sim.on("ipc-message-host", onIpcMessageHost);
|
|
2177
|
+
sim.once("destroyed", onSimDestroyed);
|
|
1619
2178
|
}, 1e3);
|
|
1620
|
-
setTimeout(() =>
|
|
2179
|
+
pollStopTimer = setTimeout(() => {
|
|
2180
|
+
if (pollInterval) {
|
|
2181
|
+
clearInterval(pollInterval);
|
|
2182
|
+
pollInterval = null;
|
|
2183
|
+
}
|
|
2184
|
+
pollStopTimer = null;
|
|
2185
|
+
}, 3e4);
|
|
1621
2186
|
}
|
|
1622
2187
|
wss.on("connection", (ws) => {
|
|
1623
2188
|
clients.add(ws);
|
|
@@ -1648,7 +2213,24 @@ async function startAutomationServer(ctx, port = 0) {
|
|
|
1648
2213
|
});
|
|
1649
2214
|
return {
|
|
1650
2215
|
close: () => {
|
|
2216
|
+
if (pollInterval) {
|
|
2217
|
+
clearInterval(pollInterval);
|
|
2218
|
+
pollInterval = null;
|
|
2219
|
+
}
|
|
2220
|
+
if (pollStopTimer) {
|
|
2221
|
+
clearTimeout(pollStopTimer);
|
|
2222
|
+
pollStopTimer = null;
|
|
2223
|
+
}
|
|
2224
|
+
detachConsoleForwarding();
|
|
2225
|
+
for (const ws of clients) {
|
|
2226
|
+
try {
|
|
2227
|
+
ws.close();
|
|
2228
|
+
} catch {
|
|
2229
|
+
}
|
|
2230
|
+
}
|
|
2231
|
+
clients.clear();
|
|
1651
2232
|
if (currentPort === resolvedPort) currentPort = null;
|
|
2233
|
+
void portIpc.dispose();
|
|
1652
2234
|
wss.close();
|
|
1653
2235
|
},
|
|
1654
2236
|
port: resolvedPort
|
|
@@ -1807,7 +2389,7 @@ function getClient(kind) {
|
|
|
1807
2389
|
}
|
|
1808
2390
|
|
|
1809
2391
|
// src/main/services/mcp/tool-registry.ts
|
|
1810
|
-
import { z } from "zod";
|
|
2392
|
+
import { z as z2 } from "zod";
|
|
1811
2393
|
function registerCommonTargetTools(server, kind) {
|
|
1812
2394
|
const descriptions = kind === "simulator" ? {
|
|
1813
2395
|
screenshot: "Take a screenshot of the simulator webview",
|
|
@@ -1828,9 +2410,9 @@ function registerCommonTargetTools(server, kind) {
|
|
|
1828
2410
|
return { content: [{ type: "image", data, mimeType: "image/png" }] };
|
|
1829
2411
|
});
|
|
1830
2412
|
server.tool(`${kind}_console_logs`, descriptions.consoleLogs, {
|
|
1831
|
-
limit:
|
|
1832
|
-
level:
|
|
1833
|
-
sinceTimestamp:
|
|
2413
|
+
limit: z2.number().optional().default(50).describe("Maximum number of log entries"),
|
|
2414
|
+
level: z2.enum(["error", "warning", "warn", "info", "log", "debug"]).optional().describe("Only return entries with this level"),
|
|
2415
|
+
sinceTimestamp: z2.string().optional().describe("ISO timestamp; only return entries at or after this time")
|
|
1834
2416
|
}, async ({ limit, level, sinceTimestamp }) => {
|
|
1835
2417
|
getClient(kind);
|
|
1836
2418
|
let entries = getTargetState(kind).consoleLogs;
|
|
@@ -1845,7 +2427,7 @@ function registerCommonTargetTools(server, kind) {
|
|
|
1845
2427
|
});
|
|
1846
2428
|
if (kind !== "workbench") {
|
|
1847
2429
|
server.tool(`${kind}_evaluate`, descriptions.evaluate, {
|
|
1848
|
-
expression:
|
|
2430
|
+
expression: z2.string().describe("JavaScript expression to evaluate")
|
|
1849
2431
|
}, async ({ expression }) => {
|
|
1850
2432
|
const c = getClient(kind);
|
|
1851
2433
|
const result = await c.Runtime.evaluate({ expression, returnByValue: true, awaitPromise: true });
|
|
@@ -1858,15 +2440,15 @@ ${JSON.stringify(result.exceptionDetails, null, 2)}` }], isError: true };
|
|
|
1858
2440
|
});
|
|
1859
2441
|
}
|
|
1860
2442
|
server.tool(`${kind}_get_dom`, descriptions.getDom, {
|
|
1861
|
-
depth:
|
|
2443
|
+
depth: z2.number().optional().default(3).describe("Maximum depth")
|
|
1862
2444
|
}, async ({ depth }) => {
|
|
1863
2445
|
const c = getClient(kind);
|
|
1864
2446
|
const { root } = await c.DOM.getDocument({ depth });
|
|
1865
2447
|
return { content: [{ type: "text", text: JSON.stringify(root, null, 2) }] };
|
|
1866
2448
|
});
|
|
1867
2449
|
server.tool(`${kind}_network_log`, descriptions.networkLog, {
|
|
1868
|
-
limit:
|
|
1869
|
-
minStatus:
|
|
2450
|
+
limit: z2.number().optional().default(20).describe("Maximum number of entries"),
|
|
2451
|
+
minStatus: z2.number().optional().describe("Only return entries with status >= minStatus (status 0 = failed before response is included when minStatus >= 400)")
|
|
1870
2452
|
}, async ({ limit, minStatus }) => {
|
|
1871
2453
|
getClient(kind);
|
|
1872
2454
|
let entries = getTargetState(kind).networkRequests;
|
|
@@ -2109,11 +2691,11 @@ function registerContextTools(server) {
|
|
|
2109
2691
|
}
|
|
2110
2692
|
|
|
2111
2693
|
// src/main/services/mcp/tools/simulator-tools.ts
|
|
2112
|
-
import { z as
|
|
2694
|
+
import { z as z3 } from "zod";
|
|
2113
2695
|
function registerSimulatorTools(server) {
|
|
2114
2696
|
server.tool("simulator_navigate", "Navigate the simulator to a URL, or reload the current page", {
|
|
2115
|
-
url:
|
|
2116
|
-
reload:
|
|
2697
|
+
url: z3.string().optional().describe("URL to navigate to"),
|
|
2698
|
+
reload: z3.boolean().optional().describe("If true, reload current page instead of navigating")
|
|
2117
2699
|
}, async ({ url, reload }) => {
|
|
2118
2700
|
const c = getClient("simulator");
|
|
2119
2701
|
if (reload) {
|
|
@@ -2128,15 +2710,15 @@ function registerSimulatorTools(server) {
|
|
|
2128
2710
|
return { content: [{ type: "text", text: "Error: either url or reload is required" }], isError: true };
|
|
2129
2711
|
});
|
|
2130
2712
|
server.tool("simulator_input", "Dispatch input to the simulator. `tap_coord` requires x and y. `tap_selector` requires selector and optional nth. `type` requires selector and text. `scroll` requires x, y, deltaX, and deltaY. `key` is best-effort for common keys such as Enter, Escape, Tab, Arrow* and Space.", {
|
|
2131
|
-
action:
|
|
2132
|
-
x:
|
|
2133
|
-
y:
|
|
2134
|
-
selector:
|
|
2135
|
-
nth:
|
|
2136
|
-
text:
|
|
2137
|
-
key:
|
|
2138
|
-
deltaX:
|
|
2139
|
-
deltaY:
|
|
2713
|
+
action: z3.enum(["tap_coord", "tap_selector", "type", "scroll", "key"]).describe("Input action to dispatch"),
|
|
2714
|
+
x: z3.number().optional().describe("Viewport x coordinate for `tap_coord` or `scroll`"),
|
|
2715
|
+
y: z3.number().optional().describe("Viewport y coordinate for `tap_coord` or `scroll`"),
|
|
2716
|
+
selector: z3.string().optional().describe("CSS selector for `tap_selector` or `type`"),
|
|
2717
|
+
nth: z3.number().int().optional().describe("Zero-based index when selector matches multiple elements; defaults to 0"),
|
|
2718
|
+
text: z3.string().optional().describe("Text to insert for `type`"),
|
|
2719
|
+
key: z3.string().optional().describe("Best-effort keyboard key name for `key`; common keys such as Enter, Escape, Tab, Arrow* and Space work best"),
|
|
2720
|
+
deltaX: z3.number().optional().describe("Horizontal wheel delta for `scroll`"),
|
|
2721
|
+
deltaY: z3.number().optional().describe("Vertical wheel delta for `scroll`")
|
|
2140
2722
|
}, async ({ action, x, y, selector, nth, text, key, deltaX, deltaY }) => {
|
|
2141
2723
|
const c = getClient("simulator");
|
|
2142
2724
|
const err = (msg) => ({ content: [{ type: "text", text: `Error: ${msg}` }], isError: true });
|
|
@@ -2291,110 +2873,327 @@ function startMcpServer(resolvedCdpPort, mcpPort) {
|
|
|
2291
2873
|
httpServer.listen(mcpPort, "127.0.0.1", () => {
|
|
2292
2874
|
console.log(`[MCP] SSE server listening on http://127.0.0.1:${mcpPort}/sse`);
|
|
2293
2875
|
});
|
|
2876
|
+
return toDisposable(() => {
|
|
2877
|
+
transports.clear();
|
|
2878
|
+
httpServer.close();
|
|
2879
|
+
});
|
|
2294
2880
|
}
|
|
2295
2881
|
|
|
2296
2882
|
// src/main/services/simulator-storage/index.ts
|
|
2297
|
-
import { app as app8,
|
|
2298
|
-
var attachedWc = null;
|
|
2299
|
-
var hostWc = null;
|
|
2883
|
+
import { app as app8, webContents as wcStatic } from "electron";
|
|
2300
2884
|
function isSimulatorWebview(wc) {
|
|
2301
2885
|
if (wc.isDestroyed()) return false;
|
|
2302
2886
|
if (wc.getType() !== "webview") return false;
|
|
2303
2887
|
return wc.getURL().includes("simulator.html");
|
|
2304
2888
|
}
|
|
2305
|
-
function
|
|
2306
|
-
if (!attachedWc) return;
|
|
2307
|
-
const wc = attachedWc;
|
|
2308
|
-
attachedWc = null;
|
|
2889
|
+
function safeOff(target, event, fn) {
|
|
2309
2890
|
try {
|
|
2310
|
-
if (
|
|
2311
|
-
|
|
2312
|
-
}
|
|
2891
|
+
if (target.isDestroyed?.()) return;
|
|
2892
|
+
target.removeListener(event, fn);
|
|
2313
2893
|
} catch {
|
|
2314
2894
|
}
|
|
2315
2895
|
}
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2896
|
+
function setupSimulatorStorage(host, options) {
|
|
2897
|
+
const registry = new DisposableRegistry();
|
|
2898
|
+
const getActiveAppId = options.getActiveAppId;
|
|
2899
|
+
let attachedWc = null;
|
|
2900
|
+
let attachDisposables = null;
|
|
2901
|
+
let cachedOrigin = null;
|
|
2902
|
+
function activePrefix() {
|
|
2903
|
+
const appId = getActiveAppId();
|
|
2904
|
+
return appId ? `${appId}_` : null;
|
|
2905
|
+
}
|
|
2906
|
+
function detachFromSim() {
|
|
2907
|
+
if (!attachedWc) return;
|
|
2908
|
+
const wc = attachedWc;
|
|
2909
|
+
attachedWc = null;
|
|
2910
|
+
cachedOrigin = null;
|
|
2911
|
+
const ad = attachDisposables;
|
|
2912
|
+
attachDisposables = null;
|
|
2913
|
+
if (ad) void ad.disposeAll().catch(() => {
|
|
2328
2914
|
});
|
|
2329
|
-
|
|
2330
|
-
if (
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2915
|
+
try {
|
|
2916
|
+
if (!wc.isDestroyed() && wc.debugger.isAttached()) {
|
|
2917
|
+
wc.debugger.detach();
|
|
2918
|
+
}
|
|
2919
|
+
} catch {
|
|
2920
|
+
}
|
|
2335
2921
|
}
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2922
|
+
async function attachToSim(wc) {
|
|
2923
|
+
if (attachedWc === wc) return;
|
|
2924
|
+
if (wc.isDestroyed()) return;
|
|
2925
|
+
detachFromSim();
|
|
2926
|
+
try {
|
|
2927
|
+
if (!wc.debugger.isAttached()) {
|
|
2928
|
+
wc.debugger.attach("1.3");
|
|
2929
|
+
}
|
|
2930
|
+
await wc.debugger.sendCommand("DOMStorage.enable");
|
|
2931
|
+
const attach = new DisposableRegistry();
|
|
2932
|
+
attachDisposables = attach;
|
|
2933
|
+
const onMessage = (_event, method, params) => forwardCdpMessage(method, params);
|
|
2934
|
+
wc.debugger.on("message", onMessage);
|
|
2935
|
+
attach.add(() => safeOff(wc.debugger, "message", onMessage));
|
|
2936
|
+
const onDetach = () => {
|
|
2937
|
+
if (attachedWc === wc) attachedWc = null;
|
|
2351
2938
|
};
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2939
|
+
wc.debugger.on("detach", onDetach);
|
|
2940
|
+
attach.add(() => safeOff(wc.debugger, "detach", onDetach));
|
|
2941
|
+
const onDestroyed = () => {
|
|
2942
|
+
if (attachedWc === wc) {
|
|
2943
|
+
attachedWc = null;
|
|
2944
|
+
const ad = attachDisposables;
|
|
2945
|
+
attachDisposables = null;
|
|
2946
|
+
if (ad) void ad.disposeAll().catch(() => {
|
|
2947
|
+
});
|
|
2948
|
+
}
|
|
2949
|
+
};
|
|
2950
|
+
wc.once("destroyed", onDestroyed);
|
|
2951
|
+
attach.add(() => safeOff(wc, "destroyed", onDestroyed));
|
|
2952
|
+
attachedWc = wc;
|
|
2953
|
+
} catch (e) {
|
|
2954
|
+
console.warn("[storage-watcher] attach failed:", e.message);
|
|
2955
|
+
}
|
|
2956
|
+
}
|
|
2957
|
+
function forwardCdpMessage(method, params) {
|
|
2958
|
+
if (host.isDestroyed()) return;
|
|
2959
|
+
const p = params;
|
|
2960
|
+
const prefix = activePrefix();
|
|
2961
|
+
let evt;
|
|
2962
|
+
switch (method) {
|
|
2963
|
+
case "DOMStorage.domStorageItemAdded": {
|
|
2964
|
+
const key = String(p.key);
|
|
2965
|
+
if (prefix && !key.startsWith(prefix)) return;
|
|
2966
|
+
evt = { type: "added", key, newValue: String(p.newValue ?? "") };
|
|
2967
|
+
break;
|
|
2968
|
+
}
|
|
2969
|
+
case "DOMStorage.domStorageItemUpdated": {
|
|
2970
|
+
const key = String(p.key);
|
|
2971
|
+
if (prefix && !key.startsWith(prefix)) return;
|
|
2972
|
+
evt = {
|
|
2973
|
+
type: "updated",
|
|
2974
|
+
key,
|
|
2975
|
+
oldValue: String(p.oldValue ?? ""),
|
|
2976
|
+
newValue: String(p.newValue ?? "")
|
|
2977
|
+
};
|
|
2978
|
+
break;
|
|
2979
|
+
}
|
|
2980
|
+
case "DOMStorage.domStorageItemRemoved": {
|
|
2981
|
+
const key = String(p.key);
|
|
2982
|
+
if (prefix && !key.startsWith(prefix)) return;
|
|
2983
|
+
evt = { type: "removed", key };
|
|
2984
|
+
break;
|
|
2985
|
+
}
|
|
2986
|
+
case "DOMStorage.domStorageItemsCleared":
|
|
2987
|
+
evt = { type: "cleared" };
|
|
2988
|
+
break;
|
|
2989
|
+
default:
|
|
2990
|
+
return;
|
|
2991
|
+
}
|
|
2992
|
+
host.send(SimulatorStorageChannel.Event, evt);
|
|
2361
2993
|
}
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2994
|
+
async function ensureAttached() {
|
|
2995
|
+
if (attachedWc && !attachedWc.isDestroyed()) return;
|
|
2996
|
+
const sim = findSimulatorWebContents();
|
|
2997
|
+
if (!sim) return;
|
|
2998
|
+
await attachToSim(sim);
|
|
2999
|
+
}
|
|
3000
|
+
async function getStorageId() {
|
|
3001
|
+
if (!attachedWc || attachedWc.isDestroyed()) return null;
|
|
3002
|
+
if (!cachedOrigin) {
|
|
3003
|
+
try {
|
|
3004
|
+
cachedOrigin = String(await attachedWc.executeJavaScript("location.origin"));
|
|
3005
|
+
} catch {
|
|
3006
|
+
return null;
|
|
3007
|
+
}
|
|
3008
|
+
}
|
|
3009
|
+
return { securityOrigin: cachedOrigin, isLocalStorage: true };
|
|
3010
|
+
}
|
|
3011
|
+
function pushSyntheticEvent(evt) {
|
|
3012
|
+
if (host.isDestroyed()) return;
|
|
3013
|
+
const prefix = activePrefix();
|
|
3014
|
+
if (prefix && !evt.key.startsWith(prefix)) return;
|
|
3015
|
+
host.send(SimulatorStorageChannel.Event, evt);
|
|
3016
|
+
}
|
|
3017
|
+
async function setItem(key, value) {
|
|
3018
|
+
await ensureAttached();
|
|
3019
|
+
if (!attachedWc || attachedWc.isDestroyed()) {
|
|
3020
|
+
return { ok: false, error: "simulator not attached" };
|
|
3021
|
+
}
|
|
3022
|
+
const storageId = await getStorageId();
|
|
3023
|
+
if (!storageId) return { ok: false, error: "failed to resolve simulator origin" };
|
|
3024
|
+
try {
|
|
3025
|
+
await attachedWc.debugger.sendCommand("DOMStorage.setDOMStorageItem", {
|
|
3026
|
+
storageId,
|
|
3027
|
+
key,
|
|
3028
|
+
value
|
|
3029
|
+
});
|
|
3030
|
+
pushSyntheticEvent({ type: "added", key, newValue: value });
|
|
3031
|
+
return { ok: true };
|
|
3032
|
+
} catch (e) {
|
|
3033
|
+
return { ok: false, error: e.message };
|
|
3034
|
+
}
|
|
3035
|
+
}
|
|
3036
|
+
async function removeItem(key) {
|
|
3037
|
+
await ensureAttached();
|
|
3038
|
+
if (!attachedWc || attachedWc.isDestroyed()) {
|
|
3039
|
+
return { ok: false, error: "simulator not attached" };
|
|
3040
|
+
}
|
|
3041
|
+
const storageId = await getStorageId();
|
|
3042
|
+
if (!storageId) return { ok: false, error: "failed to resolve simulator origin" };
|
|
3043
|
+
try {
|
|
3044
|
+
await attachedWc.debugger.sendCommand("DOMStorage.removeDOMStorageItem", {
|
|
3045
|
+
storageId,
|
|
3046
|
+
key
|
|
3047
|
+
});
|
|
3048
|
+
pushSyntheticEvent({ type: "removed", key });
|
|
3049
|
+
return { ok: true };
|
|
3050
|
+
} catch (e) {
|
|
3051
|
+
return { ok: false, error: e.message };
|
|
3052
|
+
}
|
|
3053
|
+
}
|
|
3054
|
+
async function clearScoped() {
|
|
3055
|
+
await ensureAttached();
|
|
3056
|
+
if (!attachedWc || attachedWc.isDestroyed()) {
|
|
3057
|
+
return { ok: false, error: "simulator not attached" };
|
|
3058
|
+
}
|
|
3059
|
+
const storageId = await getStorageId();
|
|
3060
|
+
if (!storageId) return { ok: false, error: "failed to resolve simulator origin" };
|
|
3061
|
+
const prefix = activePrefix();
|
|
3062
|
+
try {
|
|
3063
|
+
if (!prefix) {
|
|
3064
|
+
await attachedWc.debugger.sendCommand("DOMStorage.clear", { storageId });
|
|
3065
|
+
return { ok: true };
|
|
3066
|
+
}
|
|
3067
|
+
const result = await attachedWc.debugger.sendCommand("DOMStorage.getDOMStorageItems", {
|
|
3068
|
+
storageId
|
|
3069
|
+
});
|
|
3070
|
+
for (const [key] of result.entries) {
|
|
3071
|
+
if (!key.startsWith(prefix)) continue;
|
|
3072
|
+
await attachedWc.debugger.sendCommand("DOMStorage.removeDOMStorageItem", {
|
|
3073
|
+
storageId,
|
|
3074
|
+
key
|
|
3075
|
+
});
|
|
3076
|
+
}
|
|
3077
|
+
return { ok: true };
|
|
3078
|
+
} catch (e) {
|
|
3079
|
+
return { ok: false, error: e.message };
|
|
3080
|
+
}
|
|
3081
|
+
}
|
|
3082
|
+
async function clearAll() {
|
|
3083
|
+
await ensureAttached();
|
|
3084
|
+
if (!attachedWc || attachedWc.isDestroyed()) {
|
|
3085
|
+
return { ok: false, error: "simulator not attached" };
|
|
3086
|
+
}
|
|
3087
|
+
const storageId = await getStorageId();
|
|
3088
|
+
if (!storageId) return { ok: false, error: "failed to resolve simulator origin" };
|
|
3089
|
+
try {
|
|
3090
|
+
await attachedWc.debugger.sendCommand("DOMStorage.clear", { storageId });
|
|
3091
|
+
return { ok: true };
|
|
3092
|
+
} catch (e) {
|
|
3093
|
+
return { ok: false, error: e.message };
|
|
3094
|
+
}
|
|
3095
|
+
}
|
|
3096
|
+
async function getSnapshot() {
|
|
3097
|
+
await ensureAttached();
|
|
3098
|
+
if (!attachedWc || attachedWc.isDestroyed()) return [];
|
|
3099
|
+
try {
|
|
3100
|
+
const storageId = await getStorageId();
|
|
3101
|
+
if (!storageId) return [];
|
|
3102
|
+
const result = await attachedWc.debugger.sendCommand("DOMStorage.getDOMStorageItems", {
|
|
3103
|
+
storageId
|
|
3104
|
+
});
|
|
3105
|
+
const prefix = activePrefix();
|
|
3106
|
+
const filtered = prefix ? result.entries.filter(([key]) => key.startsWith(prefix)) : result.entries;
|
|
3107
|
+
return filtered.map(([key, value]) => ({ key, value }));
|
|
3108
|
+
} catch {
|
|
3109
|
+
return [];
|
|
3110
|
+
}
|
|
2374
3111
|
}
|
|
2375
|
-
}
|
|
2376
|
-
function setupSimulatorStorage(host) {
|
|
2377
|
-
hostWc = host;
|
|
2378
3112
|
for (const wc of wcStatic.getAllWebContents()) {
|
|
2379
3113
|
if (isSimulatorWebview(wc)) {
|
|
2380
3114
|
void attachToSim(wc);
|
|
2381
3115
|
break;
|
|
2382
3116
|
}
|
|
2383
3117
|
}
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
3118
|
+
const wcSubs = /* @__PURE__ */ new Map();
|
|
3119
|
+
const onWcCreated = (_event, wc) => {
|
|
3120
|
+
const sub = new DisposableRegistry();
|
|
3121
|
+
wcSubs.set(wc, sub);
|
|
3122
|
+
const onFinishLoad = () => {
|
|
3123
|
+
if (isSimulatorWebview(wc)) void attachToSim(wc);
|
|
3124
|
+
};
|
|
3125
|
+
wc.on("did-finish-load", onFinishLoad);
|
|
3126
|
+
sub.add(() => safeOff(wc, "did-finish-load", onFinishLoad));
|
|
3127
|
+
wc.once("destroyed", () => {
|
|
3128
|
+
void sub.disposeAll().catch(() => {
|
|
3129
|
+
});
|
|
3130
|
+
wcSubs.delete(wc);
|
|
2391
3131
|
});
|
|
3132
|
+
};
|
|
3133
|
+
app8.on("web-contents-created", onWcCreated);
|
|
3134
|
+
registry.add(() => {
|
|
3135
|
+
app8.removeListener("web-contents-created", onWcCreated);
|
|
2392
3136
|
});
|
|
2393
|
-
|
|
3137
|
+
registry.add(async () => {
|
|
3138
|
+
const subs = Array.from(wcSubs.values());
|
|
3139
|
+
wcSubs.clear();
|
|
3140
|
+
for (const sub of subs) {
|
|
3141
|
+
await sub.disposeAll().catch(() => {
|
|
3142
|
+
});
|
|
3143
|
+
}
|
|
3144
|
+
});
|
|
3145
|
+
const ipc = new IpcRegistry(options.senderPolicy);
|
|
3146
|
+
ipc.handle(SimulatorStorageChannel.GetSnapshot, () => getSnapshot());
|
|
3147
|
+
ipc.handle(SimulatorStorageChannel.GetActivePrefix, () => activePrefix() ?? "");
|
|
3148
|
+
ipc.handle(
|
|
3149
|
+
SimulatorStorageChannel.Set,
|
|
3150
|
+
(_event, payload) => setItem(String(payload?.key ?? ""), String(payload?.value ?? ""))
|
|
3151
|
+
);
|
|
3152
|
+
ipc.handle(
|
|
3153
|
+
SimulatorStorageChannel.Remove,
|
|
3154
|
+
(_event, payload) => removeItem(String(payload?.key ?? ""))
|
|
3155
|
+
);
|
|
3156
|
+
ipc.handle(SimulatorStorageChannel.Clear, () => clearScoped());
|
|
3157
|
+
ipc.handle(SimulatorStorageChannel.ClearAll, () => clearAll());
|
|
3158
|
+
ipc.handle(SimulatorElementChannel.Inspect, (_event, sid) => inspectElement(sid));
|
|
3159
|
+
ipc.handle(SimulatorElementChannel.Clear, () => clearElementInspection());
|
|
3160
|
+
registry.add(ipc);
|
|
3161
|
+
registry.add(() => detachFromSim());
|
|
3162
|
+
return registry;
|
|
3163
|
+
}
|
|
3164
|
+
function findSimulatorWebContents() {
|
|
3165
|
+
for (const wc of wcStatic.getAllWebContents()) {
|
|
3166
|
+
if (isSimulatorWebview(wc)) return wc;
|
|
3167
|
+
}
|
|
3168
|
+
return null;
|
|
3169
|
+
}
|
|
3170
|
+
async function inspectElement(sid) {
|
|
3171
|
+
if (!sid) return null;
|
|
3172
|
+
const sim = findSimulatorWebContents();
|
|
3173
|
+
if (!sim) return null;
|
|
3174
|
+
try {
|
|
3175
|
+
const result = await sim.executeJavaScript(
|
|
3176
|
+
`window.__simulatorData && window.__simulatorData.highlightElement ? window.__simulatorData.highlightElement(${JSON.stringify(sid)}) : null`
|
|
3177
|
+
);
|
|
3178
|
+
return result ?? null;
|
|
3179
|
+
} catch (e) {
|
|
3180
|
+
console.warn("[simulator-element] inspect failed:", e.message);
|
|
3181
|
+
return null;
|
|
3182
|
+
}
|
|
3183
|
+
}
|
|
3184
|
+
async function clearElementInspection() {
|
|
3185
|
+
const sim = findSimulatorWebContents();
|
|
3186
|
+
if (!sim) return;
|
|
3187
|
+
try {
|
|
3188
|
+
await sim.executeJavaScript(
|
|
3189
|
+
"window.__simulatorData && window.__simulatorData.unhighlightElement && window.__simulatorData.unhighlightElement()"
|
|
3190
|
+
);
|
|
3191
|
+
} catch {
|
|
3192
|
+
}
|
|
2394
3193
|
}
|
|
2395
3194
|
|
|
2396
3195
|
// src/main/services/update/update-manager.ts
|
|
2397
|
-
import { app as app9,
|
|
3196
|
+
import { app as app9, shell as shell3 } from "electron";
|
|
2398
3197
|
var UpdateManager = class {
|
|
2399
3198
|
checker;
|
|
2400
3199
|
mainWindow;
|
|
@@ -2403,23 +3202,17 @@ var UpdateManager = class {
|
|
|
2403
3202
|
downloadedPath = null;
|
|
2404
3203
|
timer = null;
|
|
2405
3204
|
initialTimer = null;
|
|
3205
|
+
ipc;
|
|
2406
3206
|
constructor(opts) {
|
|
2407
3207
|
this.checker = opts.checker;
|
|
2408
3208
|
this.mainWindow = opts.mainWindow;
|
|
2409
3209
|
this.getCurrentVersion = opts.getCurrentVersion ?? (() => app9.getVersion());
|
|
3210
|
+
this.ipc = new IpcRegistry(opts.senderPolicy);
|
|
2410
3211
|
this.registerIpc();
|
|
2411
3212
|
this.startPeriodicCheck(opts.checkInterval ?? 60 * 60 * 1e3, opts.initialDelay ?? 5e3);
|
|
2412
3213
|
}
|
|
2413
3214
|
registerIpc() {
|
|
2414
|
-
|
|
2415
|
-
return this.check();
|
|
2416
|
-
});
|
|
2417
|
-
ipcMain11.handle("updates:download", async () => {
|
|
2418
|
-
return this.download();
|
|
2419
|
-
});
|
|
2420
|
-
ipcMain11.handle("updates:install", async () => {
|
|
2421
|
-
this.install();
|
|
2422
|
-
});
|
|
3215
|
+
this.ipc.handle(UpdateChannel.Check, async () => this.check()).handle(UpdateChannel.Download, async () => this.download()).handle(UpdateChannel.Install, async () => this.install());
|
|
2423
3216
|
}
|
|
2424
3217
|
async check() {
|
|
2425
3218
|
try {
|
|
@@ -2442,7 +3235,7 @@ var UpdateManager = class {
|
|
|
2442
3235
|
}
|
|
2443
3236
|
try {
|
|
2444
3237
|
const filePath = await this.checker.downloadUpdate(this.latestUpdate, (percent) => {
|
|
2445
|
-
this.mainWindow.webContents.send(
|
|
3238
|
+
this.mainWindow.webContents.send(UpdateChannel.DownloadProgress, { percent });
|
|
2446
3239
|
});
|
|
2447
3240
|
this.downloadedPath = filePath;
|
|
2448
3241
|
return { success: true, filePath };
|
|
@@ -2453,10 +3246,16 @@ var UpdateManager = class {
|
|
|
2453
3246
|
}
|
|
2454
3247
|
install() {
|
|
2455
3248
|
if (this.downloadedPath) {
|
|
2456
|
-
|
|
3249
|
+
shell3.openPath(this.downloadedPath);
|
|
2457
3250
|
app9.quit();
|
|
2458
3251
|
}
|
|
2459
3252
|
}
|
|
3253
|
+
/**
|
|
3254
|
+
* Tear down timers + IPC handlers. Returns a Promise so callers that need
|
|
3255
|
+
* a settled cleanup (e.g. workbench registry shutdown, the unit-test
|
|
3256
|
+
* lifecycle suite) can await it; calling without await is also safe since
|
|
3257
|
+
* the timer clears + handler removals are scheduled synchronously.
|
|
3258
|
+
*/
|
|
2460
3259
|
dispose() {
|
|
2461
3260
|
if (this.timer) {
|
|
2462
3261
|
clearInterval(this.timer);
|
|
@@ -2466,9 +3265,7 @@ var UpdateManager = class {
|
|
|
2466
3265
|
clearTimeout(this.initialTimer);
|
|
2467
3266
|
this.initialTimer = null;
|
|
2468
3267
|
}
|
|
2469
|
-
|
|
2470
|
-
ipcMain11.removeHandler("updates:download");
|
|
2471
|
-
ipcMain11.removeHandler("updates:install");
|
|
3268
|
+
return this.ipc.dispose();
|
|
2472
3269
|
}
|
|
2473
3270
|
startPeriodicCheck(interval, initialDelay) {
|
|
2474
3271
|
this.initialTimer = setTimeout(() => void this.checkAndNotify(), initialDelay);
|
|
@@ -2477,7 +3274,7 @@ var UpdateManager = class {
|
|
|
2477
3274
|
async checkAndNotify() {
|
|
2478
3275
|
const result = await this.check();
|
|
2479
3276
|
if (result.hasUpdate && result.info) {
|
|
2480
|
-
this.mainWindow.webContents.send(
|
|
3277
|
+
this.mainWindow.webContents.send(UpdateChannel.Available, result.info);
|
|
2481
3278
|
}
|
|
2482
3279
|
}
|
|
2483
3280
|
};
|
|
@@ -2493,16 +3290,12 @@ var DEFAULT_MODULES = {
|
|
|
2493
3290
|
popover: true,
|
|
2494
3291
|
settings: true
|
|
2495
3292
|
};
|
|
2496
|
-
var
|
|
2497
|
-
projects:
|
|
2498
|
-
session:
|
|
2499
|
-
simulator:
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
registerToolbarIpc(ctx);
|
|
2503
|
-
},
|
|
2504
|
-
popover: registerPopoverIpc,
|
|
2505
|
-
settings: registerSettingsIpc
|
|
3293
|
+
var BUILTIN_MODULES = {
|
|
3294
|
+
projects: projectsModule,
|
|
3295
|
+
session: sessionModule,
|
|
3296
|
+
simulator: simulatorModule,
|
|
3297
|
+
popover: popoverModule,
|
|
3298
|
+
settings: settingsModule
|
|
2506
3299
|
};
|
|
2507
3300
|
function parseAutoArgs() {
|
|
2508
3301
|
const argv = process.argv;
|
|
@@ -2527,18 +3320,25 @@ function resolveModules(config) {
|
|
|
2527
3320
|
...config.modules
|
|
2528
3321
|
};
|
|
2529
3322
|
}
|
|
2530
|
-
async function disposeContext(ctx
|
|
2531
|
-
updateManager?.dispose();
|
|
3323
|
+
async function disposeContext(ctx) {
|
|
2532
3324
|
await ctx.workspace.closeProject();
|
|
3325
|
+
await ctx.registry.dispose().catch((err) => {
|
|
3326
|
+
console.warn("[workbench] dispose registry encountered errors:", err);
|
|
3327
|
+
});
|
|
2533
3328
|
}
|
|
2534
3329
|
function createConfiguredMainWindow(config, rendererDir2) {
|
|
2535
3330
|
const mainWindow = createMainWindow({
|
|
2536
3331
|
title: config.appName ?? "Dimina DevTools",
|
|
2537
|
-
indexHtml:
|
|
3332
|
+
indexHtml: path8.join(rendererDir2, "entries/main/index.html"),
|
|
2538
3333
|
width: config.window?.width,
|
|
2539
3334
|
height: config.window?.height,
|
|
2540
3335
|
minWidth: config.window?.minWidth,
|
|
2541
|
-
minHeight: config.window?.minHeight
|
|
3336
|
+
minHeight: config.window?.minHeight,
|
|
3337
|
+
// P1: pass the same preload path the workbench context stores on
|
|
3338
|
+
// ctx.preloadPath so hosts that ship a custom simulator preload are the
|
|
3339
|
+
// ones registered on the persist:simulator session — otherwise the
|
|
3340
|
+
// backstop wouldn't be the host's script.
|
|
3341
|
+
simulatorPreloadPath: config.preloadPath ?? defaultPreloadPath
|
|
2542
3342
|
});
|
|
2543
3343
|
if (config.icon) {
|
|
2544
3344
|
const icon = nativeImage.createFromPath(config.icon);
|
|
@@ -2562,7 +3362,7 @@ function createContext(config, mainWindow, rendererDir2) {
|
|
|
2562
3362
|
function registerBuiltinModules(config, context) {
|
|
2563
3363
|
const modules = resolveModules(config);
|
|
2564
3364
|
Object.keys(modules).forEach((moduleId) => {
|
|
2565
|
-
if (modules[moduleId])
|
|
3365
|
+
if (modules[moduleId]) context.registry.add(BUILTIN_MODULES[moduleId].setup(context));
|
|
2566
3366
|
});
|
|
2567
3367
|
}
|
|
2568
3368
|
function installMenu(config, mainWindow, context) {
|
|
@@ -2577,19 +3377,20 @@ async function setupAutomation(instance) {
|
|
|
2577
3377
|
if (autoArgs.auto) {
|
|
2578
3378
|
const server = await startAutomationServer(instance.context, autoArgs.autoPort);
|
|
2579
3379
|
instance.automationServer = server;
|
|
3380
|
+
instance.context.registry.add(() => server.close());
|
|
2580
3381
|
console.log(`[automation] listening on ws://127.0.0.1:${server.port}`);
|
|
2581
3382
|
}
|
|
2582
3383
|
}
|
|
2583
3384
|
function setupMcp() {
|
|
2584
3385
|
const settings = loadWorkbenchSettings();
|
|
2585
|
-
if (!settings.mcp.enabled) return;
|
|
3386
|
+
if (!settings.mcp.enabled) return null;
|
|
2586
3387
|
const cdpPortSwitch = app11.commandLine.getSwitchValue("remote-debugging-port");
|
|
2587
3388
|
const cdpPort2 = cdpPortSwitch ? parseInt(cdpPortSwitch, 10) : settings.cdp.port;
|
|
2588
|
-
startMcpServer(cdpPort2, settings.mcp.port);
|
|
3389
|
+
return startMcpServer(cdpPort2, settings.mcp.port);
|
|
2589
3390
|
}
|
|
2590
3391
|
function wireAppWindowEvents(config, instance) {
|
|
2591
3392
|
const { mainWindow, context } = instance;
|
|
2592
|
-
wireMainWindowEvents(mainWindow, {
|
|
3393
|
+
return wireMainWindowEvents(mainWindow, {
|
|
2593
3394
|
context,
|
|
2594
3395
|
onResize: () => context.views.repositionAll(),
|
|
2595
3396
|
onClose: async (e) => {
|
|
@@ -2598,23 +3399,32 @@ function wireAppWindowEvents(config, instance) {
|
|
|
2598
3399
|
if (config.onBeforeClose) {
|
|
2599
3400
|
await config.onBeforeClose(instance);
|
|
2600
3401
|
}
|
|
2601
|
-
await
|
|
3402
|
+
await context.workspace.closeProject();
|
|
2602
3403
|
context.notify.windowNavigateBack();
|
|
2603
3404
|
}
|
|
2604
3405
|
});
|
|
2605
3406
|
}
|
|
2606
3407
|
function enableDevRendererAutoReload(rendererDir2) {
|
|
2607
|
-
if (
|
|
2608
|
-
|
|
2609
|
-
fs4.watch(rendererDir2, { recursive: true }, () => {
|
|
2610
|
-
if (reloadTimer) clearTimeout(reloadTimer);
|
|
2611
|
-
reloadTimer = setTimeout(() => {
|
|
2612
|
-
for (const win of BrowserWindow3.getAllWindows()) {
|
|
2613
|
-
win.webContents.reload();
|
|
2614
|
-
}
|
|
2615
|
-
}, 300);
|
|
3408
|
+
if (app11.isPackaged) {
|
|
3409
|
+
return toDisposable(() => {
|
|
2616
3410
|
});
|
|
2617
3411
|
}
|
|
3412
|
+
let reloadTimer = null;
|
|
3413
|
+
const watcher = fs5.watch(rendererDir2, { recursive: true }, () => {
|
|
3414
|
+
if (reloadTimer) clearTimeout(reloadTimer);
|
|
3415
|
+
reloadTimer = setTimeout(() => {
|
|
3416
|
+
for (const win of BrowserWindow3.getAllWindows()) {
|
|
3417
|
+
win.webContents.reload();
|
|
3418
|
+
}
|
|
3419
|
+
}, 300);
|
|
3420
|
+
});
|
|
3421
|
+
return toDisposable(() => {
|
|
3422
|
+
if (reloadTimer) {
|
|
3423
|
+
clearTimeout(reloadTimer);
|
|
3424
|
+
reloadTimer = null;
|
|
3425
|
+
}
|
|
3426
|
+
watcher.close();
|
|
3427
|
+
});
|
|
2618
3428
|
}
|
|
2619
3429
|
function createWorkbenchApp(config = {}) {
|
|
2620
3430
|
let setupPromise = null;
|
|
@@ -2627,13 +3437,13 @@ function createWorkbenchApp(config = {}) {
|
|
|
2627
3437
|
const rendererDir2 = config.rendererDir ?? rendererDir;
|
|
2628
3438
|
const mainWindow = createConfiguredMainWindow(config, rendererDir2);
|
|
2629
3439
|
const context = createContext(config, mainWindow, rendererDir2);
|
|
2630
|
-
registerAppIpc(context);
|
|
3440
|
+
context.registry.add(registerAppIpc(context));
|
|
2631
3441
|
registerBuiltinModules(config, context);
|
|
2632
3442
|
installMenu(config, mainWindow, context);
|
|
2633
3443
|
const instance = {
|
|
2634
3444
|
mainWindow,
|
|
2635
3445
|
context,
|
|
2636
|
-
dispose: () => disposeContext(context
|
|
3446
|
+
dispose: () => disposeContext(context)
|
|
2637
3447
|
};
|
|
2638
3448
|
if (config.onSetup) {
|
|
2639
3449
|
await config.onSetup(instance);
|
|
@@ -2646,22 +3456,37 @@ function createWorkbenchApp(config = {}) {
|
|
|
2646
3456
|
initialDelay: config.updateOptions?.initialDelay,
|
|
2647
3457
|
getCurrentVersion: config.updateOptions?.getCurrentVersion
|
|
2648
3458
|
});
|
|
3459
|
+
context.registry.add(() => instance.updateManager.dispose());
|
|
2649
3460
|
}
|
|
2650
3461
|
await setupAutomation(instance);
|
|
2651
|
-
setupMcp();
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
3462
|
+
const mcp = setupMcp();
|
|
3463
|
+
if (mcp) context.registry.add(mcp);
|
|
3464
|
+
context.registry.add(setupSimulatorStorage(mainWindow.webContents, {
|
|
3465
|
+
senderPolicy: context.senderPolicy,
|
|
3466
|
+
// Per-project filter for the simulator-storage panel: the simulator
|
|
3467
|
+
// uses a fixed `persist:simulator` partition + a fixed simulator.html
|
|
3468
|
+
// origin, so localStorage is shared across every project that has
|
|
3469
|
+
// ever opened. The dimina runtime isolates writes with `${appId}_`
|
|
3470
|
+
// prefixes; this callback lets the storage panel filter the CDP
|
|
3471
|
+
// snapshot/event stream to the active appId.
|
|
3472
|
+
getActiveAppId: () => {
|
|
3473
|
+
const session2 = context.workspace.getSession();
|
|
3474
|
+
const appInfo = session2?.appInfo;
|
|
3475
|
+
return appInfo?.appId ?? null;
|
|
3476
|
+
}
|
|
3477
|
+
}));
|
|
3478
|
+
context.registry.add(wireAppWindowEvents(config, instance));
|
|
3479
|
+
context.registry.add(enableDevRendererAutoReload(rendererDir2));
|
|
2655
3480
|
return instance;
|
|
2656
3481
|
});
|
|
2657
3482
|
return setupPromise;
|
|
2658
3483
|
}
|
|
2659
3484
|
function start() {
|
|
2660
|
-
void setup();
|
|
2661
3485
|
if (!appEventsRegistered) {
|
|
2662
3486
|
appEventsRegistered = true;
|
|
2663
3487
|
registerAppLifecycle();
|
|
2664
3488
|
}
|
|
3489
|
+
return setup().then(() => void 0);
|
|
2665
3490
|
}
|
|
2666
3491
|
return {
|
|
2667
3492
|
setup,
|
|
@@ -2671,7 +3496,7 @@ function createWorkbenchApp(config = {}) {
|
|
|
2671
3496
|
|
|
2672
3497
|
// src/main/windows/settings-window/create.ts
|
|
2673
3498
|
import { BrowserWindow as BrowserWindow4 } from "electron";
|
|
2674
|
-
import
|
|
3499
|
+
import path9 from "path";
|
|
2675
3500
|
async function createSettingsWindow(parent, rendererDir2) {
|
|
2676
3501
|
const win = new BrowserWindow4({
|
|
2677
3502
|
width: 420,
|
|
@@ -2681,9 +3506,15 @@ async function createSettingsWindow(parent, rendererDir2) {
|
|
|
2681
3506
|
parent: parent ?? void 0,
|
|
2682
3507
|
title: "\u5F00\u53D1\u5DE5\u5177\u8BBE\u7F6E",
|
|
2683
3508
|
backgroundColor: themeBg(),
|
|
2684
|
-
webPreferences: {
|
|
3509
|
+
webPreferences: {
|
|
3510
|
+
nodeIntegration: false,
|
|
3511
|
+
contextIsolation: true,
|
|
3512
|
+
sandbox: false,
|
|
3513
|
+
preload: mainPreloadPath
|
|
3514
|
+
}
|
|
2685
3515
|
});
|
|
2686
|
-
|
|
3516
|
+
applyNavigationHardening(win.webContents, rendererDir2);
|
|
3517
|
+
await win.loadFile(path9.join(rendererDir2, "entries/workbench-settings/index.html"));
|
|
2687
3518
|
return win;
|
|
2688
3519
|
}
|
|
2689
3520
|
|
|
@@ -2696,13 +3527,16 @@ function wireSettingsWindowEvents(win, onClosed) {
|
|
|
2696
3527
|
|
|
2697
3528
|
// src/main/app/launch.ts
|
|
2698
3529
|
function launch(config = {}) {
|
|
2699
|
-
createWorkbenchApp(config).start();
|
|
3530
|
+
return createWorkbenchApp(config).start();
|
|
2700
3531
|
}
|
|
2701
3532
|
async function openSettingsWindow(ctx) {
|
|
2702
3533
|
if (!ctx.workbenchSettingsWindow || ctx.workbenchSettingsWindow.isDestroyed()) {
|
|
2703
|
-
|
|
2704
|
-
|
|
3534
|
+
const win = await createSettingsWindow(ctx.mainWindow, ctx.rendererDir);
|
|
3535
|
+
ctx.workbenchSettingsWindow = win;
|
|
3536
|
+
ctx.windows.setSettingsWindow(win);
|
|
3537
|
+
wireSettingsWindowEvents(win, () => {
|
|
2705
3538
|
ctx.workbenchSettingsWindow = null;
|
|
3539
|
+
ctx.windows.setSettingsWindow(null);
|
|
2706
3540
|
});
|
|
2707
3541
|
}
|
|
2708
3542
|
ctx.workbenchSettingsWindow.show();
|