/** * Typed prop contracts for each slot id. * * Every slot consumer passes exactly the props defined here to each contribution * component. Plugins receive only the props for the slot they claim. * * NOTE: PluginContext is imported as a type-only forward reference so this * shared package doesn't depend on the runtime package. The runtime package * will re-export this map with the concrete PluginContext type filled in. */ import type { DashboardSession } from "../types.js"; import type { SlotId } from "./slot-types.js"; /** * Opaque marker type for PluginContext. * The concrete type is defined in @blackbelt-technology/dashboard-plugin-runtime/context. * Using `unknown` here keeps this shared types-only package free of runtime deps. */ export type AnyPluginContext = unknown; /** Folder descriptor passed to sidebar-folder-section slot. */ export interface FolderDescriptor { cwd: string; label?: string; } /** Map of slot id → props type for that slot's contributions. */ export interface SlotPropsMap { "sidebar-folder-section": { folder: FolderDescriptor; pluginContext: AnyPluginContext; }; "session-card-badge": { session: DashboardSession; pluginContext: AnyPluginContext; }; "session-card-action-bar": { session: DashboardSession; pluginContext: AnyPluginContext; }; "session-card-memory": { session: DashboardSession; pluginContext: AnyPluginContext; }; "session-card-flows": { session: DashboardSession; pluginContext: AnyPluginContext; }; "workspace-action-bar": { session: DashboardSession; pluginContext: AnyPluginContext; }; "content-view": { session: DashboardSession; routeParams: Record; onClose: () => void; pluginContext: AnyPluginContext; }; "content-header-sticky": { session: DashboardSession; pluginContext: AnyPluginContext; }; "content-inline-footer": { session: DashboardSession; pluginContext: AnyPluginContext; }; "anchored-popover": { anchorEl: HTMLElement; onDismiss: () => void; pluginContext: AnyPluginContext; }; "command-route": { session: DashboardSession; routeParams: Record; onClose: () => void; pluginContext: AnyPluginContext; }; "shell-overlay-route": { params: Record; /** DashboardSession metadata resolved from the URL’s session param (`config.sessionParam`, default `"sid"`). Undefined when the URL has no session id or no matching session. */ session?: DashboardSession; onBack: () => void; pluginContext: AnyPluginContext; }; "settings-section": { pluginContext: AnyPluginContext; }; "tool-renderer": { toolName: string; toolInput: Record; sessionId: string; pluginContext: AnyPluginContext; }; // Descriptor-only slots don't have React props (consumed by extension-ui-system) "management-modal": Record; "footer-segment": Record; "agent-metric": Record; "breadcrumb": Record; "gate": Record; "toast": Record; "rjsf-form": Record; } /** Get the props type for a specific slot id. */ export type SlotProps = SlotPropsMap[S]; // Type-level test: assert SlotPropsMap covers every SlotId. // This will produce a TS error if any SlotId is not in SlotPropsMap. type _AssertAllSlotsCovered = { [K in SlotId]: SlotPropsMap[K]; };