import type { TemplateResult } from "lit"; import type { DeleteWorkspaceFileResponse, FileContentResponse, FileTreeResponse, JsonValue, MachineKind, MoveWorkspaceFileOptions, MoveWorkspaceFileResponse, PiWebStatusResponse, TerminalCommandRunHandle, WorkspaceProviderMetadata, WorkspaceRemovalPresentation, WriteWorkspaceFileOptions, WriteWorkspaceFileResponse } from "./shared/pluginApiTypes.js"; export type { FileContentMediaType, FileContentResponse, FileTreeEntry, FileTreeResponse, JsonObject, JsonPrimitive, JsonValue, MachineKind, PiWebComponentStatus, PiWebDockerMode, PiWebInstallationInfo, PiWebInstallationKind, PiWebReleaseStatus, PiWebServiceComponent, PiWebStatusMessage, PiWebStatusResponse, PiWebStatusSeverity, PiWebVersionResponse, TerminalCommandRun, TerminalCommandRunHandle, TerminalCommandRunStatus, WorkspaceProviderCapabilities, WorkspaceProviderMetadata, WorkspaceRemovalPresentation, WriteWorkspaceFileOptions, WriteWorkspaceFileResponse, DeleteWorkspaceFileResponse, MoveWorkspaceFileOptions, MoveWorkspaceFileResponse, } from "./shared/pluginApiTypes.js"; export type PluginId = string; export type LocalContributionId = string; export type QualifiedContributionId = string; export type HtmlTemplateTag = (strings: TemplateStringsArray, ...values: unknown[]) => TemplateResult; export type SvgTemplateTag = (strings: TemplateStringsArray, ...values: unknown[]) => TemplateResult; export interface PiWebPlugin { apiVersion: 2; name: string; activate: (context: PluginActivationContext) => PluginActivationResult; } /** Host-owned frozen values supplied once during browser plugin activation. */ export interface PluginActivationContext { readonly apiVersion: 2; /** Stable package/source identity, including on federated machines. */ readonly pluginId: PluginId; /** Host-unique identity for qualified contribution references in this runtime. */ readonly runtimePluginId: PluginId; readonly html: HtmlTemplateTag; readonly svg: SvgTemplateTag; } export interface PluginActivationResult { contributions: PluginContributions; } export interface PluginContributions { actions?: PluginAction[]; workspacePanels?: WorkspacePanelContribution[]; workspaceLabels?: WorkspaceLabelContribution[]; themes?: ThemeContribution[]; themePairs?: ThemePairContribution[]; } export interface PluginMachine { id: string; name: string; kind: MachineKind; } export interface PluginRuntimeState { /** Identity of the currently selected machine. Undefined only on older hosts or before machines load. */ selectedMachine?: PluginMachine; selectedWorkspace?: Workspace; selectedSession?: unknown; workspaceTool?: string; mainView?: string; piWebStatus?: PiWebStatusResponse; } export interface PluginPromptEditor { /** Insert text at the current cursor position. Replaces any selection. * If the editor is not focused, focuses it first. * No-op if the editor is not mounted. */ insertText(text: string): void; /** Get the current prompt text content. Returns "" if the editor is not mounted. */ getText(): string; /** Get the current selection range, or null if no selection or editor not mounted. */ getSelection(): { start: number; end: number; text: string; } | null; } export interface PluginRuntimeContext { state: PluginRuntimeState; prompt: PluginPromptEditor; openActionPalette: () => void; focusPrompt: () => void; addProject: () => void | Promise; configureAuth: () => void | Promise; logoutAuth: () => void | Promise; openThemePicker: () => void; selectMainView: (view: string) => void; selectWorkspaceTool: (tool: QualifiedContributionId) => void; openTerminal: (options?: { terminalId?: string | undefined; }) => void; refreshFiles: () => void | Promise; /** Invalidate plugin workspace-panel data for the selected workspace, optionally targeting one qualified panel id. */ refreshWorkspacePanels: (panelId?: QualifiedContributionId) => void | Promise; refreshAppData: () => void | Promise; /** Force a fresh PI WEB release check on the selected machine. Optional for compatibility with older hosts. */ checkForPiWebUpdates?: () => void | Promise; reloadPage: () => void; startSession: () => void | Promise; archiveSession: () => void | Promise; stopActiveWork: () => void | Promise; } export interface PluginAction { id: LocalContributionId; title: string; description?: string; shortcut?: string; /** Former qualified action ids whose saved shortcut preference should still apply. */ shortcutAliases?: QualifiedContributionId[]; group?: string; enabled?: (context: PluginRuntimeContext) => boolean; /** Explain why a disabled action is visible but unavailable. */ disabledReason?: (context: PluginRuntimeContext) => string | undefined; run: (context: PluginRuntimeContext) => void | Promise; } /** Host-resolved workspace snapshot exposed to browser plugin callbacks. */ export interface Workspace { readonly id: string; readonly projectId: string; readonly path: string; readonly label: string; readonly isMain: boolean; readonly provider?: WorkspaceProviderMetadata; readonly removal?: WorkspaceRemovalPresentation; } export interface WorkspaceFiles { /** Read a file from the workspace. Works for local and federated machines. */ readFile(path: string): Promise; /** List the entries of a workspace directory. Pass "" for the workspace root. * Works for local and federated machines. Rejects when the directory does not * exist or cannot be read, matching readFile error behavior. */ listFiles(path: string): Promise; /** Write content to a workspace file. Creates intermediate directories by default. * Works for local and federated machines. Auto-refreshes the file explorer after success. */ writeFile(path: string, content: string | Uint8Array, options?: WriteWorkspaceFileOptions): Promise; /** Delete a file from the workspace. Idempotent — returns { existed: false } if file doesn't exist. * Deletes the entry itself (for symlinks, removes the symlink not the target). */ deleteFile(path: string): Promise; /** Move or rename a file within the workspace. Unix mv semantics. * Default overwrite: false (safer than writeFile). Auto-refreshes the file explorer after success. */ moveFile(fromPath: string, toPath: string, options?: MoveWorkspaceFileOptions): Promise; } export type WorkspacePanelFiles = WorkspaceFiles; /** JSON-only request path to the server module that currently owns this workspace. */ export interface WorkspaceBackend { request(operation: string, input: JsonValue): Promise; } export interface WorkspaceHost { requestRender(): void; } export type WorkspacePanelHost = WorkspaceHost; export interface WorkspaceContext { machine: PluginMachine; workspace: Workspace; state?: PluginRuntimeState; files: WorkspaceFiles; /** Present only when this browser entry has a paired active server backend. */ backend?: WorkspaceBackend; host: WorkspaceHost; } export interface WorkspaceTerminalCommandInput { title: string; command: string; metadata?: Record; open?: boolean; } export interface WorkspacePanelTerminal { open(options?: { terminalId?: string | undefined; }): void; runCommand(input: WorkspaceTerminalCommandInput): Promise; } export interface WorkspacePanelContext extends WorkspaceContext { prompt: PluginPromptEditor; terminal: WorkspacePanelTerminal; } export type WorkspacePanelIcon = TemplateResult; export interface WorkspacePanelContribution { id: LocalContributionId; title: string; icon?: WorkspacePanelIcon; order?: number; /** Former URL tool/view values that should resolve to this panel. */ routeAliases?: string[]; visible?: (context: WorkspacePanelContext) => boolean; badge?: (context: WorkspacePanelContext) => string | number | TemplateResult | undefined; /** Called when the host invalidates workspace-panel data. */ onInvalidate?: (context: WorkspacePanelContext) => void | Promise; render: (context: WorkspacePanelContext) => TemplateResult; } export interface WorkspaceLabelContext extends WorkspaceContext { machine: PluginMachine; workspace: Workspace; state?: PluginRuntimeState; files: WorkspaceFiles; host: WorkspaceHost; } export type WorkspaceLabelItem = WorkspaceLabelTextItem | WorkspaceLabelLinkItem | WorkspaceLabelRenderItem; export interface WorkspaceLabelTextItem { type: "text"; text: string; title?: string; } export interface WorkspaceLabelLinkItem { type: "link"; text: string; href: string; title?: string; target?: "_blank" | "_self"; } export interface WorkspaceLabelRenderItem { type: "render"; render: () => TemplateResult; } export interface WorkspaceLabelContribution { id: LocalContributionId; order?: number; visible?: (context: WorkspaceLabelContext) => boolean; items: (context: WorkspaceLabelContext) => WorkspaceLabelItem[]; } export type ThemeColorScheme = "dark" | "light"; export type ThemeTokens = Record; export interface ThemeContribution { id: LocalContributionId; name: string; description?: string; order?: number; colorScheme: ThemeColorScheme; tokens: ThemeTokens; } export interface ThemePairContribution { id: LocalContributionId; name: string; description?: string; order?: number; light: LocalContributionId; dark: LocalContributionId; }