import type { Hooks, Plugin as ServerPluginFactory, PluginInput } from "@opencode-ai/plugin" import type { Fx } from "./common" import type { Loaded } from "./external" import type { Source } from "./spec" /** * Built-in server plugin that ships with the app and does not go through the external loader. */ export interface InternalPlugin { /** Stable id used for diagnostics and duplicate detection. */ readonly id: string /** Factory that creates one `Hooks` object when the plugin service starts. */ readonly plugin: ServerPluginFactory } /** * One successfully instantiated server plugin hook set. */ export interface HookEntry { /** Stable runtime id. */ readonly id: string /** Normalized spec that produced this hook set. */ readonly spec: string /** Whether the plugin came from npm, a file path, or built-in code. */ readonly source: Source | "internal" /** Hook handlers returned by the plugin factory. */ readonly hooks: Hooks } /** * Stateful data owned by the server plugin runtime per project/worktree instance. */ export interface State { /** Fully initialized hook sets in the order they should run. */ readonly loaded: readonly HookEntry[] /** Flat hook list kept for the existing trigger API. */ readonly hooks: readonly Hooks[] } /** * Hook names that follow the trigger pattern `(input, output) => Promise`. */ export type TriggerName = { [Name in keyof Hooks]-?: NonNullable extends (input: infer _Input, output: infer _Output) => Promise ? Name : never }[keyof Hooks] /** * Input type for one triggerable hook name. */ export type TriggerInput = Parameters[Name]>[0] /** * Output accumulator type for one triggerable hook name. */ export type TriggerOutput = Parameters[Name]>[1] /** * Context assembled before any server plugins are instantiated. */ export interface RuntimeContext { /** Rich plugin input passed to every server plugin factory. */ readonly input: PluginInput /** Whether external plugins should be skipped because the runtime is in pure mode. */ readonly pure: boolean } /** * Stateless adapter that turns a loaded external module into one or more server hook sets. * * The return type is plural because legacy server modules can still expose multiple plugin factories. */ export type ApplyLoaded = (load: Loaded, input: PluginInput) => Fx /** * Public service surface for the server plugin runtime. * * The implementation would be backed by `InstanceState` because loaded hooks and bus subscriptions are * scoped to one project/worktree instance. */ export interface Interface { /** Ensure the per-instance plugin state has been initialized. */ readonly init: () => Fx /** Return the currently loaded hook objects. */ readonly list: () => Fx /** Trigger one hook name across loaded plugins while preserving plugin order. */ readonly trigger: ( name: Name, input: TriggerInput, output: TriggerOutput, ) => Fx> }