@dimina-kit/devtools 0.4.0-dev.20260831134112 → 0.4.0-dev.20260907055341
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 +52 -729
- package/dist/main/app/app.d.ts +27 -7
- package/dist/main/app/app.js +285 -681
- package/dist/main/app/editor-view.d.ts +21 -0
- package/dist/main/app/editor-view.js +71 -0
- package/dist/main/app/global-mirrors.d.ts +23 -0
- package/dist/main/app/global-mirrors.js +37 -0
- package/dist/main/app/host-sidebar-default.d.ts +19 -0
- package/dist/main/app/host-sidebar-default.js +44 -0
- package/dist/main/app/menu-setup.d.ts +13 -0
- package/dist/main/app/menu-setup.js +49 -0
- package/dist/main/app/open-project-ipc.d.ts +13 -0
- package/dist/main/app/open-project-ipc.js +21 -0
- package/dist/main/app/project-list-surface.d.ts +31 -0
- package/dist/main/app/project-list-surface.js +20 -0
- package/dist/main/app/project-window.d.ts +36 -0
- package/dist/main/app/project-window.js +93 -0
- package/dist/main/app/servers.d.ts +17 -0
- package/dist/main/app/servers.js +60 -0
- package/dist/main/app/ui-extension-targets.d.ts +42 -0
- package/dist/main/app/ui-extension-targets.js +101 -0
- package/dist/main/app/window-close-reveal.harness.d.ts +34 -0
- package/dist/main/app/window-close-reveal.harness.js +65 -0
- package/dist/main/app/window-events.d.ts +15 -0
- package/dist/main/app/window-events.js +45 -0
- package/dist/main/app/window-runtime-services.d.ts +41 -0
- package/dist/main/app/window-runtime-services.js +178 -0
- package/dist/main/app/workbench-modules.d.ts +24 -0
- package/dist/main/app/workbench-modules.js +51 -0
- package/dist/main/app/workbench-window.d.ts +85 -0
- package/dist/main/app/workbench-window.js +310 -0
- package/dist/main/index.bundle.js +10669 -9096
- package/dist/main/ipc/app.d.ts +4 -1
- package/dist/main/ipc/app.js +4 -3
- package/dist/main/ipc/device-picker.d.ts +16 -0
- package/dist/main/ipc/device-picker.js +27 -0
- package/dist/main/ipc/index.d.ts +1 -0
- package/dist/main/ipc/index.js +1 -0
- package/dist/main/ipc/internal-devtools.d.ts +2 -1
- package/dist/main/ipc/internal-devtools.js +4 -3
- package/dist/main/ipc/popover.d.ts +4 -1
- package/dist/main/ipc/popover.js +25 -9
- package/dist/main/ipc/project-create.d.ts +2 -1
- package/dist/main/ipc/project-create.js +6 -5
- package/dist/main/ipc/project-fs.d.ts +3 -1
- package/dist/main/ipc/project-fs.js +17 -17
- package/dist/main/ipc/projects.d.ts +3 -3
- package/dist/main/ipc/projects.js +13 -12
- package/dist/main/ipc/session.d.ts +4 -1
- package/dist/main/ipc/session.js +16 -11
- package/dist/main/ipc/settings.d.ts +4 -1
- package/dist/main/ipc/settings.js +12 -19
- package/dist/main/ipc/simulator-module.d.ts +5 -0
- package/dist/main/ipc/simulator-module.js +9 -5
- package/dist/main/ipc/simulator.d.ts +4 -1
- package/dist/main/ipc/simulator.js +12 -18
- package/dist/main/ipc/tooltip.d.ts +2 -1
- package/dist/main/ipc/tooltip.js +8 -7
- package/dist/main/ipc/views.d.ts +4 -1
- package/dist/main/ipc/views.js +20 -9
- package/dist/main/runtime/devtools-backend-before-quit.harness.d.ts +2 -20
- package/dist/main/runtime/devtools-backend-before-quit.harness.js +14 -283
- package/dist/main/runtime/devtools-backend.js +14 -3
- package/dist/main/runtime/devtools-runtime-mock.harness.d.ts +21 -0
- package/dist/main/runtime/devtools-runtime-mock.harness.js +313 -0
- package/dist/main/services/app-services.d.ts +62 -0
- package/dist/main/services/app-services.js +64 -0
- package/dist/main/services/automation/connection-target.d.ts +36 -0
- package/dist/main/services/automation/connection-target.js +29 -0
- package/dist/main/services/automation/console-bridge.d.ts +28 -0
- package/dist/main/services/automation/console-bridge.js +91 -0
- package/dist/main/services/automation/handlers/app.js +4 -4
- package/dist/main/services/automation/handlers/element.js +55 -21
- package/dist/main/services/automation/index.d.ts +12 -1
- package/dist/main/services/automation/index.js +54 -133
- package/dist/main/services/default-adapter.js +1 -1
- package/dist/main/services/fs-bridge-protocol.d.ts +61 -0
- package/dist/main/services/fs-bridge-protocol.js +34 -0
- package/dist/main/services/fs-watch-sse.d.ts +8 -1
- package/dist/main/services/fs-watch-sse.js +19 -5
- package/dist/main/services/mcp/connection-owner.d.ts +38 -0
- package/dist/main/services/mcp/connection-owner.js +79 -0
- package/dist/main/services/mcp/index.d.ts +3 -1
- package/dist/main/services/mcp/index.js +4 -3
- package/dist/main/services/mcp/opened-project.d.ts +88 -0
- package/dist/main/services/mcp/opened-project.js +60 -0
- package/dist/main/services/mcp/target-manager.d.ts +71 -23
- package/dist/main/services/mcp/target-manager.js +269 -142
- package/dist/main/services/mcp/target-selection.d.ts +47 -0
- package/dist/main/services/mcp/target-selection.js +71 -0
- package/dist/main/services/mcp/tools/context-tools.js +20 -5
- package/dist/main/services/mcp/tools/project-tools.d.ts +29 -6
- package/dist/main/services/mcp/tools/project-tools.js +37 -25
- package/dist/main/services/module.d.ts +13 -5
- package/dist/main/services/notifications/renderer-notifier.d.ts +28 -4
- package/dist/main/services/notifications/renderer-notifier.js +15 -3
- package/dist/main/services/projects/local-provider.js +2 -0
- package/dist/main/services/projects/project-repository.d.ts +31 -1
- package/dist/main/services/projects/project-repository.js +144 -20
- package/dist/main/services/projects/types.d.ts +31 -8
- package/dist/main/services/safe-area/index.d.ts +19 -5
- package/dist/main/services/safe-area/index.js +38 -13
- package/dist/main/services/simulator/ui-extensions.d.ts +8 -0
- package/dist/main/services/simulator/ui-extensions.js +16 -6
- package/dist/main/services/simulator-storage/index.d.ts +12 -1
- package/dist/main/services/simulator-storage/index.js +22 -7
- package/dist/main/services/simulator-storage/window-scope.d.ts +20 -0
- package/dist/main/services/simulator-storage/window-scope.js +20 -0
- package/dist/main/services/views/host-slot-port-channel.d.ts +20 -3
- package/dist/main/services/views/host-slot-port-channel.js +33 -5
- package/dist/main/services/views/managed-web-contents-view.js +21 -1
- package/dist/main/services/views/native-simulator-view.js +13 -16
- package/dist/main/services/views/overlay-panels-view.d.ts +13 -0
- package/dist/main/services/views/overlay-panels-view.js +31 -0
- package/dist/main/services/views/view-manager.d.ts +1 -1
- package/dist/main/services/views/view-manager.js +3 -0
- package/dist/main/services/window-contexts/context-router.d.ts +36 -0
- package/dist/main/services/window-contexts/context-router.js +55 -0
- package/dist/main/services/workbench-coi-host.d.ts +52 -0
- package/dist/main/services/workbench-coi-host.js +227 -0
- package/dist/main/services/workbench-coi-server.js +75 -133
- package/dist/main/services/workbench-coi-shutdown.d.ts +40 -0
- package/dist/main/services/workbench-coi-shutdown.js +69 -0
- package/dist/main/services/workbench-coi-static.d.ts +23 -0
- package/dist/main/services/workbench-coi-static.js +87 -0
- package/dist/main/services/workbench-context.d.ts +27 -3
- package/dist/main/services/workbench-context.js +10 -5
- package/dist/main/services/workspace/compile-mode-adapter.d.ts +18 -0
- package/dist/main/services/workspace/compile-mode-adapter.js +57 -0
- package/dist/main/services/workspace/compile-mode-store.d.ts +25 -0
- package/dist/main/services/workspace/compile-mode-store.js +71 -0
- package/dist/main/services/workspace/workspace-compile-modes.d.ts +59 -0
- package/dist/main/services/workspace/workspace-compile-modes.js +93 -0
- package/dist/main/services/workspace/workspace-referer.d.ts +17 -0
- package/dist/main/services/workspace/workspace-referer.js +26 -0
- package/dist/main/services/workspace/workspace-service.d.ts +4 -0
- package/dist/main/services/workspace/workspace-service.js +51 -84
- package/dist/main/services/workspace/workspace-thumbnails.d.ts +22 -0
- package/dist/main/services/workspace/workspace-thumbnails.js +67 -0
- package/dist/main/utils/ipc-context-source.d.ts +40 -0
- package/dist/main/utils/ipc-context-source.js +23 -0
- package/dist/main/utils/ipc-registry.d.ts +42 -36
- package/dist/main/utils/ipc-registry.js +117 -50
- package/dist/main/utils/sender-policy.d.ts +9 -0
- package/dist/main/utils/sender-policy.js +26 -3
- package/dist/main/utils/theme.d.ts +3 -2
- package/dist/main/utils/theme.js +3 -2
- package/dist/main/windows/main-window/create.d.ts +16 -0
- package/dist/main/windows/main-window/create.js +19 -11
- package/dist/main/windows/main-window/events.d.ts +1 -1
- package/dist/main/windows/main-window/events.js +26 -13
- package/dist/main/windows/main-window/index.d.ts +1 -1
- package/dist/main/windows/main-window/index.js +1 -1
- package/dist/native-host/common/common.js +94 -73
- package/dist/native-host/render/render.js +4079 -3171
- package/dist/native-host/service/service.js +2 -2
- package/dist/preload/runtime/native-host.d.ts +4 -0
- package/dist/preload/runtime/temp-files.js +9 -2
- package/dist/preload/runtime/wait-for-slot-root.d.ts +7 -4
- package/dist/preload/runtime/wait-for-slot-root.js +36 -8
- package/dist/preload/windows/host-dialog-runtime.cjs +10 -3
- package/dist/preload/windows/host-dialog-runtime.cjs.map +2 -2
- package/dist/preload/windows/host-sidebar-runtime.cjs +10 -3
- package/dist/preload/windows/host-sidebar-runtime.cjs.map +2 -2
- package/dist/preload/windows/host-toolbar-runtime.cjs +10 -3
- package/dist/preload/windows/host-toolbar-runtime.cjs.map +2 -2
- package/dist/preload/windows/main.cjs +181 -4
- package/dist/preload/windows/main.cjs.map +4 -4
- package/dist/preload/windows/simulator.cjs +10 -0
- package/dist/preload/windows/simulator.cjs.map +2 -2
- package/dist/preload/windows/simulator.js +10 -0
- package/dist/renderer/assets/button-CB2MWjHY.js +2 -0
- package/dist/renderer/assets/constants-CkoGPQTS.js +2 -0
- package/dist/renderer/assets/constants-zQZ2-y21.js +2 -0
- package/dist/renderer/assets/{createLucideIcon-Bqi8hpdi.js → createLucideIcon-cZ9FlZZw.js} +2 -2
- package/dist/renderer/assets/devicePicker-H2eIO4e1.js +2 -0
- package/dist/renderer/assets/dialog-pHzEA8Vx.js +46 -0
- package/dist/renderer/assets/dist-B5HADirS.js +2 -0
- package/dist/renderer/assets/{dist-DKWdE1TK.js → dist-DIFlRMKe.js} +2 -2
- package/dist/renderer/assets/hostSidebarDefault-DRWh6OCt.js +2 -0
- package/dist/renderer/assets/index-CEL_XFge.js +2 -0
- package/dist/renderer/assets/{input-Ct3alvkq.js → input-CAObw95L.js} +2 -2
- package/dist/renderer/assets/ipc-channels-overlays-gIPUFnqc.js +2 -0
- package/dist/renderer/assets/jsx-runtime-DICEQH_0.css +1 -0
- package/dist/renderer/assets/{jsx-runtime-DGLHmmOq.js → jsx-runtime-DIw5wnYl.js} +1 -1
- package/dist/renderer/assets/plus-BQ9u5EbL.js +2 -0
- package/dist/renderer/assets/popover-Cw7G2Ctp.js +2 -0
- package/dist/renderer/assets/presets-DMZOb9ay.js +2 -0
- package/dist/renderer/assets/project-api-YTOr_Yvo.js +2 -0
- package/dist/renderer/assets/{projectCreateDialog-Bbjz75bP.js → projectCreateDialog-BmLqiYxn.js} +2 -2
- package/dist/renderer/assets/search-BMvuYF48.js +2 -0
- package/dist/renderer/assets/select-nFP95TxM.js +2 -0
- package/dist/renderer/assets/settings-CnpVfSWt.js +2 -0
- package/dist/renderer/assets/settings-api-Ccsf-Nsj.js +2 -0
- package/dist/renderer/assets/settings-tab-bar-CAzrv32m.js +2 -0
- package/dist/renderer/assets/smartphone-Bb2GdIKy.js +2 -0
- package/dist/renderer/assets/tabs-CPKN3Mmq.js +2 -0
- package/dist/renderer/assets/{tooltip-B_-_YVbw.js → tooltip-D6AxXRk5.js} +2 -2
- package/dist/renderer/assets/types-Bh0hA7El.js +2 -0
- package/dist/renderer/assets/updateDialog-CwndJ0Bl.js +2 -0
- package/dist/renderer/assets/{utils-kfQov6Pa.js → utils-sEB5OZEQ.js} +2 -2
- package/dist/renderer/assets/view-api-B-2zPBR5.js +2 -0
- package/dist/renderer/assets/view-ids-BfaDVV5P.js +2 -0
- package/dist/renderer/assets/workbench-BLJ0wKsg.js +5 -0
- package/dist/renderer/assets/{workbenchSettings-CV4LVA9b.js → workbenchSettings-YD0Ctbm_.js} +3 -3
- package/dist/renderer/entries/device-picker/index.html +28 -0
- package/dist/renderer/entries/host-sidebar-default/index.html +6 -5
- package/dist/renderer/entries/main/index.html +16 -17
- package/dist/renderer/entries/popover/index.html +16 -10
- package/dist/renderer/entries/project-create-dialog/index.html +12 -12
- package/dist/renderer/entries/settings/index.html +10 -10
- package/dist/renderer/entries/tooltip/index.html +5 -5
- package/dist/renderer/entries/update-dialog/index.html +10 -10
- package/dist/renderer/entries/workbench/index.html +49 -0
- package/dist/renderer/entries/workbench-settings/index.html +12 -11
- package/dist/service-host/host-env-update.cjs +23 -0
- package/dist/service-host/preload.cjs +24 -49
- package/dist/service-host/service-message-queue.cjs +71 -0
- package/dist/service-host/sync-impls/system-info.js +31 -9
- package/dist/shared/compile-mode-state.d.ts +73 -0
- package/dist/shared/compile-mode-state.js +100 -0
- package/dist/shared/compile-modes.d.ts +152 -0
- package/dist/shared/compile-modes.js +237 -0
- package/dist/shared/ipc-channels-overlays.d.ts +8 -2
- package/dist/shared/ipc-channels-overlays.js +19 -2
- package/dist/shared/ipc-channels.d.ts +5 -10
- package/dist/shared/ipc-channels.js +17 -14
- package/dist/shared/ipc-schemas.d.ts +76 -24
- package/dist/shared/ipc-schemas.js +55 -10
- package/dist/shared/project-window-types.d.ts +42 -0
- package/dist/shared/project-window-types.js +2 -0
- package/dist/shared/types.d.ts +43 -17
- package/dist/shared/view-ids.d.ts +1 -0
- package/dist/shared/view-ids.js +3 -1
- package/dist/simulator/assets/bridge-channels-B3JAmRfl.js +2 -0
- package/dist/simulator/assets/device-shell-ATEhHV2_.css +1 -0
- package/dist/simulator/assets/device-shell-pxnZZp10.js +431 -0
- package/dist/simulator/assets/simulator-Dwp7lnvu.js +10 -0
- package/dist/simulator/assets/simulator-mini-app-DFo7fhi5.js +2 -0
- package/dist/simulator/assets/simulator-ui-B2ddJB1R.js +2 -0
- package/dist/simulator/simulator.html +3 -3
- package/dist/simulator/temp-files.d.ts +6 -0
- package/dist/simulator/temp-files.js +46 -4
- package/dist/simulator/types.d.ts +7 -0
- package/dist/vscode-workbench/assets/__vite-browser-external-JIkWewFf.js +1 -0
- package/dist/vscode-workbench/assets/{dist-CMfmHflW.js → dist-CXG-u1VB.js} +3 -3
- package/dist/vscode-workbench/assets/{iconv-lite-umd-Bx8CgaZq.js → iconv-lite-umd-Dxx9Qyb4.js} +1 -1
- package/dist/vscode-workbench/assets/{index-CdG6YWhW.js → index-6VJMsaWj.js} +460 -460
- package/dist/vscode-workbench/assets/{jschardet-M0qgd2lN.js → jschardet-Ba3D16vt.js} +1 -1
- package/dist/vscode-workbench/index.html +1 -1
- package/package.json +11 -8
- package/dist/renderer/assets/button-D5Q2wkXq.js +0 -2
- package/dist/renderer/assets/constants-D7DfVqMp.js +0 -2
- package/dist/renderer/assets/constants-D8zsejFq.js +0 -2
- package/dist/renderer/assets/dialog-e1TecTOY.js +0 -46
- package/dist/renderer/assets/hostSidebarDefault-B3yLfy8j.js +0 -2
- package/dist/renderer/assets/index-CsPD68N_.js +0 -5
- package/dist/renderer/assets/ipc-channels-overlays-LsDzGAtV.js +0 -2
- package/dist/renderer/assets/jsx-runtime-2vXHouwr.css +0 -1
- package/dist/renderer/assets/popover-Dix5cm_b.js +0 -2
- package/dist/renderer/assets/project-api-k7Oq9iaq.js +0 -2
- package/dist/renderer/assets/select-acGb0AmJ.js +0 -2
- package/dist/renderer/assets/settings-CQrTMr43.js +0 -2
- package/dist/renderer/assets/settings-api-CrUQ9rYV.js +0 -2
- package/dist/renderer/assets/settings-tab-bar-Cw1kVIf2.js +0 -2
- package/dist/renderer/assets/types-CsEKtFyr.js +0 -2
- package/dist/renderer/assets/updateDialog-NsF8223A.js +0 -2
- package/dist/renderer/assets/view-api-CLn3rcQE.js +0 -2
- package/dist/simulator/assets/bridge-channels-zhsumfky.js +0 -2
- package/dist/simulator/assets/device-shell-CmtM1QxP.js +0 -2
- package/dist/simulator/assets/device-shell-iFZo1igL.css +0 -1
- package/dist/simulator/assets/simulator-CIobn3Mh.js +0 -10
- package/dist/simulator/assets/simulator-mini-app-CRe6n9br.js +0 -2
- package/dist/simulator/assets/simulator-ui-C_cP602X.js +0 -2
- package/dist/vscode-workbench/assets/__vite-browser-external-Bc1vizTf.js +0 -1
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import { toDisposable } from '@dimina-kit/electron-deck/main';
|
|
3
|
+
import { createInternalDevtoolsWindow } from '../windows/internal-devtools-window/index.js';
|
|
4
|
+
import { revealMainWindow, wireMainWindowEvents } from '../windows/main-window/index.js';
|
|
5
|
+
import { isAppQuitting } from './lifecycle.js';
|
|
6
|
+
import { installGlobalMirrors } from './global-mirrors.js';
|
|
7
|
+
import { setupEditorView } from './editor-view.js';
|
|
8
|
+
import { createActiveAppIdResolver, setupWindowRuntimeServices } from './window-runtime-services.js';
|
|
9
|
+
import { createWorkbenchWindow } from './project-window.js';
|
|
10
|
+
/**
|
|
11
|
+
* Close semantics for a workbench window. Unlike the old single-window app —
|
|
12
|
+
* where closing meant "return this window to the project list" — closing a
|
|
13
|
+
* workbench window means the window itself goes away, so teardown must finish
|
|
14
|
+
* BEFORE the window is destroyed.
|
|
15
|
+
*
|
|
16
|
+
* Three guards, each covering a failure this app has actually shipped:
|
|
17
|
+
*
|
|
18
|
+
* 1. A real application quit (⌘Q / menu Quit / app.quit()) fires `before-quit`
|
|
19
|
+
* first. Let it through: converting a quit into a project close swallows the
|
|
20
|
+
* quit and the app can never exit with a project open.
|
|
21
|
+
* 2. A close arriving while teardown is already in flight (the user
|
|
22
|
+
* rapid-double-clicked) MUST keep the window. This runs BEFORE any
|
|
23
|
+
* session check on purpose: `closeProject()` → `disposeSession()`
|
|
24
|
+
* synchronously nulls the active session before it finishes awaiting
|
|
25
|
+
* `session.close()`, so a session-presence check would already read false
|
|
26
|
+
* by the time the second close arrives, fall through with no
|
|
27
|
+
* `preventDefault()`, and let Chromium destroy the window out from under a
|
|
28
|
+
* live teardown.
|
|
29
|
+
* 3. Teardown is UNCONDITIONAL — deliberately not gated on
|
|
30
|
+
* `hasActiveSession()`. A failed open (invalid/non-existent project) never
|
|
31
|
+
* creates a session, yet the window still owns views, an editor server and
|
|
32
|
+
* IPC registrations. Gating on session presence let that case skip teardown
|
|
33
|
+
* entirely, which is how closing an invalid project used to take the whole
|
|
34
|
+
* app down with it.
|
|
35
|
+
*/
|
|
36
|
+
function wireWorkbenchWindowEvents(win, ctx, teardown) {
|
|
37
|
+
let closing = false;
|
|
38
|
+
let torndown = false;
|
|
39
|
+
return wireMainWindowEvents(win, {
|
|
40
|
+
context: ctx,
|
|
41
|
+
onResize: () => ctx.views.repositionAll(),
|
|
42
|
+
onClose: async (e) => {
|
|
43
|
+
if (isAppQuitting())
|
|
44
|
+
return;
|
|
45
|
+
if (closing) {
|
|
46
|
+
e.preventDefault();
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
// Safety net for a `close()` that arrives after teardown finished (this
|
|
50
|
+
// module destroys the window itself, which emits no `close`).
|
|
51
|
+
if (torndown)
|
|
52
|
+
return;
|
|
53
|
+
e.preventDefault();
|
|
54
|
+
closing = true;
|
|
55
|
+
try {
|
|
56
|
+
await teardown();
|
|
57
|
+
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
console.error('[workbench] workbench window teardown failed:', err);
|
|
60
|
+
}
|
|
61
|
+
finally {
|
|
62
|
+
closing = false;
|
|
63
|
+
torndown = true;
|
|
64
|
+
}
|
|
65
|
+
if (!win.isDestroyed())
|
|
66
|
+
win.destroy();
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
export function createWorkbenchWindowManager(deps) {
|
|
71
|
+
const { config, rendererDir, appServices, router } = deps;
|
|
72
|
+
// Keyed by project path: one window per project, so a second open of the
|
|
73
|
+
// same project focuses the existing window instead of racing two sessions
|
|
74
|
+
// (and two compile workers) over the same directory.
|
|
75
|
+
const windows = new Map();
|
|
76
|
+
// Serializes every open and close of one project path. The map alone cannot
|
|
77
|
+
// carry "one window per project": an open has awaits in it, and a close
|
|
78
|
+
// awaits host code, so overlapping requests (a re-click on the project list,
|
|
79
|
+
// MCP's project_open) must queue rather than each find "no window" and build
|
|
80
|
+
// one. Entries are dropped once a path goes idle.
|
|
81
|
+
const pathQueues = new Map();
|
|
82
|
+
// Terminal state owned by this manager, deliberately not `isAppQuitting()`:
|
|
83
|
+
// a runtime can be disposed while the app keeps running, and a manager that
|
|
84
|
+
// has torn everything down must never build another window either way.
|
|
85
|
+
let disposed = false;
|
|
86
|
+
function disposedError() {
|
|
87
|
+
return new Error('workbench window manager is disposed');
|
|
88
|
+
}
|
|
89
|
+
function enqueue(path, task) {
|
|
90
|
+
const previous = pathQueues.get(path) ?? Promise.resolve();
|
|
91
|
+
// Same task on either outcome: a failed open or close must not wedge the
|
|
92
|
+
// queue for its path.
|
|
93
|
+
const result = previous.then(task, task);
|
|
94
|
+
const settled = result.then(() => { }, () => { });
|
|
95
|
+
pathQueues.set(path, settled);
|
|
96
|
+
void settled.then(() => {
|
|
97
|
+
if (pathQueues.get(path) === settled)
|
|
98
|
+
pathQueues.delete(path);
|
|
99
|
+
});
|
|
100
|
+
return result;
|
|
101
|
+
}
|
|
102
|
+
async function openWindow(project) {
|
|
103
|
+
// Checked where the queued task starts running, not where it was queued:
|
|
104
|
+
// an open sitting behind a close on the same path can be dequeued long
|
|
105
|
+
// after `disposeAll()` began, and must fail instead of resurrecting a
|
|
106
|
+
// project the app just tore down.
|
|
107
|
+
if (disposed)
|
|
108
|
+
throw disposedError();
|
|
109
|
+
const existing = windows.get(project.path);
|
|
110
|
+
if (existing && !existing.window.isDestroyed()) {
|
|
111
|
+
if (existing.window.isMinimized())
|
|
112
|
+
existing.window.restore();
|
|
113
|
+
existing.window.focus();
|
|
114
|
+
router.setActive(existing.context);
|
|
115
|
+
deps.onActiveContextChanged?.();
|
|
116
|
+
return existing.window;
|
|
117
|
+
}
|
|
118
|
+
const projectWindow = createWorkbenchWindow({ config, rendererDir, appServices, router }, project);
|
|
119
|
+
const { window, context } = projectWindow;
|
|
120
|
+
windows.set(project.path, projectWindow);
|
|
121
|
+
// Reveal gate: the window is created hidden (see `createWorkbenchWindow`)
|
|
122
|
+
// and must stay hidden until BOTH the renderer has painted its first
|
|
123
|
+
// frame (`ready-to-show`) and `setupProjectWindow` has resolved —
|
|
124
|
+
// whichever finishes second triggers the reveal, exactly once. Wired
|
|
125
|
+
// before any `await` below so a renderer that paints before the hook
|
|
126
|
+
// settles (the common case) is never missed.
|
|
127
|
+
let rendererReady = false;
|
|
128
|
+
let setupDone = false;
|
|
129
|
+
let revealed = false;
|
|
130
|
+
// Flipped the moment a close is requested, not when teardown runs: the
|
|
131
|
+
// close queues behind this open on the same path, so the hook can still
|
|
132
|
+
// resolve first and would otherwise show a window whose close was
|
|
133
|
+
// already asked for, only for the queued teardown to destroy it.
|
|
134
|
+
let closeRequested = false;
|
|
135
|
+
const revealIfReady = () => {
|
|
136
|
+
if (revealed || !rendererReady || !setupDone)
|
|
137
|
+
return;
|
|
138
|
+
if (window.isDestroyed())
|
|
139
|
+
return;
|
|
140
|
+
// Same for a manager already tearing everything down: `disposeAll()`
|
|
141
|
+
// waits for this open to settle, and the window must not flash on the
|
|
142
|
+
// way out.
|
|
143
|
+
if (closeRequested || disposed)
|
|
144
|
+
return;
|
|
145
|
+
// Permanent opt-out: the framework must never show this window, no
|
|
146
|
+
// matter how many times the two gates above are satisfied.
|
|
147
|
+
if (config.projectWindow?.autoShow === false)
|
|
148
|
+
return;
|
|
149
|
+
revealed = true;
|
|
150
|
+
revealMainWindow(window);
|
|
151
|
+
};
|
|
152
|
+
window.once('ready-to-show', () => {
|
|
153
|
+
rendererReady = true;
|
|
154
|
+
revealIfReady();
|
|
155
|
+
});
|
|
156
|
+
const teardown = async () => {
|
|
157
|
+
// A close queued behind an open that then failed (or lost to
|
|
158
|
+
// `disposeAll()`) finds the window already removed and torn down by
|
|
159
|
+
// that open's own undo path. Nothing is left to close, and the host
|
|
160
|
+
// hook must not be handed a disposed context and a destroyed window.
|
|
161
|
+
if (windows.get(project.path) !== projectWindow)
|
|
162
|
+
return;
|
|
163
|
+
try {
|
|
164
|
+
await deps.onBeforeClose?.(projectWindow, project);
|
|
165
|
+
}
|
|
166
|
+
catch (err) {
|
|
167
|
+
// The hook is the host's chance to react, not a veto: everything below
|
|
168
|
+
// (compile session, bridge router, editor server, IPC and app-level
|
|
169
|
+
// listeners) has to go, and the map entry with it, or the window's
|
|
170
|
+
// resources outlive a window nothing can reach any more.
|
|
171
|
+
console.error('[workbench] host onBeforeClose hook failed:', err);
|
|
172
|
+
}
|
|
173
|
+
try {
|
|
174
|
+
await projectWindow.dispose();
|
|
175
|
+
}
|
|
176
|
+
finally {
|
|
177
|
+
// Dropped LAST: while teardown is in flight this project still has a
|
|
178
|
+
// window, and an open arriving mid-close must queue behind it (see
|
|
179
|
+
// `enqueue`) instead of finding an empty map and building a second one.
|
|
180
|
+
if (windows.get(project.path) === projectWindow)
|
|
181
|
+
windows.delete(project.path);
|
|
182
|
+
}
|
|
183
|
+
// After the map entry is gone, so listeners read the window that is left.
|
|
184
|
+
deps.onActiveContextChanged?.();
|
|
185
|
+
};
|
|
186
|
+
try {
|
|
187
|
+
// The standalone internal DevTools window debugs THIS window's renderer,
|
|
188
|
+
// so it is per-window wiring. `isAppQuitting` lets the controller stop
|
|
189
|
+
// intercepting 'close' during a real quit.
|
|
190
|
+
context.internalDevtoolsWindow = createInternalDevtoolsWindow(window, { isAppQuitting });
|
|
191
|
+
context.registry.add(toDisposable(() => context.internalDevtoolsWindow?.dispose()));
|
|
192
|
+
// Wired before the awaited steps below: the window is already closable
|
|
193
|
+
// even though it's still hidden behind the reveal gate above, so it
|
|
194
|
+
// must never exist without the close handling that disposes it.
|
|
195
|
+
context.registry.add(wireWorkbenchWindowEvents(window, context, () => {
|
|
196
|
+
closeRequested = true;
|
|
197
|
+
return enqueue(project.path, teardown);
|
|
198
|
+
}));
|
|
199
|
+
// Whichever workbench window the user is looking at answers the IPC that
|
|
200
|
+
// no single window owns (menus, app-level host windows).
|
|
201
|
+
const onFocus = () => {
|
|
202
|
+
router.setActive(context);
|
|
203
|
+
deps.onActiveContextChanged?.();
|
|
204
|
+
};
|
|
205
|
+
window.on('focus', onFocus);
|
|
206
|
+
context.registry.add(toDisposable(() => {
|
|
207
|
+
if (!window.isDestroyed())
|
|
208
|
+
window.removeListener('focus', onFocus);
|
|
209
|
+
}));
|
|
210
|
+
// Order matters: the bridge router assigns ctx.bridge / ctx.consoleForwarder
|
|
211
|
+
// / ctx.diagnostics, which both the mirrors and the runtime services read.
|
|
212
|
+
deps.setupWindowModules(context);
|
|
213
|
+
installGlobalMirrors(context, window);
|
|
214
|
+
const getActiveAppId = createActiveAppIdResolver(context);
|
|
215
|
+
setupWindowRuntimeServices(context, window, getActiveAppId, project.path);
|
|
216
|
+
await setupEditorView(config, context, getActiveAppId);
|
|
217
|
+
// `disposeAll()` can land while this open is parked above. It waits for
|
|
218
|
+
// this task to settle rather than reaching into a half-built window, so
|
|
219
|
+
// the undo below is this open's own job.
|
|
220
|
+
if (disposed)
|
|
221
|
+
throw disposedError();
|
|
222
|
+
// Last, so the host configures a window whose own services are all up.
|
|
223
|
+
// It runs while the window is already in `windows`: a hook that opens
|
|
224
|
+
// views or drives the session needs the window reachable, and a failure
|
|
225
|
+
// path below removes the entry again.
|
|
226
|
+
await deps.setupProjectWindow?.(projectWindow, project);
|
|
227
|
+
// Re-checked after the hook for the same reason as before it: the hook
|
|
228
|
+
// is host code of unbounded duration, and an open that lost the race
|
|
229
|
+
// must reject rather than hand back a window `disposeAll()` is about
|
|
230
|
+
// to destroy.
|
|
231
|
+
if (disposed)
|
|
232
|
+
throw disposedError();
|
|
233
|
+
// Does not block `open()` returning: if `ready-to-show` already fired,
|
|
234
|
+
// this reveals now; otherwise it just marks the gate and the pending
|
|
235
|
+
// `ready-to-show` listener above reveals once Chromium paints.
|
|
236
|
+
setupDone = true;
|
|
237
|
+
revealIfReady();
|
|
238
|
+
}
|
|
239
|
+
catch (err) {
|
|
240
|
+
// A half-built window (the editor's http server can fail to bind) leaves
|
|
241
|
+
// live services behind and keeps the project counted as open — which is
|
|
242
|
+
// what the list window reads to decide whether to stay hidden. Undo the
|
|
243
|
+
// whole thing before handing the failure back.
|
|
244
|
+
windows.delete(project.path);
|
|
245
|
+
await projectWindow.dispose().catch((disposeErr) => {
|
|
246
|
+
console.warn('[workbench] failed to dispose a partially opened window:', disposeErr);
|
|
247
|
+
});
|
|
248
|
+
if (!window.isDestroyed())
|
|
249
|
+
window.destroy();
|
|
250
|
+
throw err;
|
|
251
|
+
}
|
|
252
|
+
deps.onActiveContextChanged?.();
|
|
253
|
+
return window;
|
|
254
|
+
}
|
|
255
|
+
return {
|
|
256
|
+
// One project window per RESOLVED absolute path: two differently-spelled
|
|
257
|
+
// strings pointing at the same directory ('/a/b' vs '/a/b/.') must not
|
|
258
|
+
// race two windows (and two compile workers) over one project. Resolving
|
|
259
|
+
// here, before the path reaches `windows`/`pathQueues`/`openWindow`,
|
|
260
|
+
// keeps every downstream lookup keyed on the one canonical spelling.
|
|
261
|
+
open: (project, options) => {
|
|
262
|
+
const normalized = { ...project, path: path.resolve(project.path) };
|
|
263
|
+
// The readiness gate is awaited inside the queued task, not before
|
|
264
|
+
// queuing: opens of one path must keep their arrival order, and a
|
|
265
|
+
// `disposeAll()` landing meanwhile still finds this open in the queue it
|
|
266
|
+
// drains rather than floating loose outside it.
|
|
267
|
+
const awaitReady = options?.awaitReady ?? true;
|
|
268
|
+
return enqueue(normalized.path, async () => {
|
|
269
|
+
if (awaitReady)
|
|
270
|
+
await deps.ready;
|
|
271
|
+
return openWindow(normalized);
|
|
272
|
+
});
|
|
273
|
+
},
|
|
274
|
+
list: () => [...windows.values()],
|
|
275
|
+
activeContext: () => {
|
|
276
|
+
const active = router.active();
|
|
277
|
+
const all = [...windows.values()];
|
|
278
|
+
if (all.some((pw) => pw.context === active))
|
|
279
|
+
return active;
|
|
280
|
+
return all.length > 0 ? all[all.length - 1].context : null;
|
|
281
|
+
},
|
|
282
|
+
disposeAll: async () => {
|
|
283
|
+
// Set before waiting, never after: the in-flight opens and closes being
|
|
284
|
+
// waited on are exactly the code that has to observe the terminal state
|
|
285
|
+
// in order to finish instead of building on.
|
|
286
|
+
disposed = true;
|
|
287
|
+
// Drained repeatedly because settling one entry releases whatever was
|
|
288
|
+
// queued behind it on the same path; new opens reject at their task
|
|
289
|
+
// start, so the queues run dry.
|
|
290
|
+
while (pathQueues.size > 0) {
|
|
291
|
+
await Promise.allSettled([...pathQueues.values()]);
|
|
292
|
+
}
|
|
293
|
+
// Snapshotted only now: an open that lost the race above already removed
|
|
294
|
+
// and disposed itself, and a finished close already dropped its entry,
|
|
295
|
+
// so nothing here is disposed twice.
|
|
296
|
+
const all = [...windows.values()];
|
|
297
|
+
windows.clear();
|
|
298
|
+
// Serial: each teardown closes a devkit session and an http server, and
|
|
299
|
+
// a parallel storm during quit is exactly when those races bite.
|
|
300
|
+
for (const projectWindow of all) {
|
|
301
|
+
await projectWindow.dispose().catch((err) => {
|
|
302
|
+
console.warn('[workbench] failed to tear down workbench window:', err);
|
|
303
|
+
});
|
|
304
|
+
if (!projectWindow.window.isDestroyed())
|
|
305
|
+
projectWindow.window.destroy();
|
|
306
|
+
}
|
|
307
|
+
},
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
//# sourceMappingURL=workbench-window.js.map
|