@dimina-kit/devtools 0.3.2-dev.20260611063505 → 0.3.2-dev.20260611135124

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/README.md +53 -40
  2. package/dist/main/api.d.ts +4 -2
  3. package/dist/main/api.js +5 -1
  4. package/dist/main/app/app.d.ts +1 -5
  5. package/dist/main/app/app.js +4 -19
  6. package/dist/main/index.bundle.js +238 -392
  7. package/dist/main/ipc/app.d.ts +1 -1
  8. package/dist/main/ipc/app.js +0 -7
  9. package/dist/main/ipc/index.d.ts +0 -2
  10. package/dist/main/ipc/index.js +0 -2
  11. package/dist/main/ipc/settings.d.ts +1 -1
  12. package/dist/main/ipc/settings.js +1 -13
  13. package/dist/main/ipc/simulator-module.d.ts +3 -3
  14. package/dist/main/ipc/simulator-module.js +3 -7
  15. package/dist/main/ipc/simulator.js +1 -12
  16. package/dist/main/runtime/miniapp-runtime.d.ts +138 -28
  17. package/dist/main/runtime/miniapp-runtime.js +6 -11
  18. package/dist/main/services/layout/index.d.ts +0 -11
  19. package/dist/main/services/layout/index.js +0 -23
  20. package/dist/main/services/notifications/renderer-notifier.d.ts +0 -6
  21. package/dist/main/services/notifications/renderer-notifier.js +1 -10
  22. package/dist/main/services/service-host-pool/pool.d.ts +5 -4
  23. package/dist/main/services/views/host-toolbar-port-channel.d.ts +93 -0
  24. package/dist/main/services/views/host-toolbar-port-channel.js +169 -0
  25. package/dist/main/services/views/host-toolbar-session-runtime.d.ts +35 -0
  26. package/dist/main/services/views/host-toolbar-session-runtime.js +55 -0
  27. package/dist/main/services/views/view-manager.d.ts +68 -39
  28. package/dist/main/services/views/view-manager.js +143 -182
  29. package/dist/main/services/workbench-context.d.ts +6 -26
  30. package/dist/main/services/workbench-context.js +0 -14
  31. package/dist/main/services/workspace/workspace-service.js +7 -13
  32. package/dist/main/utils/paths.d.ts +11 -2
  33. package/dist/main/utils/paths.js +11 -2
  34. package/dist/preload/index.d.ts +15 -0
  35. package/dist/preload/index.js +15 -0
  36. package/dist/preload/runtime/host-toolbar-port.d.ts +44 -0
  37. package/dist/preload/runtime/host-toolbar-port.js +127 -0
  38. package/dist/preload/runtime/host-toolbar-runtime.d.ts +41 -0
  39. package/dist/preload/runtime/host-toolbar-runtime.js +49 -0
  40. package/dist/preload/windows/{host-toolbar.cjs → host-toolbar-runtime.cjs} +94 -3
  41. package/dist/preload/windows/host-toolbar-runtime.cjs.map +7 -0
  42. package/dist/preload/windows/host-toolbar-runtime.d.ts +2 -0
  43. package/dist/preload/windows/host-toolbar-runtime.js +13 -0
  44. package/dist/preload/windows/simulator.cjs +0 -2
  45. package/dist/preload/windows/simulator.cjs.map +2 -2
  46. package/dist/preload/windows/simulator.js +0 -2
  47. package/dist/renderer/assets/constants-DI382mTP.js +2 -0
  48. package/dist/renderer/assets/index-DLzjz1wv.js +50 -0
  49. package/dist/renderer/assets/{input-CFHmbOgz.js → input-6fpCXV-n.js} +2 -2
  50. package/dist/renderer/assets/ipc-transport-Bs8Sf1B2.css +1 -0
  51. package/dist/renderer/assets/{ipc-transport-BkKKww3u.js → ipc-transport-D22e4dv7.js} +6 -6
  52. package/dist/renderer/assets/popover-CdGdKkkc.js +2 -0
  53. package/dist/renderer/assets/select-X0sbjwdP.js +2 -0
  54. package/dist/renderer/assets/{settings-Cl4IcWnG.js → settings-CS4jYaCw.js} +2 -2
  55. package/dist/renderer/assets/settings-api-CCWTAao_.js +2 -0
  56. package/dist/renderer/assets/workbenchSettings-Bpzaj3bm.js +8 -0
  57. package/dist/renderer/entries/main/index.html +7 -6
  58. package/dist/renderer/entries/popover/index.html +6 -6
  59. package/dist/renderer/entries/settings/index.html +5 -5
  60. package/dist/renderer/entries/workbench-settings/index.html +5 -5
  61. package/dist/shared/constants.d.ts +18 -0
  62. package/dist/shared/constants.js +18 -0
  63. package/dist/shared/ipc-channels.d.ts +10 -23
  64. package/dist/shared/ipc-channels.js +13 -34
  65. package/dist/shared/ipc-schemas.d.ts +0 -12
  66. package/dist/shared/ipc-schemas.js +0 -12
  67. package/dist/shared/types.d.ts +14 -67
  68. package/package.json +6 -6
  69. package/dist/main/ipc/panels.d.ts +0 -4
  70. package/dist/main/ipc/panels.js +0 -46
  71. package/dist/main/ipc/toolbar.d.ts +0 -4
  72. package/dist/main/ipc/toolbar.js +0 -21
  73. package/dist/main/services/toolbar/toolbar-store.d.ts +0 -23
  74. package/dist/main/services/toolbar/toolbar-store.js +0 -40
  75. package/dist/preload/windows/host-toolbar.cjs.map +0 -7
  76. package/dist/preload/windows/host-toolbar.d.ts +0 -2
  77. package/dist/preload/windows/host-toolbar.js +0 -12
  78. package/dist/renderer/assets/constants-CLAQX6VZ.js +0 -2
  79. package/dist/renderer/assets/index-CZQOpCvg.js +0 -50
  80. package/dist/renderer/assets/ipc-transport-Bv_BVu4T.css +0 -1
  81. package/dist/renderer/assets/popover-h1M7n3tt.js +0 -2
  82. package/dist/renderer/assets/select-kj0n1oYf.js +0 -2
  83. package/dist/renderer/assets/settings-api-CCwo2eOi.js +0 -2
  84. package/dist/renderer/assets/workbenchSettings-BzlpQnve.js +0 -8
@@ -1,4 +1,4 @@
1
1
  import type { WorkbenchContext } from '../services/workbench-context.js';
2
2
  import type { Disposable } from '@dimina-kit/electron-deck/main';
3
- export declare function registerAppIpc(ctx: Pick<WorkbenchContext, 'preloadPath' | 'brandingProvider' | 'appName' | 'headerHeight' | 'senderPolicy'>): Disposable;
3
+ export declare function registerAppIpc(ctx: Pick<WorkbenchContext, 'brandingProvider' | 'appName' | 'senderPolicy'>): Disposable;
4
4
  //# sourceMappingURL=app.d.ts.map
@@ -1,18 +1,11 @@
1
- import fs from 'fs';
2
1
  import { AppChannel } from '../../shared/ipc-channels.js';
3
2
  import { IpcRegistry } from '../utils/ipc-registry.js';
4
3
  export function registerAppIpc(ctx) {
5
4
  return new IpcRegistry(ctx.senderPolicy)
6
- .handle(AppChannel.GetPreloadPath, () => {
7
- return `file://${fs.realpathSync(ctx.preloadPath)}`;
8
- })
9
5
  .handle(AppChannel.GetBranding, async () => {
10
6
  if (ctx.brandingProvider)
11
7
  return ctx.brandingProvider();
12
8
  return { appName: ctx.appName };
13
- })
14
- .handle(AppChannel.GetHeaderHeight, () => {
15
- return ctx.headerHeight;
16
9
  });
17
10
  }
18
11
  //# sourceMappingURL=app.js.map
@@ -1,10 +1,8 @@
1
1
  export { registerAppIpc } from './app.js';
2
2
  export { registerSimulatorIpc } from './simulator.js';
3
- export { registerPanelsIpc } from './panels.js';
4
3
  export { registerPopoverIpc, popoverModule } from './popover.js';
5
4
  export { registerProjectsIpc, projectsModule } from './projects.js';
6
5
  export { registerSessionIpc, sessionModule } from './session.js';
7
6
  export { registerSettingsIpc, settingsModule } from './settings.js';
8
- export { registerToolbarIpc } from './toolbar.js';
9
7
  export { simulatorModule } from './simulator-module.js';
10
8
  //# sourceMappingURL=index.d.ts.map
@@ -1,10 +1,8 @@
1
1
  export { registerAppIpc } from './app.js';
2
2
  export { registerSimulatorIpc } from './simulator.js';
3
- export { registerPanelsIpc } from './panels.js';
4
3
  export { registerPopoverIpc, popoverModule } from './popover.js';
5
4
  export { registerProjectsIpc, projectsModule } from './projects.js';
6
5
  export { registerSessionIpc, sessionModule } from './session.js';
7
6
  export { registerSettingsIpc, settingsModule } from './settings.js';
8
- export { registerToolbarIpc } from './toolbar.js';
9
7
  export { simulatorModule } from './simulator-module.js';
10
8
  //# sourceMappingURL=index.js.map
@@ -1,6 +1,6 @@
1
1
  import type { WorkbenchContext } from '../services/workbench-context.js';
2
2
  import type { Disposable } from '@dimina-kit/electron-deck/main';
3
3
  import type { WorkbenchModule } from '../services/module.js';
4
- export declare function registerSettingsIpc(ctx: Pick<WorkbenchContext, 'views' | 'notify' | 'workspace' | 'rendererDir' | 'senderPolicy' | 'windows'>): Disposable;
4
+ export declare function registerSettingsIpc(ctx: Pick<WorkbenchContext, 'views' | 'notify' | 'workspace' | 'rendererDir' | 'senderPolicy'>): Disposable;
5
5
  export declare const settingsModule: WorkbenchModule;
6
6
  //# sourceMappingURL=settings.d.ts.map
@@ -1,10 +1,9 @@
1
1
  import { app } from 'electron';
2
- import { openSettingsWindow } from '../app/launch.js';
3
2
  import { loadWorkbenchSettings, saveWorkbenchSettings, applyTheme, } from '../services/settings/index.js';
4
3
  import { WorkbenchSettingsChannel, SettingsChannel } from '../../shared/ipc-channels.js';
5
4
  import { DEFAULT_CDP_PORT } from '../../shared/constants.js';
6
5
  import { getMcpStatus } from '../services/mcp/status.js';
7
- import { SettingsConfigChangedSchema, SettingsProjectSettingsChangedSchema, SettingsSetVisibleSchema, WorkbenchSettingsSaveSchema, WorkbenchSettingsSetThemeSchema, WorkbenchSettingsSetVisibleSchema, } from '../../shared/ipc-schemas.js';
6
+ import { SettingsConfigChangedSchema, SettingsProjectSettingsChangedSchema, SettingsSetVisibleSchema, WorkbenchSettingsSaveSchema, WorkbenchSettingsSetThemeSchema, } from '../../shared/ipc-schemas.js';
8
7
  import { validate } from '../utils/ipc-schema.js';
9
8
  import { IpcRegistry } from '../utils/ipc-registry.js';
10
9
  export function registerSettingsIpc(ctx) {
@@ -44,15 +43,6 @@ export function registerSettingsIpc(ctx) {
44
43
  activePort: runtime.port,
45
44
  error: runtime.error,
46
45
  };
47
- })
48
- .handle(WorkbenchSettingsChannel.SetVisible, async (_, ...args) => {
49
- const [visible] = validate(WorkbenchSettingsChannel.SetVisible, WorkbenchSettingsSetVisibleSchema, args);
50
- if (visible) {
51
- await openSettingsWindow(ctx);
52
- }
53
- else {
54
- ctx.windows.closeSettingsWindow();
55
- }
56
46
  })
57
47
  .handle(SettingsChannel.SetVisible, async (_, ...args) => {
58
48
  const [visible] = validate(SettingsChannel.SetVisible, SettingsSetVisibleSchema, args);
@@ -67,7 +57,6 @@ export function registerSettingsIpc(ctx) {
67
57
  }
68
58
  else {
69
59
  ctx.views.hideSettings();
70
- ctx.notify.settingsClosed();
71
60
  }
72
61
  })
73
62
  .on(SettingsChannel.ConfigChanged, async (_, ...args) => {
@@ -76,7 +65,6 @@ export function registerSettingsIpc(ctx) {
76
65
  if (projectPath) {
77
66
  await ctx.workspace.saveCompileConfig(projectPath, config);
78
67
  }
79
- ctx.notify.settingsChanged(config);
80
68
  })
81
69
  .on(SettingsChannel.ProjectSettingsChanged, (_, ...args) => {
82
70
  const [patch] = validate(SettingsChannel.ProjectSettingsChanged, SettingsProjectSettingsChangedSchema, args);
@@ -1,8 +1,8 @@
1
1
  import type { WorkbenchModule } from '../services/module.js';
2
2
  /**
3
- * The 'simulator' built-in module fans out into three IPC registrars
4
- * (core simulator, panels, toolbar). Bundle them under a single module
5
- * so app.ts only sees one entry per BuiltinModuleId.
3
+ * The 'simulator' built-in module fans out into the simulator + views IPC
4
+ * registrars. Bundle them under a single module so app.ts only sees one
5
+ * entry per BuiltinModuleId.
6
6
  *
7
7
  * Bridge router (native-host PAGE_OPEN / NAV_ACTION / TAB_ACTION etc.) hooks
8
8
  * up unconditionally — the `__diminaNativeHost.enabled` flag in the simulator
@@ -1,13 +1,11 @@
1
1
  import { DisposableRegistry } from '@dimina-kit/electron-deck/main';
2
2
  import { registerSimulatorIpc } from './simulator.js';
3
- import { registerPanelsIpc } from './panels.js';
4
- import { registerToolbarIpc } from './toolbar.js';
5
3
  import { installBridgeRouter } from './bridge-router.js';
6
4
  import { registerViewsIpc } from './views.js';
7
5
  /**
8
- * The 'simulator' built-in module fans out into three IPC registrars
9
- * (core simulator, panels, toolbar). Bundle them under a single module
10
- * so app.ts only sees one entry per BuiltinModuleId.
6
+ * The 'simulator' built-in module fans out into the simulator + views IPC
7
+ * registrars. Bundle them under a single module so app.ts only sees one
8
+ * entry per BuiltinModuleId.
11
9
  *
12
10
  * Bridge router (native-host PAGE_OPEN / NAV_ACTION / TAB_ACTION etc.) hooks
13
11
  * up unconditionally — the `__diminaNativeHost.enabled` flag in the simulator
@@ -19,8 +17,6 @@ export const simulatorModule = {
19
17
  setup: (ctx) => {
20
18
  const reg = new DisposableRegistry();
21
19
  reg.add(registerSimulatorIpc(ctx));
22
- reg.add(registerPanelsIpc(ctx));
23
- reg.add(registerToolbarIpc(ctx));
24
20
  reg.add(registerViewsIpc(ctx));
25
21
  installBridgeRouter(ctx);
26
22
  return reg;
@@ -1,5 +1,5 @@
1
1
  import { ServiceHostChannel, SimulatorChannel, SimulatorCustomApiChannel } from '../../shared/ipc-channels.js';
2
- import { SimulatorAttachNativeSchema, SimulatorCustomApiInvokeSchema, SimulatorResizeSchema, SimulatorSetDeviceInfoSchema, SimulatorSetNativeBoundsSchema, SimulatorSetVisibleSchema, } from '../../shared/ipc-schemas.js';
2
+ import { SimulatorAttachNativeSchema, SimulatorCustomApiInvokeSchema, SimulatorSetDeviceInfoSchema, SimulatorSetNativeBoundsSchema, } from '../../shared/ipc-schemas.js';
3
3
  import { deviceInfoToHostEnv } from '../../shared/bridge-channels.js';
4
4
  import { validate } from '../utils/ipc-schema.js';
5
5
  import { IpcRegistry } from '../utils/ipc-registry.js';
@@ -11,10 +11,6 @@ export function registerSimulatorIpc(ctx) {
11
11
  })
12
12
  .handle(SimulatorChannel.Detach, () => {
13
13
  ctx.views.detachSimulator();
14
- })
15
- .handle(SimulatorChannel.Resize, (_, ...args) => {
16
- const [simWidth] = validate(SimulatorChannel.Resize, SimulatorResizeSchema, args);
17
- ctx.views.resize(simWidth);
18
14
  })
19
15
  .handle(SimulatorChannel.SetNativeBounds, (_, ...args) => {
20
16
  const [p] = validate(SimulatorChannel.SetNativeBounds, SimulatorSetNativeBoundsSchema, args);
@@ -38,13 +34,6 @@ export function registerSimulatorIpc(ctx) {
38
34
  if (serviceWc && !serviceWc.isDestroyed()) {
39
35
  serviceWc.send(ServiceHostChannel.HostEnvUpdate, deviceInfoToHostEnv(device));
40
36
  }
41
- })
42
- .handle(SimulatorChannel.SetVisible, (_, ...args) => {
43
- const [visible, simWidth] = validate(SimulatorChannel.SetVisible, SimulatorSetVisibleSchema, args);
44
- ctx.views.setVisible(visible, simWidth);
45
- })
46
- .handle(SimulatorCustomApiChannel.List, () => {
47
- return ctx.simulatorApis.list();
48
37
  })
49
38
  .handle(SimulatorCustomApiChannel.Invoke, (_, ...args) => {
50
39
  const [name, params] = validate(SimulatorCustomApiChannel.Invoke, SimulatorCustomApiInvokeSchema, args);
@@ -1,39 +1,149 @@
1
1
  /**
2
2
  * MiniappRuntime — the stable, host-facing contract surface (foundation.md §3
3
- * "MiniappRuntime 契约" layer, P4).
3
+ * "MiniappRuntime 契约" layer).
4
4
  *
5
- * `WorkbenchContext` is the rich internal main-process state: runtime kernel +
6
- * host config + trust/infra plumbing, all mixed. Downstream hosts (qdmp, a
7
- * re-skin of devtools that depends ONLY on devtools) don't consume that whole
8
- * grab-bag they drive the miniapp KERNEL: the view lifecycle (including the
9
- * host-controllable toolbar at `views.hostToolbar`), the cross-wc bridge, the
10
- * workspace, the custom-API registry, async storage, the appdata tap, the
11
- * connection layer, and the main→renderer notifier.
5
+ * HAND-WRITTEN, not derived from `WorkbenchContext`. A `Pick`-style projection
6
+ * would drag every nested internal service type (ViewManager,
7
+ * BridgeRouterHandle, SimulatorApiRegistry, Electron WebContents…) onto the
8
+ * public semver face, so any internal refactor of those services becomes an
9
+ * unreviewed breaking change for downstream hosts (qdmp). Instead this module
10
+ * names ONLY the audited downstream consumption surface, with structural DTOs
11
+ * and zero Electron types non-Electron consumers can compile against it.
12
12
  *
13
- * This module NAMES that kernel as an explicit, documented contract so the
14
- * surface a host depends on is compiler-enforced and versionable, instead of
15
- * "whatever fields of WorkbenchContext you happen to reach for". Config inputs
16
- * (appName / panels / apiNamespaces / branding / project templates) are the
17
- * host's INPUT, not part of the runtime it consumes; trust/infra
18
- * (senderPolicy / trustedWindowSenderIds / registry / toolbar action-table)
19
- * stay internal.
20
- *
21
- * Derived via `Pick<WorkbenchContext, …>` so the field TYPES never drift from
22
- * the real implementation — `MiniappRuntime` is a view onto `WorkbenchContext`,
23
- * and the conformance assertion below fails to compile the moment the context
24
- * stops satisfying the contract.
13
+ * Contract rules:
14
+ * - Members are FUNCTION-VALUED PROPERTIES (`m: (x) => r`), never method
15
+ * syntax: under strictFunctionTypes method signatures compare bivariantly,
16
+ * which would let a wrongly-narrowed implementation or host override slip
17
+ * past the drift sentinel.
18
+ * - `workspace.openProject` stays writable (no `readonly`): qdmp gates
19
+ * project permissions by reassigning it (documented monkey-patch contract).
20
+ * - `windows` is an OPAQUE handle (`object`): hosts pass it through to
21
+ * framework helpers but never reach into it (no BrowserWindow leak).
25
22
  *
26
- * The host-controllable toolbar WebContentsView hangs off `views.hostToolbar`
27
- * (a ViewManager concern), so it's reachable through the contract WITHOUT a 9th
28
- * top-level member `runtime.views.hostToolbar.loadURL(...)`.
23
+ * `asMiniappRuntime(ctx)` is an identity return the contract is a typed
24
+ * VIEW onto the live context, not a snapshot/projection. That is what makes
25
+ * the monkey-patch contract work (a copied projection would receive the patch
26
+ * on a dead object), and its `return ctx` doubles as the assignment-compat
27
+ * sentinel: if an internal service drifts away from the contract, compilation
28
+ * breaks HERE, in this package's CI — not in a downstream host's upgrade.
29
29
  */
30
30
  import type { WorkbenchContext } from '../services/workbench-context.js';
31
- /** The stable miniapp-kernel surface a downstream host (qdmp) consumes. */
32
- export type MiniappRuntime = Pick<WorkbenchContext, 'views' | 'bridge' | 'workspace' | 'simulatorApis' | 'storageApi' | 'appData' | 'connections' | 'notify'>;
31
+ /** Compile-status payload broadcast to hosts via `notify.projectStatus`. */
32
+ export interface MiniappProjectStatusPayload {
33
+ status: string;
34
+ message: string;
35
+ /** True when the status update is emitted by the file-watcher rebuild loop. */
36
+ hotReload?: boolean;
37
+ }
38
+ /**
39
+ * Host-facing control surface for the toolbar WebContentsView — the exact
40
+ * post-R2 message-channel surface (`send`/`onMessage`), with no `webContents`
41
+ * escape hatch (that would put Electron types on the contract).
42
+ */
43
+ export interface MiniappHostToolbar {
44
+ /**
45
+ * The host's own `webPreferences.preload` for the toolbar view (purely
46
+ * additive — never replaces the framework's session-resident height
47
+ * advertiser). Must be set before the view is (re)created; `null` (default)
48
+ * means "no host preload".
49
+ */
50
+ setPreloadPath: (path: string | null) => void;
51
+ /** Load a local file into the toolbar view (lazy-creates the view). */
52
+ loadFile: (path: string) => Promise<void>;
53
+ /** Load a URL into the toolbar view (lazy-creates the view). */
54
+ loadURL: (url: string) => Promise<void>;
55
+ /**
56
+ * Post `{ channel, payload }` to the toolbar page. Gated and non-queueing:
57
+ * returns false (delivering nothing, creating no view) while there is no
58
+ * live toolbar webContents or the current load's MessagePort handshake
59
+ * hasn't completed; true once the envelope went out.
60
+ */
61
+ send: (channel: string, payload: unknown) => boolean;
62
+ /**
63
+ * Register a host-side handler for messages the toolbar page sends via
64
+ * `window.diminaHostToolbar.send(channel, payload)`. May be called before
65
+ * the view exists; survives page reloads. `dispose()` detaches (idempotent).
66
+ */
67
+ onMessage: (channel: string, handler: (payload: unknown) => void) => {
68
+ dispose: () => void;
69
+ };
70
+ /**
71
+ * Pin (`{ fixed }`) or unpin (`'auto'`) the toolbar strip height. `'auto'`
72
+ * (default) lets the in-page height advertiser drive the placeholder.
73
+ */
74
+ setHeightMode: (mode: 'auto' | {
75
+ fixed: number;
76
+ }) => void;
77
+ }
78
+ /**
79
+ * The audited workspace surface: project list membership, session lifecycle,
80
+ * and minimal session state. Thumbnails / per-project settings / providers
81
+ * stay internal.
82
+ */
83
+ export interface MiniappWorkspace {
84
+ /** True while a project session is open. */
85
+ hasActiveSession: () => boolean;
86
+ /** Absolute path of the open project, or '' when none. */
87
+ getProjectPath: () => string;
88
+ /**
89
+ * Open (compile + start) a project session. WRITABLE BY CONTRACT: hosts may
90
+ * reassign this member to wrap it (e.g. a permission gate) — every internal
91
+ * caller routes through the live property, so the wrapper always intercepts.
92
+ */
93
+ openProject: (projectPath: string) => Promise<{
94
+ success: boolean;
95
+ error?: string;
96
+ }>;
97
+ /** Tear down the active session (no-op when none). */
98
+ closeProject: () => Promise<void>;
99
+ /** True when the directory is already in the project list. */
100
+ hasProject: (dirPath: string) => Promise<boolean>;
101
+ /** Add a directory to the project list. */
102
+ addProject: (dirPath: string) => Promise<unknown>;
103
+ /**
104
+ * Minimal live-session DTO, or null when no session. Deliberately excludes
105
+ * the session's own `close` — hosts end sessions via `closeProject`, never
106
+ * behind the workspace's back.
107
+ */
108
+ getSession: () => {
109
+ appInfo: unknown;
110
+ } | null;
111
+ }
112
+ /**
113
+ * The stable miniapp-kernel surface a downstream host (qdmp) consumes.
114
+ * Compiler-enforced and versionable: widening it back toward internal
115
+ * plumbing is a deliberate semver decision, not an accident of projection.
116
+ */
117
+ export interface MiniappRuntime {
118
+ /** Absolute path to the devtools renderer dist directory. */
119
+ rendererDir: string;
120
+ /** View layer — only the host-owned toolbar control is public. */
121
+ views: {
122
+ readonly hostToolbar: MiniappHostToolbar;
123
+ };
124
+ /** Project + session workspace (see {@link MiniappWorkspace}). */
125
+ workspace: MiniappWorkspace;
126
+ /** Main → renderer notifier — only the compile-status broadcast is public. */
127
+ notify: {
128
+ projectStatus: (payload: MiniappProjectStatusPayload) => void;
129
+ };
130
+ /** Lifecycle sink: hosts register their own teardown via `registry.add`. */
131
+ registry: {
132
+ add: (dispose: () => void) => unknown;
133
+ };
134
+ /**
135
+ * Opaque window-service handle. Pass it through to framework helpers
136
+ * (e.g. `openSettingsWindow`); it exposes nothing to reach into.
137
+ */
138
+ windows: object;
139
+ }
33
140
  /**
34
- * Project a full `WorkbenchContext` down to its `MiniappRuntime` view. Hosts
35
- * call this to get a value typed to exactly the contract no wider access to
36
- * the context's internals leaks through.
141
+ * View a full `WorkbenchContext` as its `MiniappRuntime` contract. Identity
142
+ * return: the result IS the live context, typed down to the contract, so host
143
+ * monkey-patches (e.g. `runtime.workspace.openProject = gated`) land on the
144
+ * real object. The `return ctx` is also the compile-time drift sentinel — if
145
+ * `WorkbenchContext` ever stops structurally satisfying the contract, THIS
146
+ * stops compiling.
37
147
  */
38
148
  export declare function asMiniappRuntime(ctx: WorkbenchContext): MiniappRuntime;
39
149
  //# sourceMappingURL=miniapp-runtime.d.ts.map
@@ -1,17 +1,12 @@
1
1
  /**
2
- * Project a full `WorkbenchContext` down to its `MiniappRuntime` view. Hosts
3
- * call this to get a value typed to exactly the contract no wider access to
4
- * the context's internals leaks through.
2
+ * View a full `WorkbenchContext` as its `MiniappRuntime` contract. Identity
3
+ * return: the result IS the live context, typed down to the contract, so host
4
+ * monkey-patches (e.g. `runtime.workspace.openProject = gated`) land on the
5
+ * real object. The `return ctx` is also the compile-time drift sentinel — if
6
+ * `WorkbenchContext` ever stops structurally satisfying the contract, THIS
7
+ * stops compiling.
5
8
  */
6
9
  export function asMiniappRuntime(ctx) {
7
10
  return ctx;
8
11
  }
9
- /**
10
- * Compile-time conformance guard: if `WorkbenchContext` ever stops structurally
11
- * satisfying `MiniappRuntime` (a kernel field renamed / its type narrowed),
12
- * THIS line fails `tsc`, catching the contract break at build time. The runtime
13
- * value is unused.
14
- */
15
- const _conformance = (ctx) => ctx;
16
- void _conformance;
17
12
  //# sourceMappingURL=miniapp-runtime.js.map
@@ -1,20 +1,9 @@
1
- /** Layout constants (px) */
2
- export declare const SPLITTER_W = 4;
3
- /**
4
- * X coordinate where the legacy right-side overlay starts.
5
- */
6
- export declare function getRightX(simWidth: number): number;
7
1
  export interface Bounds {
8
2
  x: number;
9
3
  y: number;
10
4
  width: number;
11
5
  height: number;
12
6
  }
13
- export declare function computeRightPanelBounds(contentWidth: number, contentHeight: number, simWidth: number, headerHeight: number): Bounds;
14
- /**
15
- * Compute bounds for DevTools view (same as right panel, overlays it).
16
- */
17
- export declare function computeSimulatorBounds(contentWidth: number, contentHeight: number, simWidth: number, headerHeight: number): Bounds;
18
7
  /**
19
8
  * NATIVE-HOST ONLY. Translate the renderer-measured simulator panel REGION rect
20
9
  * (CSS px from the main window content top-left — the flex:1 placeholder slot)
@@ -1,26 +1,3 @@
1
- /** Layout constants (px) */
2
- export const SPLITTER_W = 4;
3
- /**
4
- * X coordinate where the legacy right-side overlay starts.
5
- */
6
- export function getRightX(simWidth) {
7
- return simWidth + SPLITTER_W;
8
- }
9
- export function computeRightPanelBounds(contentWidth, contentHeight, simWidth, headerHeight) {
10
- const x = getRightX(simWidth);
11
- return {
12
- x,
13
- y: headerHeight,
14
- width: Math.max(1, contentWidth - x),
15
- height: Math.max(1, contentHeight - headerHeight),
16
- };
17
- }
18
- /**
19
- * Compute bounds for DevTools view (same as right panel, overlays it).
20
- */
21
- export function computeSimulatorBounds(contentWidth, contentHeight, simWidth, headerHeight) {
22
- return computeRightPanelBounds(contentWidth, contentHeight, simWidth, headerHeight);
23
- }
24
1
  /**
25
2
  * NATIVE-HOST ONLY. Translate the renderer-measured simulator panel REGION rect
26
3
  * (CSS px from the main window content top-left — the flex:1 placeholder slot)
@@ -45,16 +45,10 @@ export interface RendererNotifier {
45
45
  projectStatus(payload: ProjectStatusPayload): void;
46
46
  /** Ask the main renderer to navigate back to its landing screen. */
47
47
  windowNavigateBack(): void;
48
- /** Tell the main renderer the embedded settings overlay has been closed. */
49
- settingsClosed(): void;
50
- /** Broadcast an updated compile config to the main renderer. */
51
- settingsChanged(config: CompileConfig): void;
52
48
  /** Tell the main renderer the compile popover has been closed. */
53
49
  popoverClosed(): void;
54
50
  /** Ask the main renderer to relaunch the simulator with a new config. */
55
51
  popoverRelaunch(config: CompileConfig): void;
56
- /** Tell the main renderer the toolbar actions list has changed. */
57
- toolbarActionsChanged(): void;
58
52
  /**
59
53
  * Push the reserved host-toolbar height to the main renderer so its toolbar
60
54
  * placeholder div resizes (closes the host-toolbar dynamic-height loop).
@@ -1,4 +1,4 @@
1
- import { ProjectChannel, WindowChannel, SettingsChannel, PopoverChannel, ToolbarChannel, WorkbenchSettingsChannel, EditorChannel, ViewChannel, } from '../../../shared/ipc-channels.js';
1
+ import { ProjectChannel, WindowChannel, SettingsChannel, PopoverChannel, WorkbenchSettingsChannel, EditorChannel, ViewChannel, } from '../../../shared/ipc-channels.js';
2
2
  /** Safely resolve a WebContents, skipping destroyed / missing targets. */
3
3
  function liveWebContents(wc) {
4
4
  if (!wc)
@@ -27,21 +27,12 @@ export function createRendererNotifier(ctx) {
27
27
  windowNavigateBack() {
28
28
  sendToMain(WindowChannel.NavigateBack);
29
29
  },
30
- settingsClosed() {
31
- sendToMain(SettingsChannel.Closed);
32
- },
33
- settingsChanged(config) {
34
- sendToMain(SettingsChannel.Changed, config);
35
- },
36
30
  popoverClosed() {
37
31
  sendToMain(PopoverChannel.Closed);
38
32
  },
39
33
  popoverRelaunch(config) {
40
34
  sendToMain(PopoverChannel.Relaunch, config);
41
35
  },
42
- toolbarActionsChanged() {
43
- sendToMain(ToolbarChannel.ActionsChanged);
44
- },
45
36
  hostToolbarHeightChanged(height) {
46
37
  sendToMain(ViewChannel.HostToolbarHeightChanged, height);
47
38
  },
@@ -5,10 +5,11 @@ import { BrowserWindow } from 'electron';
5
5
  * Design source: `packages/devtools/docs/prewarm-webview.md`. WIRED into
6
6
  * native-host via `bridge-router.handleSpawn` (acquire) + `disposeAppSession`
7
7
  * (release / releaseDestroyed), opt-in behind `DIMINA_PREWARM_POOL_SIZE`
8
- * (default OFF). Default-arch (`view-manager.attachSimulator`) is NOT pooled
9
- * its simulator is a `<webview>` tag, which Electron can't reparent a pre-warmed
10
- * WebContents into (doc §5 Phase 4, blocked by that hard limit, not by missing
11
- * work here).
8
+ * (default OFF). Only the SERVICE-HOST window is pooled; the simulator content
9
+ * WebContentsView (`view-manager.attachNativeSimulator`) is created fresh per
10
+ * attach. (The historical `<webview>`-tag default arch was never poolable
11
+ * Electron can't reparent a pre-warmed WebContents into a `<webview>`; doc §5
12
+ * Phase 4 — and that route has since been deleted outright.)
12
13
  *
13
14
  * Lifecycle of a pool entry:
14
15
  * warming — BrowserWindow constructed, page loading
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Gated narrow channel between the main process and the host-toolbar
3
+ * WebContentsView's page, over a per-load transferred MessagePort.
4
+ *
5
+ * Why a MessagePort and not plain IPC: the toolbar page is HOST-ARBITRARY
6
+ * content. A dedicated port pair gives it exactly one pipe whose main-side end
7
+ * lives in this module — the page never gains a generic `ipcRenderer` reach
8
+ * into the ~72 internal devtools channels, and main-side inbound traffic is
9
+ * validated at this single waist.
10
+ *
11
+ * Lifecycle (per-load handshake):
12
+ * - On every toolbar-wc `did-finish-load` main builds a fresh
13
+ * `MessageChannelMain`, transfers port2 to the new document via
14
+ * `wc.postMessage(ViewChannel.HostToolbarPort, null, [port2])`, keeps
15
+ * port1 and `start()`s it. The previous port1 (if any) is closed first —
16
+ * its document is gone.
17
+ * - `onMessage` registrations are CONTROL-level (this module's registry), not
18
+ * per-port: they may be made before any view exists and survive page
19
+ * reloads / wc rebuilds, because each new handshake dispatches into the
20
+ * same registry.
21
+ * - `send` is gated and non-queueing: `false` means "not delivered, ever" —
22
+ * no toolbar view is conjured, nothing is buffered for a later handshake.
23
+ * - A port1 `'close'` event (the renderer end died without a re-handshake
24
+ * yet) drops the live-port reference so `send` reports `false` instead of
25
+ * posting into a dead pipe.
26
+ * - NAVIGATION INVALIDATES THE PORT. The port pair belongs to one DOCUMENT,
27
+ * so starting a navigation that replaces that document closes port1 and
28
+ * `send` returns `false` until the new document's `did-finish-load`
29
+ * handshake. Two paths:
30
+ * (a) host-initiated `hostToolbar.loadURL/loadFile` calls `invalidate()`
31
+ * synchronously AT INITIATION (view-manager does this before the
32
+ * `webContents.loadURL/loadFile` await), so a same-tick `send` can
33
+ * never report `true` for an envelope posted into the document the
34
+ * load is about to replace;
35
+ * (b) page-initiated navigation (location.href / reload) is caught by a
36
+ * `did-start-navigation` listener — guarded to the ACTIVE wc,
37
+ * main-frame, cross-document only. Same-document navigations
38
+ * (anchors, pushState, history) and subframe navigations do NOT
39
+ * invalidate: the document the port lives in survives those, and no
40
+ * main-frame `did-finish-load` would follow to ever restore the
41
+ * channel.
42
+ *
43
+ * Envelope both directions: `{ channel: string, payload: unknown }`. Inbound
44
+ * data that is not an object with a string `channel` is DROPPED without
45
+ * throwing (the counterpart is arbitrary host content).
46
+ */
47
+ import type { WebContents } from 'electron';
48
+ /** Handle returned by `onMessage`; `dispose()` detaches (idempotent). */
49
+ export interface HostToolbarMessageSubscription {
50
+ dispose(): void;
51
+ }
52
+ export interface HostToolbarPortChannel {
53
+ /**
54
+ * Hook a freshly created toolbar webContents: registers the
55
+ * `did-finish-load` (per-load handshake) and `destroyed` (drop the live
56
+ * port) listeners via `wc.on(...)`. Call exactly once per wc, right after
57
+ * the view is created.
58
+ */
59
+ attach(wc: WebContents): void;
60
+ /**
61
+ * Drop the live port NOW (close + clear): the document it belongs to is
62
+ * being replaced. Called by view-manager synchronously when the HOST
63
+ * initiates a `loadURL`/`loadFile` — the host-initiated half of the
64
+ * navigation-invalidates contract (the page-initiated half is the
65
+ * `did-start-navigation` listener `attach` installs). `send` returns false
66
+ * from this call until the next `did-finish-load` handshake. Idempotent.
67
+ */
68
+ invalidate(): void;
69
+ /** Register a control-level inbound handler for `channel`. */
70
+ onMessage(channel: string, handler: (payload: unknown) => void): HostToolbarMessageSubscription;
71
+ /**
72
+ * Post `{ channel, payload }` to the toolbar page over the live port.
73
+ * Returns false (delivering NOTHING, creating NOTHING) when there is no
74
+ * live toolbar wc, the current load's handshake hasn't completed, or a
75
+ * document-replacing navigation is in flight (see `invalidate`).
76
+ */
77
+ send(channel: string, payload: unknown): boolean;
78
+ /**
79
+ * Teardown (view-manager `disposeAll`): close the live port, sweep the
80
+ * handler registry, refuse further handshakes. Subsequent `send` returns
81
+ * false; late `dispose()` of an old subscription stays a no-op.
82
+ */
83
+ dispose(): void;
84
+ }
85
+ export declare function createHostToolbarPortChannel(opts: {
86
+ /**
87
+ * Is `wc` still the manager's CURRENT live toolbar webContents? Guards a
88
+ * stale wc's late `did-finish-load` from hijacking the channel after a
89
+ * rebuild swapped the view out underneath it.
90
+ */
91
+ isCurrent: (wc: WebContents) => boolean;
92
+ }): HostToolbarPortChannel;
93
+ //# sourceMappingURL=host-toolbar-port-channel.d.ts.map