@dimina-kit/devtools 0.4.0-dev.20260703101348 → 0.4.0

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 (42) hide show
  1. package/dist/main/app/app.d.ts +4 -1
  2. package/dist/main/app/app.js +26 -0
  3. package/dist/main/index.bundle.js +186 -5
  4. package/dist/main/ipc/popover.js +10 -1
  5. package/dist/main/ipc/session.js +17 -1
  6. package/dist/main/services/compile-standby.d.ts +26 -0
  7. package/dist/main/services/compile-standby.js +57 -0
  8. package/dist/main/services/notifications/renderer-notifier.d.ts +5 -1
  9. package/dist/main/services/notifications/renderer-notifier.js +6 -0
  10. package/dist/main/services/projects/local-provider.js +4 -0
  11. package/dist/main/services/projects/project-repository.d.ts +7 -1
  12. package/dist/main/services/projects/project-repository.js +24 -0
  13. package/dist/main/services/projects/types.d.ts +25 -1
  14. package/dist/main/services/render-inspect/index.js +4 -4
  15. package/dist/main/services/workspace/workspace-service.d.ts +5 -1
  16. package/dist/main/services/workspace/workspace-service.js +8 -0
  17. package/dist/native-host/render/render.js +42 -52
  18. package/dist/native-host/service/service.js +2 -2
  19. package/dist/preload/windows/host-toolbar-runtime.cjs.map +2 -2
  20. package/dist/preload/windows/simulator.cjs.map +1 -1
  21. package/dist/renderer/assets/index-BMqyDx71.js +49 -0
  22. package/dist/renderer/assets/{input-CTb_le7F.js → input-CDAEwpBO.js} +2 -2
  23. package/dist/renderer/assets/ipc-transport-B7eFOR68.css +1 -0
  24. package/dist/renderer/assets/{ipc-transport-Ck5Xa8Tu.js → ipc-transport-_G1k5V1p.js} +2 -2
  25. package/dist/renderer/assets/popover-DEdjK14m.js +2 -0
  26. package/dist/renderer/assets/{select-ozSk5Pt6.js → select-DpKPCh3y.js} +2 -2
  27. package/dist/renderer/assets/{settings-CNwGOI22.js → settings-M5q2elUr.js} +2 -2
  28. package/dist/renderer/assets/{settings-api-DMbMp1Eq.js → settings-api-CDlZoHiO.js} +2 -2
  29. package/dist/renderer/assets/{workbenchSettings-Cr4EHo5w.js → workbenchSettings-CT_H1WhV.js} +2 -2
  30. package/dist/renderer/entries/main/index.html +6 -6
  31. package/dist/renderer/entries/popover/index.html +5 -5
  32. package/dist/renderer/entries/settings/index.html +5 -5
  33. package/dist/renderer/entries/workbench-settings/index.html +4 -4
  34. package/dist/shared/ipc-channels.d.ts +6 -0
  35. package/dist/shared/ipc-channels.js +6 -0
  36. package/dist/shared/ipc-schemas.d.ts +29 -0
  37. package/dist/shared/ipc-schemas.js +34 -0
  38. package/dist/shared/types.d.ts +28 -0
  39. package/package.json +5 -5
  40. package/dist/renderer/assets/index-BwzPwCmM.js +0 -49
  41. package/dist/renderer/assets/ipc-transport-BPWIV5hA.css +0 -1
  42. package/dist/renderer/assets/popover-B1Zu2UQu.js +0 -2
@@ -1,5 +1,5 @@
1
1
  import { BrowserWindow } from 'electron';
2
- import type { WorkbenchAppConfig } from '../../shared/types.js';
2
+ import type { LaunchConfig, WorkbenchAppConfig } from '../../shared/types.js';
3
3
  import type { SimulatorApiHandler } from '../services/simulator/custom-apis.js';
4
4
  import { type WorkbenchContext } from '../services/workbench-context.js';
5
5
  import { type AutomationServer } from '../services/automation/index.js';
@@ -18,6 +18,9 @@ export interface WorkbenchAppInstance {
18
18
  automationServer?: AutomationServer;
19
19
  updateManager?: UpdateManager;
20
20
  dispose: () => Promise<void>;
21
+ getLaunchConfigs: () => Promise<LaunchConfig[]>;
22
+ setLaunchConfigs: (configs: LaunchConfig[]) => Promise<void>;
23
+ setActiveLaunchConfig: (id: string | null) => Promise<void>;
21
24
  }
22
25
  /**
23
26
  * Pre-ready bootstrap side effects (app name, CDP port, CSP suppression,
@@ -11,6 +11,7 @@ import { isAppQuitting } from './lifecycle.js';
11
11
  import { resolveNativeAppDataKeys, resolveNativeStorageOverview } from './native-overview.js';
12
12
  // eslint-disable-next-line no-restricted-syntax -- grandfathered(workbench-context): shrink-only
13
13
  import { createWorkbenchContext } from '../services/workbench-context.js';
14
+ import { setupCompileWorkerStandby } from '../services/compile-standby.js';
14
15
  import { loadWorkbenchSettings, applyTheme } from '../services/settings/index.js';
15
16
  import { installAppMenu } from '../menu/index.js';
16
17
  import { registerAppIpc, popoverModule, projectsModule, sessionModule, settingsModule, simulatorModule, } from '../ipc/index.js';
@@ -369,6 +370,11 @@ export async function createDevtoolsRuntime(config = {}) {
369
370
  // backgroundColor on theme change — windows otherwise keep the stale
370
371
  // creation-time color (see installThemeBackgroundSync).
371
372
  context.registry.add(installThemeBackgroundSync());
373
+ // Warm-standby compile worker: only meaningful for the devkit-backed
374
+ // default adapter (a host-injected adapter has no devkit fork to adopt the
375
+ // spare). Registered into the registry so the spare dies with the context.
376
+ if (!config.adapter)
377
+ context.registry.add(setupCompileWorkerStandby(context));
372
378
  registerBuiltinModules(config, context);
373
379
  // Wire the simulator-side difile:// protocol handler + temp-file IPC
374
380
  // before host onSetup so any host-driven simulator boot sees the
@@ -394,6 +400,26 @@ export async function createDevtoolsRuntime(config = {}) {
394
400
  registerTrustedWindow: (win) => context.registry.add(registerTrustedWindow(context, win)),
395
401
  registerSimulatorApi: (name, handler) => context.registry.add(toDisposable(context.simulatorApis.register(name, handler))),
396
402
  dispose: () => disposeContext(context),
403
+ async getLaunchConfigs() {
404
+ const projectPath = context.workspace.getProjectPath();
405
+ if (!projectPath)
406
+ return [];
407
+ return context.workspace.getLaunchConfigs(projectPath);
408
+ },
409
+ async setLaunchConfigs(configs) {
410
+ const projectPath = context.workspace.getProjectPath();
411
+ if (!projectPath)
412
+ return;
413
+ await context.workspace.saveLaunchConfigs(projectPath, configs);
414
+ context.notify.popoverUpdateLaunchConfigs(configs);
415
+ },
416
+ async setActiveLaunchConfig(id) {
417
+ const projectPath = context.workspace.getProjectPath();
418
+ if (!projectPath)
419
+ return;
420
+ await context.workspace.saveActiveLaunchConfigId(projectPath, id);
421
+ context.notify.popoverSwitchLaunchConfig(id);
422
+ },
397
423
  };
398
424
  // Built-in simulator APIs: devtools-supplied wx.* implementations that run
399
425
  // in the main process. Hosts can override any of these in their onSetup by
@@ -391,7 +391,11 @@ var ProjectChannel = {
391
391
  // contract (compileEvents), this one carries the line stream (compileLogs).
392
392
  CompileLog: "project:compileLog",
393
393
  CaptureThumbnail: "project:captureThumbnail",
394
- GetThumbnail: "project:getThumbnail"
394
+ GetThumbnail: "project:getThumbnail",
395
+ GetLaunchConfigs: "project:getLaunchConfigs",
396
+ SaveLaunchConfigs: "project:saveLaunchConfigs",
397
+ GetActiveLaunchConfigId: "project:getActiveLaunchConfigId",
398
+ SaveActiveLaunchConfigId: "project:saveActiveLaunchConfigId"
395
399
  };
396
400
  var SessionChannel = {
397
401
  RuntimeStatus: "session:runtimeStatus"
@@ -476,7 +480,9 @@ var PopoverChannel = {
476
480
  Hide: "popover:hide",
477
481
  Relaunch: "popover:relaunch",
478
482
  Closed: "popover:closed",
479
- Init: "popover:init"
483
+ Init: "popover:init",
484
+ SwitchLaunchConfig: "popover:switchLaunchConfig",
485
+ UpdateLaunchConfigs: "popover:updateLaunchConfigs"
480
486
  };
481
487
  var WindowChannel = {
482
488
  NavigateBack: "window:navigateBack"
@@ -1123,6 +1129,12 @@ function createRendererNotifier(ctx) {
1123
1129
  popoverRelaunch(config) {
1124
1130
  sendToMain(PopoverChannel.Relaunch, config);
1125
1131
  },
1132
+ popoverSwitchLaunchConfig(id) {
1133
+ sendToMain(PopoverChannel.SwitchLaunchConfig, id);
1134
+ },
1135
+ popoverUpdateLaunchConfigs(configs) {
1136
+ sendToMain(PopoverChannel.UpdateLaunchConfigs, configs);
1137
+ },
1126
1138
  hostToolbarHeightChanged(height) {
1127
1139
  sendToMain(ViewChannel.HostToolbarHeightChanged, height);
1128
1140
  },
@@ -3960,6 +3972,30 @@ function getProjectSettings(projectPath) {
3960
3972
  return { uploadWithSourceMap: false };
3961
3973
  }
3962
3974
  }
3975
+ function getLaunchConfigs(dirPath) {
3976
+ const project = load().find((p) => p.path === dirPath);
3977
+ return project?.launchConfigs ?? [];
3978
+ }
3979
+ function saveLaunchConfigs(dirPath, configs) {
3980
+ const projects = load();
3981
+ const idx = projects.findIndex((p) => p.path === dirPath);
3982
+ if (idx >= 0) {
3983
+ projects[idx] = { ...projects[idx], launchConfigs: configs };
3984
+ save(projects);
3985
+ }
3986
+ }
3987
+ function getActiveLaunchConfigId(dirPath) {
3988
+ const project = load().find((p) => p.path === dirPath);
3989
+ return project?.activeLaunchConfigId ?? null;
3990
+ }
3991
+ function saveActiveLaunchConfigId(dirPath, id) {
3992
+ const projects = load();
3993
+ const idx = projects.findIndex((p) => p.path === dirPath);
3994
+ if (idx >= 0) {
3995
+ projects[idx] = { ...projects[idx], activeLaunchConfigId: id };
3996
+ save(projects);
3997
+ }
3998
+ }
3963
3999
  function updateProjectSettings(projectPath, patch) {
3964
4000
  if (!projectPath) return;
3965
4001
  const configPath = path10.join(projectPath, "project.config.json");
@@ -4265,7 +4301,15 @@ function createWorkspaceService(ctx) {
4265
4301
  // Per-project settings (uploadWithSourceMap etc.) live in the project's
4266
4302
  // own `project.config.json`, not the registry — keep direct repo calls.
4267
4303
  getProjectSettings: (projectPath) => getProjectSettings(projectPath),
4268
- updateProjectSettings: (projectPath, patch) => updateProjectSettings(projectPath, patch)
4304
+ updateProjectSettings: (projectPath, patch) => updateProjectSettings(projectPath, patch),
4305
+ getLaunchConfigs: async (p) => provider.getLaunchConfigs ? await provider.getLaunchConfigs(p) : [],
4306
+ saveLaunchConfigs: async (p, c) => {
4307
+ if (provider.saveLaunchConfigs) await provider.saveLaunchConfigs(p, c);
4308
+ },
4309
+ getActiveLaunchConfigId: async (p) => provider.getActiveLaunchConfigId ? await provider.getActiveLaunchConfigId(p) : null,
4310
+ saveActiveLaunchConfigId: async (p, id) => {
4311
+ if (provider.saveActiveLaunchConfigId) await provider.saveActiveLaunchConfigId(p, id);
4312
+ }
4269
4313
  };
4270
4314
  }
4271
4315
 
@@ -4311,7 +4355,11 @@ function createLocalProjectsProvider() {
4311
4355
  getCompileConfig: (dirPath) => getCompileConfig(dirPath),
4312
4356
  saveCompileConfig: (dirPath, cfg) => saveCompileConfig(dirPath, cfg),
4313
4357
  saveThumbnail: (dirPath, dataUrl) => saveThumbnailFromDataUrl(dirPath, dataUrl),
4314
- getThumbnail: (dirPath) => loadThumbnail(dirPath)
4358
+ getThumbnail: (dirPath) => loadThumbnail(dirPath),
4359
+ getLaunchConfigs: (dirPath) => getLaunchConfigs(dirPath),
4360
+ saveLaunchConfigs: (dirPath, configs) => saveLaunchConfigs(dirPath, configs),
4361
+ getActiveLaunchConfigId: (dirPath) => getActiveLaunchConfigId(dirPath),
4362
+ saveActiveLaunchConfigId: (dirPath, id) => saveActiveLaunchConfigId(dirPath, id)
4315
4363
  };
4316
4364
  }
4317
4365
 
@@ -4391,6 +4439,55 @@ function createWorkbenchContext(opts) {
4391
4439
  return ctx;
4392
4440
  }
4393
4441
 
4442
+ // src/main/services/compile-standby.ts
4443
+ var EVENT_SEVERITY = {
4444
+ "spawned": "info",
4445
+ "prewarmed": "info",
4446
+ "adopted": "info",
4447
+ "died": "warn",
4448
+ "health-check-failed": "warn",
4449
+ "degraded": "error"
4450
+ };
4451
+ function setupCompileWorkerStandby(ctx, deps = {}) {
4452
+ const loadDevkit = deps.loadDevkit ?? (() => import("@dimina-kit/devkit"));
4453
+ let manager = null;
4454
+ let disposed = false;
4455
+ const forward = (ev) => {
4456
+ try {
4457
+ const detail = [
4458
+ `compile standby ${ev.type}`,
4459
+ typeof ev.pid === "number" ? `pid=${ev.pid}` : null,
4460
+ ev.reason ? `\u2014 ${ev.reason}` : null
4461
+ ].filter(Boolean).join(" ");
4462
+ ctx.diagnostics?.report({
4463
+ severity: EVENT_SEVERITY[ev.type] ?? "info",
4464
+ code: "compile-standby",
4465
+ message: detail
4466
+ });
4467
+ } catch {
4468
+ }
4469
+ };
4470
+ void (async () => {
4471
+ let enable;
4472
+ try {
4473
+ const devkit = await loadDevkit();
4474
+ enable = devkit.enableCompileWorkerStandby;
4475
+ } catch {
4476
+ return;
4477
+ }
4478
+ if (typeof enable !== "function") return;
4479
+ manager = enable({ onEvent: forward });
4480
+ if (disposed) void manager.dispose();
4481
+ })();
4482
+ return {
4483
+ dispose: async () => {
4484
+ if (disposed) return;
4485
+ disposed = true;
4486
+ await manager?.dispose();
4487
+ }
4488
+ };
4489
+ }
4490
+
4394
4491
  // src/main/menu/index.ts
4395
4492
  import { Menu } from "electron";
4396
4493
  function installAppMenu(ctx) {
@@ -4596,6 +4693,29 @@ var SettingsProjectSettingsChangedSchema = z3.tuple([
4596
4693
  ]);
4597
4694
  var ProjectCaptureThumbnailSchema = z3.tuple([AbsolutePath]);
4598
4695
  var ProjectGetThumbnailSchema = z3.tuple([AbsolutePath]);
4696
+ var ProjectGetLaunchConfigsSchema = z3.tuple([AbsolutePath]);
4697
+ var LaunchConfigShape = z3.looseObject({
4698
+ id: z3.string().min(1),
4699
+ name: z3.string(),
4700
+ startPage: z3.string().optional(),
4701
+ scene: z3.number().optional(),
4702
+ queryParams: z3.array(z3.looseObject({ key: z3.string(), value: z3.string() })).optional()
4703
+ });
4704
+ var ProjectSaveLaunchConfigsSchema = z3.tuple([
4705
+ AbsolutePath,
4706
+ z3.array(LaunchConfigShape)
4707
+ ]);
4708
+ var ProjectGetActiveLaunchConfigIdSchema = z3.tuple([AbsolutePath]);
4709
+ var ProjectSaveActiveLaunchConfigIdSchema = z3.tuple([
4710
+ AbsolutePath,
4711
+ z3.union([z3.string(), z3.null()])
4712
+ ]);
4713
+ var PopoverSwitchLaunchConfigSchema = z3.tuple([
4714
+ z3.union([z3.string(), z3.null()])
4715
+ ]);
4716
+ var PopoverUpdateLaunchConfigsSchema = z3.tuple([
4717
+ z3.array(LaunchConfigShape)
4718
+ ]);
4599
4719
 
4600
4720
  // src/main/ipc/simulator.ts
4601
4721
  function registerSimulatorIpc(ctx) {
@@ -4632,6 +4752,21 @@ function registerPopoverIpc(ctx) {
4632
4752
  const [newConfig] = validate(PopoverChannel.Relaunch, PopoverRelaunchSchema, args);
4633
4753
  ctx.views.hidePopover();
4634
4754
  ctx.notify.popoverRelaunch(newConfig);
4755
+ }).on(PopoverChannel.SwitchLaunchConfig, (_event, ...args) => {
4756
+ const [id] = validate(
4757
+ PopoverChannel.SwitchLaunchConfig,
4758
+ PopoverSwitchLaunchConfigSchema,
4759
+ args
4760
+ );
4761
+ ctx.views.hidePopover();
4762
+ ctx.notify.popoverSwitchLaunchConfig(id);
4763
+ }).on(PopoverChannel.UpdateLaunchConfigs, (_event, ...args) => {
4764
+ const [configs] = validate(
4765
+ PopoverChannel.UpdateLaunchConfigs,
4766
+ PopoverUpdateLaunchConfigsSchema,
4767
+ args
4768
+ );
4769
+ ctx.notify.popoverUpdateLaunchConfigs(configs);
4635
4770
  });
4636
4771
  }
4637
4772
  var popoverModule = {
@@ -4857,6 +4992,34 @@ function registerSessionIpc(ctx) {
4857
4992
  args
4858
4993
  );
4859
4994
  return ctx.workspace.getThumbnail(projectPath);
4995
+ }).handle(ProjectChannel.GetLaunchConfigs, (_, ...args) => {
4996
+ const [projectPath] = validate(
4997
+ ProjectChannel.GetLaunchConfigs,
4998
+ ProjectGetLaunchConfigsSchema,
4999
+ args
5000
+ );
5001
+ return ctx.workspace.getLaunchConfigs(projectPath);
5002
+ }).handle(ProjectChannel.SaveLaunchConfigs, (_, ...args) => {
5003
+ const [projectPath, configs] = validate(
5004
+ ProjectChannel.SaveLaunchConfigs,
5005
+ ProjectSaveLaunchConfigsSchema,
5006
+ args
5007
+ );
5008
+ return ctx.workspace.saveLaunchConfigs(projectPath, configs);
5009
+ }).handle(ProjectChannel.GetActiveLaunchConfigId, (_, ...args) => {
5010
+ const [projectPath] = validate(
5011
+ ProjectChannel.GetActiveLaunchConfigId,
5012
+ ProjectGetActiveLaunchConfigIdSchema,
5013
+ args
5014
+ );
5015
+ return ctx.workspace.getActiveLaunchConfigId(projectPath);
5016
+ }).handle(ProjectChannel.SaveActiveLaunchConfigId, (_, ...args) => {
5017
+ const [projectPath, id] = validate(
5018
+ ProjectChannel.SaveActiveLaunchConfigId,
5019
+ ProjectSaveActiveLaunchConfigIdSchema,
5020
+ args
5021
+ );
5022
+ return ctx.workspace.saveActiveLaunchConfigId(projectPath, id);
4860
5023
  });
4861
5024
  }
4862
5025
  var sessionModule = {
@@ -11379,6 +11542,7 @@ async function createDevtoolsRuntime(config = {}) {
11379
11542
  context.registry.add(registerProjectFsIpc(context));
11380
11543
  context.registry.add(setupSimulatorSessionPolicy());
11381
11544
  context.registry.add(installThemeBackgroundSync());
11545
+ if (!config.adapter) context.registry.add(setupCompileWorkerStandby(context));
11382
11546
  registerBuiltinModules(config, context);
11383
11547
  const simSession = session4.fromPartition(SHARED_MINIAPP_PARTITION);
11384
11548
  context.registry.add(setupSimulatorTempFiles(simSession));
@@ -11394,7 +11558,24 @@ async function createDevtoolsRuntime(config = {}) {
11394
11558
  // teardown, so a single dispose leaves no dead entry behind.
11395
11559
  registerTrustedWindow: (win) => context.registry.add(registerTrustedWindow(context, win)),
11396
11560
  registerSimulatorApi: (name, handler) => context.registry.add(toDisposable8(context.simulatorApis.register(name, handler))),
11397
- dispose: () => disposeContext(context)
11561
+ dispose: () => disposeContext(context),
11562
+ async getLaunchConfigs() {
11563
+ const projectPath = context.workspace.getProjectPath();
11564
+ if (!projectPath) return [];
11565
+ return context.workspace.getLaunchConfigs(projectPath);
11566
+ },
11567
+ async setLaunchConfigs(configs) {
11568
+ const projectPath = context.workspace.getProjectPath();
11569
+ if (!projectPath) return;
11570
+ await context.workspace.saveLaunchConfigs(projectPath, configs);
11571
+ context.notify.popoverUpdateLaunchConfigs(configs);
11572
+ },
11573
+ async setActiveLaunchConfig(id) {
11574
+ const projectPath = context.workspace.getProjectPath();
11575
+ if (!projectPath) return;
11576
+ await context.workspace.saveActiveLaunchConfigId(projectPath, id);
11577
+ context.notify.popoverSwitchLaunchConfig(id);
11578
+ }
11398
11579
  };
11399
11580
  instance.registerSimulatorApi("login", async () => {
11400
11581
  return "hello";
@@ -1,5 +1,5 @@
1
1
  import { PopoverChannel } from '../../shared/ipc-channels.js';
2
- import { PopoverShowSchema, PopoverRelaunchSchema, } from '../../shared/ipc-schemas.js';
2
+ import { PopoverShowSchema, PopoverRelaunchSchema, PopoverSwitchLaunchConfigSchema, PopoverUpdateLaunchConfigsSchema, } from '../../shared/ipc-schemas.js';
3
3
  import { validate } from '../utils/ipc-schema.js';
4
4
  import { IpcRegistry } from '../utils/ipc-registry.js';
5
5
  export function registerPopoverIpc(ctx) {
@@ -15,6 +15,15 @@ export function registerPopoverIpc(ctx) {
15
15
  const [newConfig] = validate(PopoverChannel.Relaunch, PopoverRelaunchSchema, args);
16
16
  ctx.views.hidePopover();
17
17
  ctx.notify.popoverRelaunch(newConfig);
18
+ })
19
+ .on(PopoverChannel.SwitchLaunchConfig, (_event, ...args) => {
20
+ const [id] = validate(PopoverChannel.SwitchLaunchConfig, PopoverSwitchLaunchConfigSchema, args);
21
+ ctx.views.hidePopover();
22
+ ctx.notify.popoverSwitchLaunchConfig(id);
23
+ })
24
+ .on(PopoverChannel.UpdateLaunchConfigs, (_event, ...args) => {
25
+ const [configs] = validate(PopoverChannel.UpdateLaunchConfigs, PopoverUpdateLaunchConfigsSchema, args);
26
+ ctx.notify.popoverUpdateLaunchConfigs(configs);
18
27
  });
19
28
  }
20
29
  export const popoverModule = {
@@ -1,5 +1,5 @@
1
1
  import { ProjectChannel } from '../../shared/ipc-channels.js';
2
- import { ProjectCaptureThumbnailSchema, ProjectGetCompileConfigSchema, ProjectGetPagesSchema, ProjectGetThumbnailSchema, ProjectOpenSchema, ProjectSaveCompileConfigSchema, } from '../../shared/ipc-schemas.js';
2
+ import { ProjectCaptureThumbnailSchema, ProjectGetCompileConfigSchema, ProjectGetPagesSchema, ProjectGetThumbnailSchema, ProjectOpenSchema, ProjectSaveCompileConfigSchema, ProjectGetLaunchConfigsSchema, ProjectSaveLaunchConfigsSchema, ProjectGetActiveLaunchConfigIdSchema, ProjectSaveActiveLaunchConfigIdSchema, } from '../../shared/ipc-schemas.js';
3
3
  import { validate } from '../utils/ipc-schema.js';
4
4
  import { IpcRegistry } from '../utils/ipc-registry.js';
5
5
  export function registerSessionIpc(ctx) {
@@ -30,6 +30,22 @@ export function registerSessionIpc(ctx) {
30
30
  .handle(ProjectChannel.GetThumbnail, (_, ...args) => {
31
31
  const [projectPath] = validate(ProjectChannel.GetThumbnail, ProjectGetThumbnailSchema, args);
32
32
  return ctx.workspace.getThumbnail(projectPath);
33
+ })
34
+ .handle(ProjectChannel.GetLaunchConfigs, (_, ...args) => {
35
+ const [projectPath] = validate(ProjectChannel.GetLaunchConfigs, ProjectGetLaunchConfigsSchema, args);
36
+ return ctx.workspace.getLaunchConfigs(projectPath);
37
+ })
38
+ .handle(ProjectChannel.SaveLaunchConfigs, (_, ...args) => {
39
+ const [projectPath, configs] = validate(ProjectChannel.SaveLaunchConfigs, ProjectSaveLaunchConfigsSchema, args);
40
+ return ctx.workspace.saveLaunchConfigs(projectPath, configs);
41
+ })
42
+ .handle(ProjectChannel.GetActiveLaunchConfigId, (_, ...args) => {
43
+ const [projectPath] = validate(ProjectChannel.GetActiveLaunchConfigId, ProjectGetActiveLaunchConfigIdSchema, args);
44
+ return ctx.workspace.getActiveLaunchConfigId(projectPath);
45
+ })
46
+ .handle(ProjectChannel.SaveActiveLaunchConfigId, (_, ...args) => {
47
+ const [projectPath, id] = validate(ProjectChannel.SaveActiveLaunchConfigId, ProjectSaveActiveLaunchConfigIdSchema, args);
48
+ return ctx.workspace.saveActiveLaunchConfigId(projectPath, id);
33
49
  });
34
50
  }
35
51
  export const sessionModule = {
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Wires devkit's warm-standby compile worker into the devtools runtime.
3
+ *
4
+ * While no project is open, devkit keeps one project-agnostic compile worker
5
+ * forked + prewarmed; every openProject adopts it so the first compile skips
6
+ * fork + compiler import (~1.6s). This module owns exactly the glue devtools
7
+ * needs on top: turn the accelerator on at boot, mirror its lifecycle events
8
+ * onto the diagnostics bus (a user-machine bug report then carries the whole
9
+ * standby story), and shut it down with the context.
10
+ *
11
+ * Failure-transparent by design: if devkit is missing or predates the standby
12
+ * API, the accelerator silently stays off — compilation itself is untouched
13
+ * (the adapter falls back to devkit's normal cold-fork path, or the host runs
14
+ * its own adapter entirely).
15
+ */
16
+ import type { DiagnosticsBus } from './diagnostics/index.js';
17
+ export interface CompileStandbyDeps {
18
+ /** Test hook: replaces the dynamic import('@dimina-kit/devkit'). */
19
+ loadDevkit?: () => Promise<unknown>;
20
+ }
21
+ export declare function setupCompileWorkerStandby(ctx: {
22
+ diagnostics?: DiagnosticsBus;
23
+ }, deps?: CompileStandbyDeps): {
24
+ dispose: () => Promise<void>;
25
+ };
26
+ //# sourceMappingURL=compile-standby.d.ts.map
@@ -0,0 +1,57 @@
1
+ const EVENT_SEVERITY = {
2
+ 'spawned': 'info',
3
+ 'prewarmed': 'info',
4
+ 'adopted': 'info',
5
+ 'died': 'warn',
6
+ 'health-check-failed': 'warn',
7
+ 'degraded': 'error',
8
+ };
9
+ export function setupCompileWorkerStandby(ctx, deps = {}) {
10
+ const loadDevkit = deps.loadDevkit ?? (() => import('@dimina-kit/devkit'));
11
+ let manager = null;
12
+ let disposed = false;
13
+ const forward = (ev) => {
14
+ try {
15
+ const detail = [
16
+ `compile standby ${ev.type}`,
17
+ typeof ev.pid === 'number' ? `pid=${ev.pid}` : null,
18
+ ev.reason ? `— ${ev.reason}` : null,
19
+ ].filter(Boolean).join(' ');
20
+ ctx.diagnostics?.report({
21
+ severity: EVENT_SEVERITY[ev.type] ?? 'info',
22
+ code: 'compile-standby',
23
+ message: detail,
24
+ });
25
+ }
26
+ catch {
27
+ // telemetry must never break the standby
28
+ }
29
+ };
30
+ void (async () => {
31
+ let enable;
32
+ try {
33
+ const devkit = await loadDevkit();
34
+ enable = devkit.enableCompileWorkerStandby;
35
+ }
36
+ catch {
37
+ // devkit unavailable — the accelerator quietly stays off.
38
+ return;
39
+ }
40
+ if (typeof enable !== 'function')
41
+ return;
42
+ manager = enable({ onEvent: forward });
43
+ // A teardown that raced the async load wins: the manager is disposed the
44
+ // moment it exists, so a quitting app can never leak a fresh spare.
45
+ if (disposed)
46
+ void manager.dispose();
47
+ })();
48
+ return {
49
+ dispose: async () => {
50
+ if (disposed)
51
+ return;
52
+ disposed = true;
53
+ await manager?.dispose();
54
+ },
55
+ };
56
+ }
57
+ //# sourceMappingURL=compile-standby.js.map
@@ -1,5 +1,5 @@
1
1
  import type { BrowserWindow, WebContents, WebContentsView } from 'electron';
2
- import type { CompileConfig } from '../../../shared/types.js';
2
+ import type { CompileConfig, LaunchConfig } from '../../../shared/types.js';
3
3
  import { type EditorOpenFilePayload } from '../../../shared/ipc-channels.js';
4
4
  import type { WorkbenchSettings } from '../settings/index.js';
5
5
  import type { ProjectSettings } from '../projects/project-repository.js';
@@ -98,6 +98,10 @@ export interface RendererNotifier {
98
98
  popoverClosed(): void;
99
99
  /** Ask the main renderer to relaunch the simulator with a new config. */
100
100
  popoverRelaunch(config: CompileConfig): void;
101
+ /** Ask the main renderer to switch to a launch config (or null for normal). */
102
+ popoverSwitchLaunchConfig(id: string | null): void;
103
+ /** Ask the main renderer to update its launch configs list. */
104
+ popoverUpdateLaunchConfigs(configs: LaunchConfig[]): void;
101
105
  /**
102
106
  * Push the reserved host-toolbar height to the main renderer so its toolbar
103
107
  * placeholder div resizes (closes the host-toolbar dynamic-height loop).
@@ -39,6 +39,12 @@ export function createRendererNotifier(ctx) {
39
39
  popoverRelaunch(config) {
40
40
  sendToMain(PopoverChannel.Relaunch, config);
41
41
  },
42
+ popoverSwitchLaunchConfig(id) {
43
+ sendToMain(PopoverChannel.SwitchLaunchConfig, id);
44
+ },
45
+ popoverUpdateLaunchConfigs(configs) {
46
+ sendToMain(PopoverChannel.UpdateLaunchConfigs, configs);
47
+ },
42
48
  hostToolbarHeightChanged(height) {
43
49
  sendToMain(ViewChannel.HostToolbarHeightChanged, height);
44
50
  },
@@ -20,6 +20,10 @@ export function createLocalProjectsProvider() {
20
20
  saveCompileConfig: (dirPath, cfg) => repo.saveCompileConfig(dirPath, cfg),
21
21
  saveThumbnail: (dirPath, dataUrl) => saveThumbnailFromDataUrl(dirPath, dataUrl),
22
22
  getThumbnail: (dirPath) => loadThumbnail(dirPath),
23
+ getLaunchConfigs: (dirPath) => repo.getLaunchConfigs(dirPath),
24
+ saveLaunchConfigs: (dirPath, configs) => repo.saveLaunchConfigs(dirPath, configs),
25
+ getActiveLaunchConfigId: (dirPath) => repo.getActiveLaunchConfigId(dirPath),
26
+ saveActiveLaunchConfigId: (dirPath, id) => repo.saveActiveLaunchConfigId(dirPath, id),
23
27
  };
24
28
  }
25
29
  //# sourceMappingURL=local-provider.js.map
@@ -1,9 +1,11 @@
1
- import type { CompileConfig } from '../../../shared/types.js';
1
+ import type { CompileConfig, LaunchConfig } from '../../../shared/types.js';
2
2
  export interface Project {
3
3
  name: string;
4
4
  path: string;
5
5
  lastOpened?: string | null;
6
6
  compileConfig?: CompileConfig;
7
+ launchConfigs?: LaunchConfig[];
8
+ activeLaunchConfigId?: string | null;
7
9
  }
8
10
  export interface ProjectPages {
9
11
  pages: string[];
@@ -23,6 +25,10 @@ export declare function getProjectPages(dirPath: string): ProjectPages;
23
25
  export declare function saveCompileConfig(dirPath: string, config: CompileConfig): void;
24
26
  /** Read a subset of `project.config.json` exposed to the settings panel. */
25
27
  export declare function getProjectSettings(projectPath: string): ProjectSettings;
28
+ export declare function getLaunchConfigs(dirPath: string): LaunchConfig[];
29
+ export declare function saveLaunchConfigs(dirPath: string, configs: LaunchConfig[]): void;
30
+ export declare function getActiveLaunchConfigId(dirPath: string): string | null;
31
+ export declare function saveActiveLaunchConfigId(dirPath: string, id: string | null): void;
26
32
  /** Persist a partial patch into the `setting` block of `project.config.json`. */
27
33
  export declare function updateProjectSettings(projectPath: string, patch: Partial<ProjectSettings>): void;
28
34
  //# sourceMappingURL=project-repository.d.ts.map
@@ -132,6 +132,30 @@ export function getProjectSettings(projectPath) {
132
132
  return { uploadWithSourceMap: false };
133
133
  }
134
134
  }
135
+ export function getLaunchConfigs(dirPath) {
136
+ const project = load().find((p) => p.path === dirPath);
137
+ return project?.launchConfigs ?? [];
138
+ }
139
+ export function saveLaunchConfigs(dirPath, configs) {
140
+ const projects = load();
141
+ const idx = projects.findIndex((p) => p.path === dirPath);
142
+ if (idx >= 0) {
143
+ projects[idx] = { ...projects[idx], launchConfigs: configs };
144
+ save(projects);
145
+ }
146
+ }
147
+ export function getActiveLaunchConfigId(dirPath) {
148
+ const project = load().find((p) => p.path === dirPath);
149
+ return project?.activeLaunchConfigId ?? null;
150
+ }
151
+ export function saveActiveLaunchConfigId(dirPath, id) {
152
+ const projects = load();
153
+ const idx = projects.findIndex((p) => p.path === dirPath);
154
+ if (idx >= 0) {
155
+ projects[idx] = { ...projects[idx], activeLaunchConfigId: id };
156
+ save(projects);
157
+ }
158
+ }
135
159
  /** Persist a partial patch into the `setting` block of `project.config.json`. */
136
160
  export function updateProjectSettings(projectPath, patch) {
137
161
  if (!projectPath)
@@ -4,7 +4,7 @@
4
4
  * `WorkbenchAppConfig` to fully take over the project source-of-truth, the
5
5
  * template catalog, and the "新建项目" dialog.
6
6
  */
7
- import type { CompileConfig } from '../../../shared/types.js';
7
+ import type { CompileConfig, LaunchConfig } from '../../../shared/types.js';
8
8
  import type { Project } from './project-repository.js';
9
9
  export type { Project };
10
10
  export type { ProjectTemplate, CreateProjectInput } from '../../../shared/types.js';
@@ -81,6 +81,30 @@ export interface ProjectsProvider {
81
81
  * Default when omitted: returns `null`.
82
82
  */
83
83
  getThumbnail?(dirPath: string): string | null | Promise<string | null>;
84
+ /**
85
+ * Read saved launch configs for a project.
86
+ *
87
+ * Default when omitted: returns `[]`.
88
+ */
89
+ getLaunchConfigs?(dirPath: string): LaunchConfig[] | Promise<LaunchConfig[]>;
90
+ /**
91
+ * Persist the full list of launch configs for a project.
92
+ *
93
+ * Default when omitted: silently no-ops.
94
+ */
95
+ saveLaunchConfigs?(dirPath: string, configs: LaunchConfig[]): void | Promise<void>;
96
+ /**
97
+ * Read the active launch config id for a project.
98
+ *
99
+ * Default when omitted: returns `null` (normal mode).
100
+ */
101
+ getActiveLaunchConfigId?(dirPath: string): string | null | Promise<string | null>;
102
+ /**
103
+ * Persist the active launch config id for a project.
104
+ *
105
+ * Default when omitted: silently no-ops.
106
+ */
107
+ saveActiveLaunchConfigId?(dirPath: string, id: string | null): void | Promise<void>;
84
108
  }
85
109
  /** Built-in template policy. */
86
110
  export type BuiltinTemplatesMode = 'all' | 'none' | readonly string[];
@@ -91,7 +91,7 @@ export function createRenderInspector(options = {}) {
91
91
  if (!(await ensureInjected(wc)))
92
92
  return null;
93
93
  try {
94
- const result = await wc.executeJavaScript('window.__diminaRenderInspect ? window.__diminaRenderInspect.getWxml() : null');
94
+ const result = (await wc.executeJavaScript('window.__diminaRenderInspect ? window.__diminaRenderInspect.getWxml() : null'));
95
95
  return result ?? null;
96
96
  }
97
97
  catch {
@@ -105,7 +105,7 @@ export function createRenderInspector(options = {}) {
105
105
  return null;
106
106
  let inspection;
107
107
  try {
108
- const result = await wc.executeJavaScript(`window.__diminaRenderInspect ? window.__diminaRenderInspect.highlightElement(${JSON.stringify(sid)}) : null`);
108
+ const result = (await wc.executeJavaScript(`window.__diminaRenderInspect ? window.__diminaRenderInspect.highlightElement(${JSON.stringify(sid)}) : null`));
109
109
  inspection = result ?? null;
110
110
  }
111
111
  catch {
@@ -149,11 +149,11 @@ export function createRenderInspector(options = {}) {
149
149
  return;
150
150
  const expression = `window.__diminaRenderInspect && window.__diminaRenderInspect.elementFor(${JSON.stringify(sid)})`;
151
151
  try {
152
- const evaluated = await wc.debugger.sendCommand('Runtime.evaluate', {
152
+ const evaluated = (await wc.debugger.sendCommand('Runtime.evaluate', {
153
153
  expression,
154
154
  returnByValue: false,
155
155
  objectGroup: HOVER_OBJECT_GROUP,
156
- });
156
+ }));
157
157
  const objectId = evaluated?.result?.objectId;
158
158
  if (!objectId)
159
159
  return;
@@ -1,4 +1,4 @@
1
- import type { AppInfo, CompileConfig, ProjectSession } from '../../../shared/types.js';
1
+ import type { AppInfo, CompileConfig, LaunchConfig, ProjectSession } from '../../../shared/types.js';
2
2
  import type { WorkbenchContext } from '../workbench-context.js';
3
3
  import type { Project, ProjectPages, ProjectSettings } from '../projects/project-repository.js';
4
4
  /**
@@ -57,6 +57,10 @@ export interface WorkspaceService {
57
57
  saveCompileConfig(projectPath: string, config: CompileConfig): Promise<void>;
58
58
  getProjectSettings(projectPath: string): ProjectSettings;
59
59
  updateProjectSettings(projectPath: string, patch: Partial<ProjectSettings>): void;
60
+ getLaunchConfigs(projectPath: string): Promise<LaunchConfig[]>;
61
+ saveLaunchConfigs(projectPath: string, configs: LaunchConfig[]): Promise<void>;
62
+ getActiveLaunchConfigId(projectPath: string): Promise<string | null>;
63
+ saveActiveLaunchConfigId(projectPath: string, id: string | null): Promise<void>;
60
64
  }
61
65
  /** Build a workspace service bound to the given workbench context. */
62
66
  export declare function createWorkspaceService(ctx: WorkbenchContext): WorkspaceService;