Documentation
¶
Overview ¶
Package extensions is a thin, read-mostly unification layer over the four existing extension surfaces in Overkill: skills, plugins, hooks, and MCP servers (Phase 1.5 #5).
Goals (kept deliberately small):
- One inventory view: List() returns everything the user can toggle, regardless of which backend owns it.
- One Enable/Disable verb: callers don't need to know which Registry to talk to.
- One status check: Get(id) returns Enabled/Source/Description.
Non-goals:
- Hot-reload coordination (each backend owns that — skills already has fsnotify, plugins doesn't, MCP relies on server lifecycle).
- Cross-backend dependencies / capability negotiation.
- Replacing the four backends — we ADAPT them, not rewrite them.
New backends register themselves with the Manager. The Manager has no knowledge of skill/plugin/hook semantics — it just delegates.
Index ¶
Constants ¶
This section is empty.
Variables ¶
var ErrNotFound = fmt.Errorf("extensions: not found")
ErrNotFound is returned by Manager.Get / Enable / Disable when no backend recognises the requested ID.
var ErrUnsupported = fmt.Errorf("extensions: operation unsupported by this backend")
ErrUnsupported is returned by Backend.Enable/Disable when the operation isn't supported for that backend (e.g. a directory-based extension that can't be toggled at runtime).
Functions ¶
This section is empty.
Types ¶
type Backend ¶
type Backend interface {
// Kind reports which extension family this backend serves.
Kind() Kind
// List returns the full inventory the backend knows about. Order
// is unimportant — Manager sorts the merged view.
List() ([]Extension, error)
// Get returns a single extension by ID, or ErrNotFound. Added
// in B138 to let Manager.Get do O(1) lookups instead of O(n)
// scanning List() results.
Get(id string) (*Extension, error)
// Enable / Disable toggle an extension by its (Kind, ID). When the
// backend doesn't support runtime toggling (e.g. hooks are
// directory-based), it returns ErrUnsupported. Callers surface
// that to the user instead of pretending the operation succeeded.
Enable(id string) error
Disable(id string) error
}
Backend is implemented by each of the four extension systems. Empty results mean no entries were discovered; inactive and unsupported entries are explicit.
type Extension ¶
type Extension struct {
Kind Kind `json:"kind"`
ID string `json:"id"` // unique within Kind
Name string `json:"name"` // display name
Description string `json:"description"` // one-liner
Source string `json:"source"` // bundled | user | remote | mcp-server-name
Enabled bool `json:"enabled"`
CanToggle bool `json:"can_toggle"`
ToggleScope string `json:"toggle_scope,omitempty"`
UnsupportedReason string `json:"unsupported_reason,omitempty"`
// Metadata is free-form per-backend payload (version, tags, etc.).
// Consumers (UI) shouldn't depend on specific keys — backend-specific
// detail belongs in dedicated dialogs.
Metadata map[string]string `json:"metadata,omitempty"`
}
Extension is the unified record returned by Manager.List/Get. Backends translate their native representations into this struct.
type HookFilesBackend ¶
type HookFilesBackend struct {
// contains filtered or unexported fields
}
HookFilesBackend lists scripts accepted by the production trusted-file loader. These files apply to newly constructed sessions, not a hidden dummy runtime.
func (*HookFilesBackend) Disable ¶
func (b *HookFilesBackend) Disable(id string) error
func (*HookFilesBackend) Enable ¶
func (b *HookFilesBackend) Enable(id string) error
func (*HookFilesBackend) Kind ¶
func (*HookFilesBackend) Kind() Kind
func (*HookFilesBackend) List ¶
func (b *HookFilesBackend) List() ([]Extension, error)
type HooksBackend ¶
type HooksBackend struct {
// contains filtered or unexported fields
}
HooksBackend retains disabled file-hook closures so enable restores the same trusted loader's execution checks. Built-in policy hooks remain owner-managed.
func NewHooksBackend ¶
func NewHooksBackend(reg *hooks.Registry) *HooksBackend
func (*HooksBackend) Disable ¶
func (b *HooksBackend) Disable(id string) error
func (*HooksBackend) Enable ¶
func (b *HooksBackend) Enable(id string) error
func (*HooksBackend) Kind ¶
func (*HooksBackend) Kind() Kind
func (*HooksBackend) List ¶
func (b *HooksBackend) List() ([]Extension, error)
type MCPBackend ¶
type MCPBackend struct {
// contains filtered or unexported fields
}
MCPBackend exposes configured servers plus supervised connection state, never command arguments or environment secrets. Per-server runtime toggles do not exist in mcp.Manager and are explicitly unsupported here.
func NewMCPBackend ¶
func NewMCPBackend(cfg config.MCPConfig, manager *mcp.Manager) *MCPBackend
func (*MCPBackend) Disable ¶
func (b *MCPBackend) Disable(id string) error
func (*MCPBackend) Enable ¶
func (b *MCPBackend) Enable(id string) error
func (*MCPBackend) Kind ¶
func (*MCPBackend) Kind() Kind
func (*MCPBackend) List ¶
func (b *MCPBackend) List() ([]Extension, error)
type Manager ¶
type Manager struct {
// contains filtered or unexported fields
}
Manager fans out to the registered backends. Safe for concurrent use.
func NewConfiguredManager ¶
NewConfiguredManager inventories configuration without starting executables. A session replaces the hook adapter with its actual executing registry; an API server replaces MCP with its supervised live manager.
func NewManager ¶
func NewManager() *Manager
NewManager returns an empty manager. Register backends with AddBackend before use.
func (*Manager) AddBackend ¶
AddBackend installs a backend. Calling twice with the same Kind REPLACES the prior backend (last-wins) so the wire-up can be reordered without panic. Nil backend is a no-op.
func (*Manager) Clone ¶
Clone shares backend owners while allowing a session to replace its hooks inventory without changing another session's executing registry.
func (*Manager) Enable ¶
Enable delegates to the backend for the given kind. ErrUnsupported bubbles up so the UI can surface "this kind of extension can't be toggled at runtime" instead of silently no-op'ing.
type PluginsBackend ¶
type PluginsBackend struct {
// contains filtered or unexported fields
}
PluginsBackend uses real discovery. The application has not connected a plugin process manager, so discovery is never presented as active execution.
func (*PluginsBackend) Disable ¶
func (b *PluginsBackend) Disable(id string) error
func (*PluginsBackend) Enable ¶
func (b *PluginsBackend) Enable(id string) error
func (*PluginsBackend) Kind ¶
func (*PluginsBackend) Kind() Kind
func (*PluginsBackend) List ¶
func (b *PluginsBackend) List() ([]Extension, error)
type SkillsBackend ¶
type SkillsBackend struct {
// contains filtered or unexported fields
}
SkillsBackend adapts the existing skills.Registry to the Backend interface. The registry already supports Enable/Disable/List so this is a thin translation layer.
func NewSkillsBackend ¶
func NewSkillsBackend(r *skills.Registry) *SkillsBackend
NewSkillsBackend wires a registry. Nil registry returns nil — the caller is expected to skip AddBackend when skills aren't configured.
func (*SkillsBackend) Disable ¶
func (b *SkillsBackend) Disable(id string) error
func (*SkillsBackend) Enable ¶
func (b *SkillsBackend) Enable(id string) error
func (*SkillsBackend) Kind ¶
func (b *SkillsBackend) Kind() Kind
func (*SkillsBackend) List ¶
func (b *SkillsBackend) List() ([]Extension, error)