feat(runtime): isolate bundled miniapps behind bridge

This commit is contained in:
2026-08-06 00:19:36 +08:00
parent a68b7cf3bf
commit 58e77462ad
6 changed files with 280 additions and 28 deletions
+7 -19
View File
@@ -27,8 +27,6 @@ import { CapabilityAuditLog } from "@/runtime/capabilities/capability-audit";
import { CapabilityExecutor, type PickedFile } from "@/runtime/capabilities/capability-executor";
import { LineUpRuntime } from "@/runtime/coordination/lineup-runtime";
import { RuntimeAppHost } from "@/runtime/app-management/runtime-app-host";
import { TaskDashboardMiniApp } from "@/core-apps/task-dashboard/task-dashboard-miniapp";
import { WhiteboardMiniApp } from "@/core-apps/whiteboard/whiteboard-miniapp";
// Vite 的开发标记和 M4 测试控制器需要扩展浏览器的全局类型。
declare global {
@@ -131,12 +129,15 @@ const { messages, appSessions, loginView, chatView, presence, rendererContext, r
const surfaceHost = new IsolatedSurfaceHost(messages, {
ready(instanceID) { surfaceInstances.ready(instanceID, new Date().toISOString()); },
event(instanceID) { queueSurfaceCancel(instanceID); },
async request(instanceID, method, payload) {
return runtime.handleMiniAppBridgeRequest(instanceID, method, payload);
},
});
// These are the two shipped reference MiniApps. They are mounted through the
// same restricted SDK as any future bundled MiniApp; this adapter only wires
// lifecycle to the SDK object and never hands them Runtime internals.
const bundledMiniApps = new Map<string, { stop: () => void }>();
const bundledMiniApps = new Set<string>();
function reconcileBundledMiniApps(): void {
const active = new Set<string>();
for (const instance of runtime.lifecycle.instances.list(runtime.currentConversationID())) {
@@ -144,24 +145,11 @@ function reconcileBundledMiniApps(): void {
if (!["starting", "foreground", "background", "suspended"].includes(instance.state)) continue;
active.add(instance.instance_id);
if (bundledMiniApps.has(instance.instance_id)) continue;
try {
const sdk = runtime.openBundledMiniApp(instance.app_scope, instance.instance_id);
if (instance.app_scope === "task-dashboard") {
const miniapp = new TaskDashboardMiniApp(sdk);
miniapp.start();
bundledMiniApps.set(instance.instance_id, { stop: () => miniapp.stop() });
} else {
const miniapp = new WhiteboardMiniApp(sdk);
miniapp.start();
bundledMiniApps.set(instance.instance_id, { stop: () => { void miniapp.close(); } });
}
} catch (reason) {
console.warn("[LineUp Host] bundled MiniApp mount rejected", instance.instance_id, reason);
}
const receipt = runtime.openBundledSurface(instance.app_scope, instance.instance_id);
if (receipt.disposition === "accepted") bundledMiniApps.add(instance.instance_id);
}
for (const [instanceID, mounted] of bundledMiniApps) {
for (const instanceID of bundledMiniApps) {
if (active.has(instanceID)) continue;
mounted.stop();
bundledMiniApps.delete(instanceID);
}
}