import { ComponentType, LazyExoticComponent } from 'react'; import { Disposable, DisposableCollection } from './disposable'; import { CoreEventMap } from './event-bus'; import { NavItem } from '../hooks/shell/useNavRegistry'; import { FooterItem } from '../hooks/shell/useFooterRegistry'; export type ActivationEvent = { type: 'eager'; } | { type: 'onRoute'; pattern: string; } | { type: 'onCommand'; commandId: string; } | { type: 'onEvent'; eventType: string; }; export interface ExtensionPointDeclaration { id: string; description?: string; } /** Base fields shared by all contribution items. */ export interface ContributionBase { id: string; pluginId: string; order?: number; visible?: boolean; } /** Navigation item contribution (extends existing NavItem). */ export type NavContribution = NavItem & { pluginId: string; }; /** Footer item contribution (extends existing FooterItem). */ export type FooterContribution = FooterItem & { pluginId: string; }; /** Command palette command contribution. */ export interface CommandContribution extends ContributionBase { label: string; description?: string; icon?: ComponentType<{ className?: string; }>; keywords?: string[]; shortcut?: string; section?: string; /** Context expression for when this command is available, e.g. "route:/vibecontrols/*" */ when?: string; execute: () => void | Promise; } /** Route contribution — plugin-owned page. */ export interface RouteContribution extends ContributionBase { path: string; component: LazyExoticComponent> | ComponentType; /** Which API gateway this route's data comes from. */ gateway?: 'workspace' | 'global'; /** Layout mode for the route. */ layout?: 'default' | 'full' | 'none'; } /** Panel props passed to panel components. */ export interface PanelProps { panelId: string; visible: boolean; onClose: () => void; } /** Panel/view contribution. */ export interface PanelContribution extends ContributionBase { title: string; icon?: ComponentType<{ className?: string; }>; position: 'bottom' | 'left' | 'right'; component: ComponentType; /** Default size in pixels. */ defaultSize?: number; minSize?: number; maxSize?: number; defaultVisible?: boolean; } /** Status bar item contribution. */ export interface StatusBarContribution extends ContributionBase { section: 'left' | 'center' | 'right'; priority: number; component: ComponentType>; tooltip?: string; onClick?: () => void; } /** Settings page/section contribution. */ export interface SettingsContribution extends ContributionBase { category: string; label: string; icon?: ComponentType<{ className?: string; }>; component: ComponentType>; } /** Dashboard widget contribution. */ export interface WidgetContribution extends ContributionBase { title: string; description?: string; icon?: ComponentType<{ className?: string; }>; component: ComponentType<{ widgetId: string; }>; defaultSize: { cols: number; rows: number; }; minSize?: { cols: number; rows: number; }; maxSize?: { cols: number; rows: number; }; category?: string; } /** Header toolbar item contribution. */ export interface ToolbarContribution extends ContributionBase { position: 'left' | 'center' | 'right'; component: ComponentType>; tooltip?: string; } /** Context menu item. */ export interface ContextMenuItem { id: string; label: string; icon?: ComponentType<{ className?: string; }>; shortcut?: string; disabled?: boolean; execute: () => void; } /** Context menu contribution. */ export interface ContextMenuContribution extends ContributionBase { /** Target element/zone this menu attaches to. */ target: string; items: ContextMenuItem[]; } export interface PluginContributions { nav?: NavContribution[]; footer?: FooterContribution[]; commands?: CommandContribution[]; routes?: RouteContribution[]; panels?: PanelContribution[]; statusBar?: StatusBarContribution[]; settings?: SettingsContribution[]; widgets?: WidgetContribution[]; toolbar?: ToolbarContribution[]; contextMenus?: ContextMenuContribution[]; } export interface UIPluginManifest { id: string; name: string; version: string; description?: string; dependencies?: string[]; activationEvents?: ActivationEvent[]; contributes?: PluginContributions; extensionPoints?: ExtensionPointDeclaration[]; } export interface RegistryAPI { register(item: T): Disposable; unregister(id: string): void; getAll(): T[]; getByPlugin(pluginId: string): T[]; } export type ToastType = 'info' | 'success' | 'warning' | 'error'; export interface PluginContext { pluginId: string; nav: { register(items: NavContribution | NavContribution[]): Disposable; unregister(id: string): void; }; footer: { register(items: FooterContribution | FooterContribution[]): Disposable; unregister(id: string): void; }; commands: RegistryAPI; routes: RegistryAPI; panels: RegistryAPI; statusBar: RegistryAPI; settings: RegistryAPI; widgets: RegistryAPI; toolbar: RegistryAPI; contextMenus: RegistryAPI; events: { on(event: K, handler: (payload: CoreEventMap[K]) => void): Disposable; on(event: string, handler: (payload: unknown) => void): Disposable; once(event: K, handler: (payload: CoreEventMap[K]) => void): Disposable; once(event: string, handler: (payload: unknown) => void): Disposable; emit(event: K, payload: CoreEventMap[K]): void; emit(event: string, payload: unknown): void; }; subscriptions: DisposableCollection; shell: { navigate(path: string): void; showToast(message: string, type?: ToastType): void; getActiveContext(): { workspaceId?: string; tenantId?: string; projectId?: string; }; /** * Returns the active user identity. Bearer tokens are intentionally * redacted (`token` is always `undefined`) — plugins must use shell * gateway clients for authenticated requests, not read tokens here. */ getAuth(): { user?: unknown; token?: undefined; }; getTheme(): { colorMode: 'light' | 'dark'; }; }; } export interface UIPlugin { manifest: UIPluginManifest; activate(context: PluginContext): void | Promise; deactivate?(): void | Promise; } export type PluginStatus = 'pending' | 'activating' | 'active' | 'error'; //# sourceMappingURL=types.d.ts.map