Documentation
¶
Index ¶
- Constants
- Variables
- func FormatList(plugins []LoadedPlugin, diagnostics []Diagnostic) string
- func MergedSkills(defaultDir string, pluginRoots []string) ([]skills.Skill, []skills.DuplicateName)
- func MergedSkillsLoaded(defaultDir string, pluginRoots []string) ([]skills.Skill, []skills.DuplicateName)
- func NewSkillTool(defaultDir string, pluginRoots []string) tools.Tool
- func ReadLock(dir string) (map[string]LockEntry, error)
- func Remove(dir string, id string) error
- func ResolvePluginPath(pluginDir string, value string, fieldPath string) (string, error)
- type ActivateOptions
- type ActivationResult
- type Diagnostic
- type DiagnosticKind
- type GitRunner
- type HookEvent
- type HookExtension
- type HookProvenance
- type InstallOptions
- type InstallResult
- type LoadOptions
- type LoadResult
- type LoadedPlugin
- type LockEntry
- type ManifestError
- type ParseManifestOptions
- type PathExtension
- type PluginAuthor
- type PluginInterface
- type ResolveRootOptions
- type Root
- type SkillProvenance
- type Source
- type ToolExtension
- type ToolPermission
- type ToolProvenance
Constants ¶
const LockFileName = "plugins.lock"
LockFileName maps an installed plugin id to its source and content hash.
Variables ¶
var ErrNameClash = errors.New("a different plugin with that id is already installed")
ErrNameClash is returned when an install would overwrite a plugin already installed from a DIFFERENT source, unless InstallOptions.Force is set.
Functions ¶
func FormatList ¶
func FormatList(plugins []LoadedPlugin, diagnostics []Diagnostic) string
func MergedSkills ¶
MergedSkills loads the default skills directory plus the supplied plugin skill roots and returns one merged, name-deduplicated list (Content stripped, like skills.List) alongside the duplicate-name collisions across all roots. Earlier roots win a name clash, matching skills.Load's first-wins rule; the default dir is always considered first so a user skill shadows a same-named plugin skill. A bad root simply yields no skills rather than failing the merge.
func MergedSkillsLoaded ¶
func MergedSkillsLoaded(defaultDir string, pluginRoots []string) ([]skills.Skill, []skills.DuplicateName)
MergedSkillsLoaded is MergedSkills but keeps each skill's Content (so the skill tool can return a body). MergedSkills strips Content for listing callers.
func NewSkillTool ¶
NewSkillTool builds the plugin-aware skill tool. defaultDir is the standard skills directory (skills.DefaultDir); pluginRoots are the plugin skill search roots from an ActivationResult. The returned tool merges both, deterministically deduplicating by name (default dir wins a clash) and listing all available skills when an unknown name is requested.
func ReadLock ¶
ReadLock loads the plugins lockfile from dir. A missing lockfile yields an empty map with no error.
Types ¶
type ActivateOptions ¶
type ActivateOptions struct {
// Cwd is the working directory plugin tool commands run in. Empty falls back to
// the plugin's own directory.
Cwd string
// Timeout bounds each plugin tool command. <= 0 uses defaultPluginToolTimeout.
Timeout time.Duration
// Env supplies the base environment for plugin tool commands. nil uses the
// current process environment (os.Environ()).
Env []string
// contains filtered or unexported fields
}
ActivateOptions configures activation. runTool is injectable for tests; when nil it defaults to executing the plugin command as a subprocess.
type ActivationResult ¶
type ActivationResult struct {
// Hooks are the live hook definitions built from plugin manifests, ready to be
// merged into the dispatcher's hook set. Order is deterministic.
Hooks []hooks.Definition
// SkillRoots are directories internal/skills.Load can scan to discover plugin
// skills, deduplicated and deterministically ordered.
SkillRoots []string
// Tools/HookProv/Skills carry provenance so a listing can attribute each live
// extension to its originating plugin.
Tools []ToolProvenance
HookProv []HookProvenance
Skills []SkillProvenance
// Warnings collects per-plugin/per-extension issues that caused an extension to
// be skipped. A single malformed plugin never aborts activation.
Warnings []string
}
ActivationResult reports what a single Activate call wired up. Tools are registered into the supplied registry directly; the remaining fields are returned for the caller (the agent bootstrap) to merge into the hook dispatcher and skills loader, and to surface provenance/warnings.
func Activate ¶
func Activate(registry *tools.Registry, loaded []LoadedPlugin, options ActivateOptions) ActivationResult
Activate turns the resolved plugin extensions into live registrations: it registers each plugin tool into registry, and returns the hook definitions and skill roots for the caller to wire into the dispatcher and skills loader.
Activation is isolation-first: a malformed plugin or extension is skipped with a recorded warning rather than aborting the whole activation, mirroring how skills.Load skips a bad skill. Plugins are processed in a deterministic order (sorted by ID) so the resulting registrations are stable across runs.
type Diagnostic ¶
type Diagnostic struct {
Kind DiagnosticKind `json:"kind"`
Message string `json:"message"`
Source Source `json:"source,omitempty"`
Root string `json:"root,omitempty"`
PluginPath string `json:"pluginPath,omitempty"`
ManifestPath string `json:"manifestPath,omitempty"`
FieldPath string `json:"fieldPath,omitempty"`
PluginID string `json:"pluginId,omitempty"`
}
type DiagnosticKind ¶
type DiagnosticKind string
const ( DiagnosticIO DiagnosticKind = "io" DiagnosticJSON DiagnosticKind = "json" DiagnosticSchema DiagnosticKind = "schema" DiagnosticDuplicate DiagnosticKind = "duplicate" )
type GitRunner ¶
GitRunner fetches the plugin at source into destination. The default runner shallow-clones with the system git (inheriting the process environment, so proxy/egress settings are honored). It is injectable so tests never hit the network. A runner must only fetch — it must never execute fetched content.
type HookExtension ¶
type HookProvenance ¶
HookProvenance records which plugin an activated hook originated from.
type InstallOptions ¶
type InstallOptions struct {
// Source is a git URL or a local filesystem path to a plugin directory (one
// that contains a plugin.json, or whose tree contains exactly one).
Source string
// Dir is the plugins directory to install into (typically the user plugins
// root from ResolveRoots).
Dir string
// Force allows overwriting a plugin installed from a different source.
Force bool
// GitRunner overrides the fetch implementation. When nil, a git source is
// shallow-cloned with the system git.
GitRunner GitRunner
}
InstallOptions configures a single plugin install.
type InstallResult ¶
type InstallResult struct {
ID string `json:"id"`
Name string `json:"name"`
Version string `json:"version"`
ManifestPath string `json:"manifestPath"`
Hash string `json:"hash"`
Source string `json:"source"`
Updated bool `json:"updated"`
PreviousHash string `json:"previousHash,omitempty"`
}
InstallResult reports what an install did.
func Install ¶
func Install(ctx context.Context, options InstallOptions) (InstallResult, error)
Install fetches the plugin at options.Source, validates its manifest, copies the plugin tree into options.Dir/<id>/, and records a content hash (over the manifest bytes) in the lockfile. Fetched content is never executed.
type LoadOptions ¶
type LoadResult ¶
type LoadResult struct {
Roots []Root `json:"roots"`
Plugins []LoadedPlugin `json:"plugins"`
Diagnostics []Diagnostic `json:"diagnostics"`
}
func Load ¶
func Load(options LoadOptions) (LoadResult, error)
type LoadedPlugin ¶
type LoadedPlugin struct {
SchemaVersion int `json:"schemaVersion"`
ID string `json:"id"`
Name string `json:"name"`
Version string `json:"version"`
Description string `json:"description,omitempty"`
Enabled bool `json:"enabled"`
Source Source `json:"source"`
Root string `json:"root"`
PluginDir string `json:"pluginDir"`
ManifestPath string `json:"manifestPath"`
Tools []ToolExtension `json:"tools"`
Prompts []PathExtension `json:"prompts"`
Skills []PathExtension `json:"skills"`
Hooks []HookExtension `json:"hooks"`
// Optional, additive metadata (omitempty so existing plugins are unchanged).
// Author/Interface are pointers: a non-pointer struct is never "empty" to
// encoding/json, so omitempty would still emit `author:{}` / `interface:{}`
// and change the serialized form of plugins that don't set them.
Author *PluginAuthor `json:"author,omitempty"`
License string `json:"license,omitempty"`
Keywords []string `json:"keywords,omitempty"`
Homepage string `json:"homepage,omitempty"`
Interface *PluginInterface `json:"interface,omitempty"`
}
func ParseManifest ¶
func ParseManifest(raw any, options ParseManifestOptions) (LoadedPlugin, error)
type ManifestError ¶
func (ManifestError) Error ¶
func (err ManifestError) Error() string
type ParseManifestOptions ¶
type PathExtension ¶
type PluginAuthor ¶
type PluginAuthor struct {
Name string `json:"name,omitempty"`
Email string `json:"email,omitempty"`
URL string `json:"url,omitempty"`
}
PluginAuthor is optional manifest authorship metadata. All fields are best-effort; missing values stay empty.
type PluginInterface ¶
type PluginInterface struct {
DisplayName string `json:"displayName,omitempty"`
Category string `json:"category,omitempty"`
BrandColor string `json:"brandColor,omitempty"`
DefaultPrompts []string `json:"defaultPrompts,omitempty"`
}
PluginInterface is optional presentation metadata describing how a plugin surfaces in a UI. All fields are optional and default to empty.
type ResolveRootOptions ¶
type Root ¶
func ResolveRoots ¶
func ResolveRoots(options ResolveRootOptions) ([]Root, error)
type SkillProvenance ¶
type SkillProvenance struct {
SkillName string `json:"skillName"`
Root string `json:"root"`
PluginID string `json:"pluginId"`
}
SkillProvenance records which plugin contributed a skill search root.
type ToolExtension ¶
type ToolPermission ¶
type ToolPermission string
const ( PermissionAllow ToolPermission = "allow" PermissionPrompt ToolPermission = "prompt" PermissionDeny ToolPermission = "deny" )
type ToolProvenance ¶
ToolProvenance records which plugin a registered tool originated from, for `zero plugin list` and debugging.