Documentation
¶
Overview ¶
Package plugin is the host side of the connector plugin platform: it spawns connector subprocesses on demand, hands out live gRPC clients, and reaps idle ones.
Index ¶
- func BuildModule(mod connector.Module, getConn ConnGetter) connector.Module
- func DefaultDir() string
- func ExtractArchive(archive, destBase string) (string, error)
- func InstallFromDir(srcDir, destRoot string) error
- func InstallFromURL(ctx context.Context, url, destRoot string) error
- func InstallFromURLProgress(ctx context.Context, url, destRoot string, onProgress ProgressFunc) error
- func ManifestFromZipBytes(data []byte) (*wickplugin.Manifest, error)
- func MarshalCatalog(entries []Available) ([]byte, error)
- func ResolveSource(ctx context.Context, src string) (string, func(), error)
- func RunDir() string
- func VersionNewer(a, b string) bool
- type Available
- type Catalog
- type ConnGetter
- type Found
- type GHAsset
- type GHRelease
- type Lease
- type Manager
- func (m *Manager) Client(key string) (*Lease, error)
- func (m *Manager) IsPlugin(key string) bool
- func (m *Manager) KillAll()
- func (m *Manager) RemoveBinary(key string)
- func (m *Manager) ResolveIdentity(ctx context.Context, key, token string) (string, string, error)
- func (m *Manager) SetBinary(key, path string)
- func (m *Manager) WarmUp()
- type ManifestFetcher
- type Phase
- type Progress
- type ProgressFunc
- type Reloader
- type StateStore
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func BuildModule ¶
func BuildModule(mod connector.Module, getConn ConnGetter) connector.Module
BuildModule wires a parsed connector.Module's operations to gRPC closures that dispatch to the plugin subprocess. The host engine (service.Execute) calls these closures exactly like in-proc ops — same pattern as custom-MCP. The envelope parsing and verification happen in the loader before this is called.
func DefaultDir ¶
func DefaultDir() string
DefaultDir is the runtime location wick scans for installed connector plugins: <appDataDir>/plugins/connectors, overridable with WICK_PLUGINS_DIR. It matches the layout `make plugins` writes to.
func ExtractArchive ¶
ExtractArchive extracts a .tar.gz or .zip into destBase and returns the directory that holds plugin.json (the archive root or its single subdir).
func InstallFromDir ¶
InstallFromDir verifies the {binary, plugin.json} in srcDir and copies them into destRoot/<key>/. The manifest's sha256 + signature are checked against the binary BEFORE anything is written, so an unverified plugin never lands in the plugins dir.
func InstallFromURL ¶
InstallFromURL downloads an archive (zip or tar.gz) from url, extracts it, verifies the manifest, and installs into destRoot. Used by the marketplace install action and `<app> plugin install <url|name>`.
func InstallFromURLProgress ¶ added in v0.28.5
func InstallFromURLProgress(ctx context.Context, url, destRoot string, onProgress ProgressFunc) error
InstallFromURLProgress is InstallFromURL with staged progress reporting. The archive lands in a temp dir first; the on-disk plugin is only touched in the Replacing phase, so a failed download/verify never disturbs the existing install (download-succeeds-then-replace).
func ManifestFromZipBytes ¶ added in v0.27.0
func ManifestFromZipBytes(data []byte) (*wickplugin.Manifest, error)
ManifestFromZipBytes reads and parses plugin.json from a plugin release zip's raw bytes. Shared by the live fetcher and by tests (which build zips in-mem).
func MarshalCatalog ¶ added in v0.27.0
MarshalCatalog renders the catalog as the pretty JSON written to plugins/plugins.json (2-space indent, trailing newline) for a stable diff.
func ResolveSource ¶
ResolveSource turns a path / url / archive into a directory containing {binary, plugin.json}, returning the dir and a cleanup func. A bare existing directory is returned as-is.
func RunDir ¶
func RunDir() string
RunDir is where wick pins plugin Unix sockets: <appDataDir>/run, overridable with WICK_PLUGIN_SOCKET_DIR. go-plugin creates the socket under here (0700) instead of the OS temp dir.
func VersionNewer ¶ added in v0.27.2
VersionNewer reports whether catalog version a is strictly newer than the installed version b, by semver. Versions may be bare ("1.4.2") or "v"-prefixed; both are normalized. Unparseable versions fall back to a plain string != comparison so a malformed tag still surfaces *some* update hint rather than silently hiding one.
Types ¶
type Available ¶
type Available struct {
Key string `json:"key"`
Name string `json:"name"`
Description string `json:"description"`
Version string `json:"version"`
// DefaultTags are the plugin's Meta.DefaultTags, carried verbatim from the
// released manifest — the SAME []entity.DefaultTag a built-in connector
// declares. The app derives the category from them with connectorCategory,
// exactly as for built-ins, so a plugin groups under its real category.
DefaultTags []entity.DefaultTag `json:"default_tags,omitempty"`
// Assets maps "<goos>/<goarch>" → direct download URL of the release zip.
Assets map[string]string `json:"assets"`
}
Available is one installable connector surfaced by the catalog.
Key vs Name mirrors connector.Meta: Key is the slug (= source folder = zip name = install dir = registry key — the one identity used for matching and install); Name is the free display string shown in the UI. Older catalog entries that only have "name" are tolerated: parseCatalog backfills Key from Name when Key is absent.
func BuildCatalog ¶ added in v0.27.0
func BuildCatalog(releases []GHRelease, fetchManifest ManifestFetcher) []Available
BuildCatalog folds releases into one Available entry per plugin key (the tag prefix before "/v"), keeping the highest semver version, and maps each zip asset to its os/arch download URL. When fetchManifest is non-nil it is used to lift Meta.Name / Meta.Description from the chosen release's first asset; failures there are non-fatal (the entry keeps key-derived defaults).
Tag convention: plugin releases are tagged "<key>/v<version>"; core wick releases ("v<version>", no slash) are ignored.
type Catalog ¶
type Catalog struct {
// contains filtered or unexported fields
}
Catalog discovers connector plugins that are AVAILABLE to install from a single curated JSON file checked into the wick repo's default branch (raw.githubusercontent.com/yogasw/wick/master/plugins/plugins.json).
This is deliberately NOT the GitHub Releases API: listing is a plain raw-file fetch, so it never hits the API rate limit and needs no token. The JSON carries, per plugin, the direct release download URL for each os/arch — the binary is pulled from the GitHub Release only when the user clicks Download.
func DefaultRegistry ¶
func DefaultRegistry() *Catalog
DefaultRegistry builds a Catalog from env overrides:
WICK_PLUGIN_CATALOG full URL to plugins.json (default: wick repo master, plugins/plugins.json)
Named DefaultRegistry for call-site compatibility with the earlier API.
type ConnGetter ¶
ConnGetter returns a lease on a live plugin connection for a connector key. The manager's Client method satisfies it; tests pass a fake.
type Found ¶
type Found struct {
Key string
BinaryPath string
Manifest wickplugin.Manifest
}
Found is one discovered plugin: its key, on-disk binary, and parsed manifest envelope.
type GHRelease ¶ added in v0.27.0
GHRelease is the slice of a GitHub release this needs. Decode the `GET /repos/{owner}/{repo}/releases` response into []GHRelease.
type Lease ¶
type Lease struct {
Conn wickplugin.GRPCConn
// contains filtered or unexported fields
}
Lease is a borrowed plugin connection. Release MUST be called exactly once (the adapter does so via defer) so the Manager can account for in-flight calls and free the subprocess for eviction.
type Manager ¶
type Manager struct {
// contains filtered or unexported fields
}
Manager owns connector plugin subprocesses keyed by connector Meta.Key.
func Load ¶
Load scans dir, builds a Manager over the discovered binaries, registers each plugin module via connectors.Register (replace-by-key so a plugin overrides the compiled-in builtin of the same key), and returns the Manager (caller owns its KillAll on shutdown). Returns a nil Manager when no plugins are present. When enabled is non-nil, keys for which it returns false are excluded from the Manager (not spawnable) and not registered; a nil enabled treats all discovered plugins as enabled.
func NewManager ¶
NewManager builds a Manager and starts the idle sweeper.
func (*Manager) Client ¶
Client returns a lease on a live gRPC connection for key, spawning the subprocess on first use (lazy) and re-spawning if a previous process died. Release the lease when the call completes.
func (*Manager) KillAll ¶
func (m *Manager) KillAll()
KillAll reaps every subprocess (call on app shutdown). It is safe to call more than once: the stop channel is closed at most once.
func (*Manager) RemoveBinary ¶
RemoveBinary drops a connector key and kills its running subprocess (if any).
func (*Manager) ResolveIdentity ¶
ResolveIdentity spawns-if-needed and asks the plugin to resolve an OAuth token's owner.
type ManifestFetcher ¶ added in v0.27.0
type ManifestFetcher func(zipURL string) (*wickplugin.Manifest, error)
ManifestFetcher reads a plugin.json out of a release zip given its download URL, returning the parsed manifest. Returns an error the caller may ignore (Name/Description backfill is best-effort). Injected so BuildCatalog stays testable without network.
type Phase ¶ added in v0.28.5
type Phase string
Phase names an install step, streamed to the caller so the UI can show a staged progress indicator instead of one opaque spinner.
type Progress ¶ added in v0.28.5
Progress is one install-progress update. Pct is the download percentage (0–100) and is only meaningful while Phase==PhaseDownloading and the server sent a Content-Length; it is -1 when the total size is unknown.
type ProgressFunc ¶ added in v0.28.5
type ProgressFunc func(Progress)
ProgressFunc receives install-progress updates. nil is allowed (no-op).
type Reloader ¶
type Reloader struct {
// contains filtered or unexported fields
}
Reloader watches the plugins dir and reconciles installed plugins into the running service without a restart. It polls on a fixed interval (no fsnotify dependency).
func NewReloader ¶
func NewReloader(dir string, svc moduleSink, mgr *Manager, interval time.Duration, store enabledChecker) *Reloader
NewReloader builds a Reloader. interval <= 0 defaults to 5s.
func (*Reloader) Reload ¶
Reload triggers an immediate reconcile (for in-process callers, e.g. CLI install).
type StateStore ¶
type StateStore struct {
// contains filtered or unexported fields
}
StateStore reads and writes the plugin enable/disable overlay.
func NewStateStore ¶
func NewStateStore(db *gorm.DB) *StateStore
NewStateStore wraps db. A nil db yields a store whose Enabled defaults to true.
func (*StateStore) Enabled ¶
func (s *StateStore) Enabled(key string) bool
Enabled reports whether key may be registered/spawned. Missing row or any error -> true (default-on; never hide a plugin because of a read error).
func (*StateStore) List ¶
func (s *StateStore) List() (map[string]bool, error)
List returns key -> enabled for all overlay rows.
func (*StateStore) SetEnabled ¶
func (s *StateStore) SetEnabled(key string, enabled bool) error
SetEnabled upserts the overlay row for key. A map is used so gorm writes the literal enabled value; a struct would let the `default:true` tag override a zero-value false on insert.