@dimina-kit/devtools 0.4.0-dev.20260615083030 → 0.4.0-dev.20260616024534

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.
@@ -6,6 +6,7 @@ import path from 'path';
6
6
  import { rendererDir as defaultRendererDir, defaultPreloadPath } from '../utils/paths.js';
7
7
  import { installThemeBackgroundSync } from '../utils/theme.js';
8
8
  import { createMainWindow, wireMainWindowEvents } from '../windows/main-window/index.js';
9
+ import { isAppQuitting } from './lifecycle.js';
9
10
  // eslint-disable-next-line no-restricted-syntax -- grandfathered(workbench-context): shrink-only
10
11
  import { createWorkbenchContext } from '../services/workbench-context.js';
11
12
  import { loadWorkbenchSettings, applyTheme } from '../services/settings/index.js';
@@ -131,6 +132,7 @@ function createConfiguredMainWindow(config, rendererDir) {
131
132
  height: config.window?.height,
132
133
  minWidth: config.window?.minWidth,
133
134
  minHeight: config.window?.minHeight,
135
+ autoShow: config.window?.autoShow,
134
136
  });
135
137
  // Set window/taskbar icon if provided (Linux/Windows; macOS uses app bundle icon)
136
138
  if (config.icon) {
@@ -157,6 +159,7 @@ function createContext(config, mainWindow, rendererDir) {
157
159
  projectTemplates: config.projectTemplates,
158
160
  builtinTemplates: config.builtinTemplates,
159
161
  customCreateProjectDialog: config.customCreateProjectDialog,
162
+ onBeforeOpenProject: config.onBeforeOpenProject,
160
163
  });
161
164
  }
162
165
  function registerBuiltinModules(config, context) {
@@ -229,6 +232,14 @@ function wireAppWindowEvents(config, instance) {
229
232
  context,
230
233
  onResize: () => context.views.repositionAll(),
231
234
  onClose: async (e) => {
235
+ // A real application quit (⌘Q / menu "Quit" / app.quit()) fires
236
+ // `before-quit` first, then this window's `close`. Let it through so the
237
+ // app actually exits — do NOT convert it into "close the project".
238
+ // Without this, `hasActiveSession()` would be true and the quit gets
239
+ // swallowed into closeProject(), so the app can never be quit while a
240
+ // project is open.
241
+ if (isAppQuitting())
242
+ return;
232
243
  if (!context.workspace.hasActiveSession())
233
244
  return;
234
245
  // Close button while a project session is open: stay in the workbench
@@ -1,2 +1,3 @@
1
+ export declare function isAppQuitting(): boolean;
1
2
  export declare function registerAppLifecycle(): void;
2
3
  //# sourceMappingURL=lifecycle.d.ts.map
@@ -1,10 +1,20 @@
1
1
  import { app, globalShortcut } from 'electron';
2
+ // Flips to `true` once Electron's `before-quit` fires — a real application
3
+ // quit (⌘Q / menu "Quit" / app.quit()) is underway. `before-quit` is emitted
4
+ // BEFORE each window's `close` event, so the main-window onClose handler can
5
+ // read this to tell "the whole app is exiting" apart from "the user closed a
6
+ // single project window" and avoid swallowing the quit.
7
+ let appIsQuitting = false;
8
+ export function isAppQuitting() {
9
+ return appIsQuitting;
10
+ }
2
11
  export function registerAppLifecycle() {
3
12
  app.on('window-all-closed', () => {
4
13
  globalShortcut.unregisterAll();
5
14
  app.quit();
6
15
  });
7
16
  app.on('before-quit', () => {
17
+ appIsQuitting = true;
8
18
  globalShortcut.unregisterAll();
9
19
  });
10
20
  }
@@ -761,7 +761,7 @@ function registerProjectFsIpc(ctx) {
761
761
  }
762
762
 
763
763
  // src/main/app/app.ts
764
- import { app as app14, BrowserWindow as BrowserWindow8, nativeImage, session as session4 } from "electron";
764
+ import { app as app15, BrowserWindow as BrowserWindow8, nativeImage, session as session4 } from "electron";
765
765
  import fs10 from "fs";
766
766
  import path21 from "path";
767
767
 
@@ -888,7 +888,9 @@ function createMainWindow(opts) {
888
888
  if (process.env.NODE_ENV === "test") {
889
889
  mainWindow.showInactive();
890
890
  } else {
891
- mainWindow.show();
891
+ if (opts.autoShow !== false) {
892
+ mainWindow.show();
893
+ }
892
894
  if (!app3.isPackaged && process.env.DIMINA_DEVTOOLS_MAIN_INSPECTOR === "1") {
893
895
  mainWindow.webContents.openDevTools({ mode: "detach" });
894
896
  }
@@ -943,6 +945,23 @@ function wireMainWindowEvents(win, state = {}) {
943
945
  return registry;
944
946
  }
945
947
 
948
+ // src/main/app/lifecycle.ts
949
+ import { app as app4, globalShortcut as globalShortcut2 } from "electron";
950
+ var appIsQuitting = false;
951
+ function isAppQuitting() {
952
+ return appIsQuitting;
953
+ }
954
+ function registerAppLifecycle() {
955
+ app4.on("window-all-closed", () => {
956
+ globalShortcut2.unregisterAll();
957
+ app4.quit();
958
+ });
959
+ app4.on("before-quit", () => {
960
+ appIsQuitting = true;
961
+ globalShortcut2.unregisterAll();
962
+ });
963
+ }
964
+
946
965
  // src/main/services/workbench-context.ts
947
966
  import {
948
967
  createConnectionRegistry,
@@ -966,12 +985,12 @@ function createWorkbenchSenderPolicy(ctx) {
966
985
 
967
986
  // src/main/services/default-adapter.ts
968
987
  import path6 from "path";
969
- import { app as app4 } from "electron";
988
+ import { app as app5 } from "electron";
970
989
  var defaultAdapter = {
971
990
  async openProject(opts) {
972
991
  const diminaKit = await import("@dimina-kit/devkit");
973
992
  const openProjectOpts = {
974
- outputDir: path6.join(app4.getPath("userData"), "dimina-fe-output"),
993
+ outputDir: path6.join(app5.getPath("userData"), "dimina-fe-output"),
975
994
  ...opts,
976
995
  simulatorDir
977
996
  };
@@ -2707,12 +2726,12 @@ async function openSettingsWindow(deps) {
2707
2726
  import { z as z2 } from "zod";
2708
2727
 
2709
2728
  // src/main/services/projects/project-repository.ts
2710
- import { app as app5 } from "electron";
2729
+ import { app as app6 } from "electron";
2711
2730
  import path9 from "path";
2712
2731
  import fs4 from "fs";
2713
2732
  var log2 = createLogger("projects");
2714
2733
  function getProjectsFile() {
2715
- return path9.join(app5.getPath("userData"), "dimina-projects.json");
2734
+ return path9.join(app6.getPath("userData"), "dimina-projects.json");
2716
2735
  }
2717
2736
  function load() {
2718
2737
  try {
@@ -2927,6 +2946,13 @@ function createWorkspaceService(ctx) {
2927
2946
  },
2928
2947
  validateProjectDir: async (dirPath) => provider.validateProjectDir ? provider.validateProjectDir(dirPath) : null,
2929
2948
  async openProject(projectPath) {
2949
+ if (ctx.onBeforeOpenProject) {
2950
+ try {
2951
+ await ctx.onBeforeOpenProject(projectPath);
2952
+ } catch (err) {
2953
+ return { success: false, error: err instanceof Error ? err.message : String(err) };
2954
+ }
2955
+ }
2930
2956
  clearSimulatorServicewechatReferer();
2931
2957
  logGeneration++;
2932
2958
  await disposeSession();
@@ -3046,9 +3072,9 @@ function createWorkspaceService(ctx) {
3046
3072
  import { createHash } from "crypto";
3047
3073
  import fs5 from "fs";
3048
3074
  import path10 from "path";
3049
- import { app as app6 } from "electron";
3075
+ import { app as app7 } from "electron";
3050
3076
  function getThumbnailDir() {
3051
- return path10.join(app6.getPath("userData"), "thumbnails");
3077
+ return path10.join(app7.getPath("userData"), "thumbnails");
3052
3078
  }
3053
3079
  function hashProjectPath(projectPath) {
3054
3080
  return createHash("sha256").update(projectPath).digest("hex").slice(0, 16);
@@ -3157,6 +3183,7 @@ function createWorkbenchContext(opts) {
3157
3183
  opts.builtinTemplates ?? "all"
3158
3184
  );
3159
3185
  ctx.customCreateProjectDialog = opts.customCreateProjectDialog;
3186
+ ctx.onBeforeOpenProject = opts.onBeforeOpenProject;
3160
3187
  ctx.workspace = createWorkspaceService(ctx);
3161
3188
  ctx.senderPolicy = createWorkbenchSenderPolicy(ctx);
3162
3189
  return ctx;
@@ -3463,7 +3490,7 @@ var popoverModule = {
3463
3490
  };
3464
3491
 
3465
3492
  // src/main/ipc/projects.ts
3466
- import { app as app7, dialog } from "electron";
3493
+ import { app as app8, dialog } from "electron";
3467
3494
  import path13 from "path";
3468
3495
 
3469
3496
  // src/main/services/projects/create-project-service.ts
@@ -3617,7 +3644,7 @@ function registerProjectsIpc(ctx) {
3617
3644
  }
3618
3645
  function safeAppPath(name) {
3619
3646
  try {
3620
- return app7.getPath(name);
3647
+ return app8.getPath(name);
3621
3648
  } catch {
3622
3649
  return null;
3623
3650
  }
@@ -3671,7 +3698,7 @@ var sessionModule = {
3671
3698
  };
3672
3699
 
3673
3700
  // src/main/ipc/settings.ts
3674
- import { app as app8 } from "electron";
3701
+ import { app as app9 } from "electron";
3675
3702
 
3676
3703
  // src/main/services/mcp/status.ts
3677
3704
  var status = { running: false, port: null, error: null };
@@ -3710,8 +3737,8 @@ function registerSettingsIpc(ctx) {
3710
3737
  applyTheme(theme);
3711
3738
  }).handle(WorkbenchSettingsChannel.GetCdpStatus, () => {
3712
3739
  const settings = loadWorkbenchSettings();
3713
- const switchValue = app8.commandLine.getSwitchValue("remote-debugging-port");
3714
- const implicitDevDefault = !app8.isPackaged && !settings.cdp.enabled && switchValue === String(DEFAULT_CDP_PORT);
3740
+ const switchValue = app9.commandLine.getSwitchValue("remote-debugging-port");
3741
+ const implicitDevDefault = !app9.isPackaged && !settings.cdp.enabled && switchValue === String(DEFAULT_CDP_PORT);
3715
3742
  return {
3716
3743
  configured: settings.cdp.enabled,
3717
3744
  port: settings.cdp.port,
@@ -3772,7 +3799,7 @@ var settingsModule = {
3772
3799
  import { DisposableRegistry as DisposableRegistry6 } from "@dimina-kit/electron-deck/main";
3773
3800
 
3774
3801
  // src/main/ipc/bridge-router.ts
3775
- import { app as app11, ipcMain as ipcMain3, protocol as protocol2, session as electronSession, webContents as webContents2 } from "electron";
3802
+ import { app as app12, ipcMain as ipcMain3, protocol as protocol2, session as electronSession, webContents as webContents2 } from "electron";
3776
3803
  import path16 from "node:path";
3777
3804
  import { pathToFileURL as pathToFileURL3 } from "node:url";
3778
3805
 
@@ -3880,7 +3907,7 @@ function setCorsHeaders(res) {
3880
3907
  }
3881
3908
 
3882
3909
  // src/main/windows/service-host-window/create.ts
3883
- import { app as app9, BrowserWindow as BrowserWindow4 } from "electron";
3910
+ import { app as app10, BrowserWindow as BrowserWindow4 } from "electron";
3884
3911
  import path15 from "node:path";
3885
3912
  import { pathToFileURL as pathToFileURL2 } from "node:url";
3886
3913
  var SERVICE_HOST_PARTITION = SHARED_MINIAPP_PARTITION;
@@ -3921,7 +3948,7 @@ function navigateServiceHost(win, url) {
3921
3948
  () => void 0,
3922
3949
  () => void 0
3923
3950
  );
3924
- if (!app9.isPackaged && process.env.NODE_ENV !== "test") {
3951
+ if (!app10.isPackaged && process.env.NODE_ENV !== "test") {
3925
3952
  const w = win;
3926
3953
  if (w.__diminaDevToolsHook) {
3927
3954
  try {
@@ -4318,7 +4345,7 @@ function createConsoleForwarder(bridge) {
4318
4345
  }
4319
4346
 
4320
4347
  // src/main/services/simulator-storage/index.ts
4321
- import { app as app10, webContents as wcStatic } from "electron";
4348
+ import { app as app11, webContents as wcStatic } from "electron";
4322
4349
  import { DisposableRegistry as DisposableRegistry5 } from "@dimina-kit/electron-deck/main";
4323
4350
 
4324
4351
  // src/main/services/simulator-storage/service-storage-ops.ts
@@ -4688,9 +4715,9 @@ function setupSimulatorStorage(host, options) {
4688
4715
  }
4689
4716
  }
4690
4717
  };
4691
- app10.on("web-contents-created", onWcCreated);
4718
+ app11.on("web-contents-created", onWcCreated);
4692
4719
  registry.add(() => {
4693
- app10.removeListener("web-contents-created", onWcCreated);
4720
+ app11.removeListener("web-contents-created", onWcCreated);
4694
4721
  });
4695
4722
  registry.add(async () => {
4696
4723
  const subs = Array.from(wcSubs.values());
@@ -5864,7 +5891,7 @@ function makeHostEnv(snapshot) {
5864
5891
  windowWidth: 390,
5865
5892
  windowHeight: 844,
5866
5893
  statusBarHeight: 24,
5867
- language: app11.getLocale(),
5894
+ language: app12.getLocale(),
5868
5895
  theme: "light",
5869
5896
  ...snapshot
5870
5897
  };
@@ -8661,7 +8688,7 @@ function setupSimulatorSessionPolicy() {
8661
8688
  }
8662
8689
 
8663
8690
  // src/main/services/update/update-manager.ts
8664
- import { app as app12, shell as shell3 } from "electron";
8691
+ import { app as app13, shell as shell3 } from "electron";
8665
8692
  var UpdateManager = class {
8666
8693
  checker;
8667
8694
  mainWindow;
@@ -8684,7 +8711,7 @@ var UpdateManager = class {
8684
8711
  constructor(opts) {
8685
8712
  this.checker = opts.checker;
8686
8713
  this.mainWindow = opts.mainWindow;
8687
- this.getCurrentVersion = opts.getCurrentVersion ?? (() => app12.getVersion());
8714
+ this.getCurrentVersion = opts.getCurrentVersion ?? (() => app13.getVersion());
8688
8715
  this.ipc = new IpcRegistry(opts.senderPolicy);
8689
8716
  this.registerIpc();
8690
8717
  this.startPeriodicCheck(opts.checkInterval ?? 60 * 60 * 1e3, opts.initialDelay ?? 5e3);
@@ -8725,7 +8752,7 @@ var UpdateManager = class {
8725
8752
  install() {
8726
8753
  if (this.downloadedPath) {
8727
8754
  shell3.openPath(this.downloadedPath);
8728
- app12.quit();
8755
+ app13.quit();
8729
8756
  }
8730
8757
  }
8731
8758
  /**
@@ -8759,7 +8786,7 @@ var UpdateManager = class {
8759
8786
  };
8760
8787
 
8761
8788
  // src/main/services/update/github-release-checker.ts
8762
- import { app as app13 } from "electron";
8789
+ import { app as app14 } from "electron";
8763
8790
 
8764
8791
  // src/main/app/app.ts
8765
8792
  import { toDisposable as toDisposable8 } from "@dimina-kit/electron-deck/main";
@@ -8834,7 +8861,8 @@ function createConfiguredMainWindow(config, rendererDir2) {
8834
8861
  width: config.window?.width,
8835
8862
  height: config.window?.height,
8836
8863
  minWidth: config.window?.minWidth,
8837
- minHeight: config.window?.minHeight
8864
+ minHeight: config.window?.minHeight,
8865
+ autoShow: config.window?.autoShow
8838
8866
  });
8839
8867
  if (config.icon) {
8840
8868
  const icon = nativeImage.createFromPath(config.icon);
@@ -8858,7 +8886,8 @@ function createContext(config, mainWindow, rendererDir2) {
8858
8886
  projectsProvider: config.projectsProvider,
8859
8887
  projectTemplates: config.projectTemplates,
8860
8888
  builtinTemplates: config.builtinTemplates,
8861
- customCreateProjectDialog: config.customCreateProjectDialog
8889
+ customCreateProjectDialog: config.customCreateProjectDialog,
8890
+ onBeforeOpenProject: config.onBeforeOpenProject
8862
8891
  });
8863
8892
  }
8864
8893
  function registerBuiltinModules(config, context) {
@@ -8903,7 +8932,7 @@ async function setupAutomation(instance) {
8903
8932
  function setupMcp() {
8904
8933
  const settings = loadWorkbenchSettings();
8905
8934
  if (!settings.mcp.enabled) return null;
8906
- const cdpPortSwitch = app14.commandLine.getSwitchValue("remote-debugging-port");
8935
+ const cdpPortSwitch = app15.commandLine.getSwitchValue("remote-debugging-port");
8907
8936
  const cdpPort2 = cdpPortSwitch ? parseInt(cdpPortSwitch, 10) : settings.cdp.port;
8908
8937
  return startMcpServer(cdpPort2, settings.mcp.port);
8909
8938
  }
@@ -8914,6 +8943,7 @@ function wireAppWindowEvents(config, instance) {
8914
8943
  context,
8915
8944
  onResize: () => context.views.repositionAll(),
8916
8945
  onClose: async (e) => {
8946
+ if (isAppQuitting()) return;
8917
8947
  if (!context.workspace.hasActiveSession()) return;
8918
8948
  e.preventDefault();
8919
8949
  if (closing) return;
@@ -8931,7 +8961,7 @@ function wireAppWindowEvents(config, instance) {
8931
8961
  });
8932
8962
  }
8933
8963
  function enableDevRendererAutoReload(rendererDir2) {
8934
- if (app14.isPackaged) {
8964
+ if (app15.isPackaged) {
8935
8965
  return toDisposable8(() => {
8936
8966
  });
8937
8967
  }
@@ -8954,7 +8984,7 @@ function enableDevRendererAutoReload(rendererDir2) {
8954
8984
  }
8955
8985
  function runDevtoolsBootstrap(config = {}) {
8956
8986
  try {
8957
- app14.setName(config.appName ?? "Dimina DevTools");
8987
+ app15.setName(config.appName ?? "Dimina DevTools");
8958
8988
  } catch {
8959
8989
  }
8960
8990
  setupCdpPort();
@@ -8962,7 +8992,7 @@ function runDevtoolsBootstrap(config = {}) {
8962
8992
  registerDifileScheme();
8963
8993
  }
8964
8994
  async function createDevtoolsRuntime(config = {}) {
8965
- await app14.whenReady();
8995
+ await app15.whenReady();
8966
8996
  applyTheme(loadWorkbenchSettings().theme);
8967
8997
  const rendererDir2 = config.rendererDir ?? rendererDir;
8968
8998
  const mainWindow = createConfiguredMainWindow(config, rendererDir2);
@@ -9111,18 +9141,6 @@ async function createDevtoolsRuntime(config = {}) {
9111
9141
  return instance;
9112
9142
  }
9113
9143
 
9114
- // src/main/app/lifecycle.ts
9115
- import { app as app15, globalShortcut as globalShortcut2 } from "electron";
9116
- function registerAppLifecycle() {
9117
- app15.on("window-all-closed", () => {
9118
- globalShortcut2.unregisterAll();
9119
- app15.quit();
9120
- });
9121
- app15.on("before-quit", () => {
9122
- globalShortcut2.unregisterAll();
9123
- });
9124
- }
9125
-
9126
9144
  // src/main/runtime/devtools-backend.ts
9127
9145
  function createDevtoolsBackend(config = {}) {
9128
9146
  let instance = null;
@@ -15,8 +15,10 @@
15
15
  * syntax: under strictFunctionTypes method signatures compare bivariantly,
16
16
  * which would let a wrongly-narrowed implementation or host override slip
17
17
  * past the drift sentinel.
18
- * - `workspace.openProject` stays writable (no `readonly`): qdmp gates
19
- * project permissions by reassigning it (documented monkey-patch contract).
18
+ * - `workspace.openProject` stays writable (no `readonly`) for backward
19
+ * compat: hosts MAY still gate permissions by reassigning it. The preferred
20
+ * path is now the declarative `WorkbenchAppConfig.onBeforeOpenProject` hook
21
+ * (runs before any side effect, throw to veto) — see host-migration.md §7.
20
22
  *
21
23
  * `asMiniappRuntime(ctx)` is an identity return — the contract is a typed
22
24
  * VIEW onto the live context, not a snapshot/projection. That is what makes
@@ -74,6 +74,13 @@ export interface WorkbenchContext {
74
74
  parentWindow: BrowserWindow;
75
75
  templates: ProjectTemplate[];
76
76
  }) => Promise<CustomCreateProjectDialogResult>;
77
+ /**
78
+ * Host permission gate consulted by `workspace.openProject` BEFORE any side
79
+ * effect. Throwing vetoes the open (see `WorkbenchAppConfig.onBeforeOpenProject`).
80
+ * Wired from the config by `createDevtoolsRuntime`; undefined for the
81
+ * single-tenant default.
82
+ */
83
+ onBeforeOpenProject?: (projectPath: string) => void | Promise<void>;
77
84
  /**
78
85
  * Trust predicate consulted by `IpcRegistry` for every incoming IPC.
79
86
  * Resolves the currently-trusted senders (main renderer + overlays)
@@ -183,6 +190,8 @@ export interface CreateContextOptions extends Pick<WorkbenchConfig, 'adapter' |
183
190
  builtinTemplates?: 'all' | 'none' | readonly string[];
184
191
  /** Host-supplied "新建项目" dialog hook. */
185
192
  customCreateProjectDialog?: WorkbenchContext['customCreateProjectDialog'];
193
+ /** Host permission gate run before a project opens (throw to veto). */
194
+ onBeforeOpenProject?: WorkbenchContext['onBeforeOpenProject'];
186
195
  }
187
196
  export declare function createWorkbenchContext(opts: CreateContextOptions): WorkbenchContext;
188
197
  export { sanitizeTemplates };
@@ -37,6 +37,7 @@ export function createWorkbenchContext(opts) {
37
37
  ctx.projectsProvider = opts.projectsProvider ?? createLocalProjectsProvider();
38
38
  ctx.projectTemplates = resolveTemplates(BUILTIN_TEMPLATES, opts.projectTemplates ?? [], opts.builtinTemplates ?? 'all');
39
39
  ctx.customCreateProjectDialog = opts.customCreateProjectDialog;
40
+ ctx.onBeforeOpenProject = opts.onBeforeOpenProject;
40
41
  ctx.workspace = createWorkspaceService(ctx);
41
42
  ctx.senderPolicy = createWorkbenchSenderPolicy(ctx);
42
43
  return ctx;
@@ -80,6 +80,19 @@ export function createWorkspaceService(ctx) {
80
80
  ? provider.validateProjectDir(dirPath)
81
81
  : null,
82
82
  async openProject(projectPath) {
83
+ // Host permission gate — runs BEFORE any side effect (referer reset,
84
+ // session teardown, compile/dev-server spin-up). A throwing hook vetoes
85
+ // the open: return early with the error and leave the currently-active
86
+ // session fully intact. The declarative replacement for monkey-patching
87
+ // this method. See WorkbenchAppConfig.onBeforeOpenProject.
88
+ if (ctx.onBeforeOpenProject) {
89
+ try {
90
+ await ctx.onBeforeOpenProject(projectPath);
91
+ }
92
+ catch (err) {
93
+ return { success: false, error: err instanceof Error ? err.message : String(err) };
94
+ }
95
+ }
83
96
  clearSimulatorServicewechatReferer();
84
97
  // Invalidate the outgoing session's onLog BEFORE teardown starts (same
85
98
  // order as closeProject below): the dying compile worker flushes
@@ -6,6 +6,12 @@ export interface WindowOptions {
6
6
  minWidth?: number;
7
7
  minHeight?: number;
8
8
  indexHtml: string;
9
+ /**
10
+ * Auto-show the window on `ready-to-show` in non-test envs. Defaults to
11
+ * `true`. `false` lets a login-gating host keep the window hidden and call
12
+ * `show()` itself. The test env always uses `showInactive()` regardless.
13
+ */
14
+ autoShow?: boolean;
9
15
  }
10
16
  export declare function createMainWindow(opts: WindowOptions): BrowserWindow;
11
17
  //# sourceMappingURL=create.d.ts.map
@@ -26,7 +26,11 @@ export function createMainWindow(opts) {
26
26
  mainWindow.showInactive();
27
27
  }
28
28
  else {
29
- mainWindow.show();
29
+ // A login-gating host opts out via `autoShow: false` and shows the
30
+ // window itself once auth passes — don't flash an un-authed window.
31
+ if (opts.autoShow !== false) {
32
+ mainWindow.show();
33
+ }
30
34
  // Don't auto-open a detached DevTools for the devtools UI shell itself —
31
35
  // it's noise for normal use (the mini-app's Console lives in the embedded
32
36
  // right-panel DevTools, not here). Opt in via env for debugging the shell.
@@ -108,6 +108,14 @@ export interface WorkbenchWindowConfig {
108
108
  height?: number;
109
109
  minWidth?: number;
110
110
  minHeight?: number;
111
+ /**
112
+ * Auto-show the main window on `ready-to-show`. Defaults to `true`. Set
113
+ * `false` when the host gates the window behind its own startup flow (e.g. a
114
+ * login screen) and wants to call `mainWindow.show()` itself once ready —
115
+ * avoids an un-authed window flashing on screen. Does not affect the test
116
+ * environment, which always uses `showInactive()` (e2e depends on it).
117
+ */
118
+ autoShow?: boolean;
111
119
  }
112
120
  export interface UpdateInfo {
113
121
  /** New version string (e.g. '1.2.0') */
@@ -205,6 +213,15 @@ export interface WorkbenchAppConfig extends WorkbenchConfig {
205
213
  onSetup?: (instance: WorkbenchHostInstance) => void | Promise<void>;
206
214
  /** Called before window close when a session is active. Session disposal happens automatically after this hook. */
207
215
  onBeforeClose?: (instance: WorkbenchHostInstance) => void | Promise<void>;
216
+ /**
217
+ * Called before a project is opened, BEFORE any side effect (session
218
+ * teardown, compile, dev-server). Use to gate the open on login/permission
219
+ * state. THROW to veto: `openProject` then resolves `{ success: false,
220
+ * error }`, leaves any currently-active session untouched, and never spins
221
+ * up the adapter. Resolve normally (or omit) to allow the open. The
222
+ * declarative alternative to monkey-patching `workspace.openProject`.
223
+ */
224
+ onBeforeOpenProject?: (projectPath: string) => void | Promise<void>;
208
225
  /** Custom update checker. If provided, enables the check-for-updates feature. */
209
226
  updateChecker?: UpdateChecker;
210
227
  /** Extra options applied when an updateChecker is provided. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dimina-kit/devtools",
3
- "version": "0.4.0-dev.20260615083030",
3
+ "version": "0.4.0-dev.20260616024534",
4
4
  "description": "Dimina DevTools - modular developer tools for mini app debugging",
5
5
  "keywords": [
6
6
  "dimina",
@@ -86,9 +86,9 @@
86
86
  "monaco-editor": "^0.55.1",
87
87
  "ws": "^8.20.0",
88
88
  "zod": "^4.3.6",
89
- "@dimina-kit/devkit": "0.1.2-dev.20260615083030",
90
- "@dimina-kit/view-anchor": "0.1.0-dev.20260615083030",
91
- "@dimina-kit/electron-deck": "0.1.0-dev.20260615083030"
89
+ "@dimina-kit/devkit": "0.1.2-dev.20260616024534",
90
+ "@dimina-kit/view-anchor": "0.1.0-dev.20260616024534",
91
+ "@dimina-kit/electron-deck": "0.1.0-dev.20260616024534"
92
92
  },
93
93
  "devDependencies": {
94
94
  "@playwright/test": "^1.59.1",