diff options
Diffstat (limited to 'src/app')
| -rw-r--r-- | src/app/plugin-host.svelte.ts | 11 | ||||
| -rw-r--r-- | src/app/store.svelte.ts | 19 |
2 files changed, 28 insertions, 2 deletions
diff --git a/src/app/plugin-host.svelte.ts b/src/app/plugin-host.svelte.ts index 729a8aa..8054005 100644 --- a/src/app/plugin-host.svelte.ts +++ b/src/app/plugin-host.svelte.ts @@ -28,6 +28,7 @@ import { usablePluginIds, } from "../core/plugin-abi"; import { + type LayoutAbiPort, registerPluginView, unregisterViewsByPlugin, type ViewComponent, @@ -60,6 +61,12 @@ export interface PluginHostOptions { /** The ACTIVE workspace provider (read per sync — workspace.set trigger). */ readonly activeWorkspaceId: () => string; readonly surfaces: FrontendSurfacesPorts; + /** + * The layout port (plan 04 §4.5) — the ABI's `api.layout` (applyOps to the + * ACTIVE workspace's provider + getTree, null in no-provider mode). Built + * by the composition root over the layout store + ops HTTP edge. + */ + readonly layout: LayoutAbiPort; } export interface PluginHost { @@ -108,6 +115,10 @@ export function createPluginHost(opts: PluginHostOptions): PluginHost { info: (msg) => console.info(`[frontend-plugin:${pluginId}] ${msg}`), warn: (msg) => console.warn(`[frontend-plugin:${pluginId}] ${msg}`), }, + // plan 04 §4.5: the layout port — the composition-root-built adapter + // over the layout store + the ops HTTP edge (the plugin never sees + // either; only this typed port). + layout: opts.layout, }; } diff --git a/src/app/store.svelte.ts b/src/app/store.svelte.ts index 8a80160..c1d265f 100644 --- a/src/app/store.svelte.ts +++ b/src/app/store.svelte.ts @@ -84,7 +84,12 @@ import type { } from "../features/heartbeat"; import { normalizeHeartbeatConfig, normalizeHeartbeatRuns } from "../features/heartbeat"; import type { LayoutStore } from "../features/layout"; -import { createLayoutHttp, createLayoutStore, listPanelViews } from "../features/layout"; +import { + createLayoutAbiPort, + createLayoutHttp, + createLayoutStore, + listPanelViews, +} from "../features/layout"; import type { NamedAgent, NamedAgentDeleteResult, @@ -723,8 +728,9 @@ export function createAppStore(opts?: CreateAppStoreOptions): AppStore { // ephemeral, logged once, no error UI). Probes run on boot, on every // workspace switch, and on `extensions-changed` (§2.6); the one-way // localStorage migration (§2.7) arms on the boot probe. + const layoutHttp = createLayoutHttp(httpBase, fetchImpl); const layoutStore = createLayoutStore({ - http: createLayoutHttp(httpBase, fetchImpl), + http: layoutHttp, workspaceId: activeWorkspaceId, storage: localStorageOpt, knownViews: listPanelViews().map((v) => v.id), @@ -1417,6 +1423,15 @@ export function createAppStore(opts?: CreateAppStoreOptions): AppStore { invokeSurfaceOp(surfaceId, actionId, payload, conversationId), getSpec: (surfaceId) => surfaceSpecOp(surfaceId), }, + // plan 04 §4.5: the plugins' `api.layout` port — applyOps posts to the + // ACTIVE workspace's provider (the ops route) and feeds the returned + // tree back through the store (instant local echo; the WS broadcast is + // every client's authoritative copy); getTree exposes the active tree + // only while a provider is PRESENT (null = no-provider mode). + layout: createLayoutAbiPort({ + store: layoutStore, + postOps: (workspaceId, ops) => layoutHttp.postOps(workspaceId, ops), + }), }); const socketOpts: SurfaceSocketOptions = { |
