Plugins v1#4421
Merged
Merged
Conversation
…plugins Rename IPluginConfigWriter to IIvyPluginConfig, add GetValue method and IIvyPluginConfigFactory. The PluginManagerApp now renders a schema-driven configuration form inline for each unconfigured plugin.
Plugins no longer access raw IConfiguration. Instead, the host provides an IIvyPluginConfigFactory and plugins read/write config via IIvyPluginConfig. Remove Microsoft.Extensions.Configuration dependency from Ivy.Plugin.Abstractions.
Adds a required Greeting field and optional Enthusiastic boolean. The greeter now uses these config values.
The framework calls SetPluginManager on the factory inside UsePlugins, so Save() can trigger ReconfigurePlugin.
Refactor PluginConfigurationView to accept pluginId + schema directly. Add GetPluginSchema to IPluginManager. Active plugins with a schema now display the config form inline.
- ExampleAppProviderPlugin provides a custom BuildConfigurationView - PluginManagerApp uses custom views when available, falls back to schema-driven form - Add BuildPluginConfigurationView to IPluginManager - Add default values to all config fields in both example plugins
Uses Stepper, Card, and Callout widgets for a radically different look from the default schema-driven form.
Footer menu item contribution is now handled by host apps (like Tendril) via their own extended plugin context, not the framework's generic interface.
…ent reloads Add Renamed event handlers to PluginWatcher, PluginReferencesWatcher so plugins are detected when editors atomically save via rename. Add per-plugin reload locking in PluginLoader to prevent concurrent reloads of the same plugin. Fix ScheduleLoad to skip if already in cooldown, and ScheduleReload to skip if a pending reload already exists rather than cancelling it.
- Make RemovePluginContributions virtual so subclasses can clean up their own contributions during plugin reload - Expose CurrentPluginId to subclasses so they can track which plugin is registering contributions - When reloading a plugin that failed its initial load, fall back to LoadPlugin instead of warning and giving up
Plugins can now define icons via PluginManifest.Icon using four kinds:
Named (built-in Icons enum), Svg (inline markup), Url (external), and
File (bundled asset served via /ivy/plugins/{id}/assets/{path}).
Adds asset-serving endpoint with path traversal protection and file
existence validation at plugin load time.
Adds SiLinear from react-icons/si and maps it in the Icon component.
Plugins can use Named, Url, or File icons. Inline SVG was unnecessary complexity given File already supports bundled .svg files.
Eliminates error-prone manual parsing in plugins by providing default interface methods that return null on failure, enabling safe ?? defaults.
This property was never read anywhere — it was redundant with Id and only added boilerplate for plugin authors.
The two loops in DiscoverAndLoad (subdirectories and references) had identical try/catch, validation, and failure-tracking code duplicated verbatim.
The menu transformers, badge providers, and app actions lists were mutated without locks while being read concurrently from the UI thread, racing with plugin reload writes in RemovePluginContributions.
Shadow directories under $TMPDIR/ivy-plugins/ were never cleaned up on unload, reload, load failure, or host exit. Track the shadow path in LoadedPlugin and delete it after AssemblyLoadContext.Unload(). Also clean up on early-return failure paths and register a ProcessExit handler as a safety net.
…ovider These were vestigial — ServiceProvider was only disposed and nulled out, never read. Service providers are fully managed by the aggregate provider in PluginContextBase.
Prevents potential handler leaks if lifetime management changes in the future.
…utation A mutable array exposed from a record contradicts the immutable design intent and allows callers to corrupt plugin configuration metadata.
Plugins can now ship external widgets — their assemblies are registered on load/reload and unregistered on unload so the frontend widget registry stays in sync with the loaded plugin set.
These were stored but never consumed. Now both app shells apply menu transformers (sorted by priority) and merge plugin badge providers into the sidebar display.
The method receives and returns a list, not appends an item. The new name makes the transformer pattern obvious at call sites.
Badge providers are a Tendril-specific feature (the framework's DefaultSidebarAppShell has no badge rendering). Keeping it in the framework interface was misleading.
SidebarMenu doesn't support per-item OnSelect handlers, so non-app menu items injected by transformers were non-functional. Plugins should use AddApp instead.
Replaces verbose object-initializer syntax with a chainable builder API (AddSecret, AddString, AddInteger, AddBoolean) that is more concise and readable.
Prevents plugins from using the old object-initializer pattern by making the constructor and Fields setter internal. Forces all schema construction through the fluent SchemaBuilder API.
zachwolfe
marked this pull request as ready for review
June 25, 2026 05:59
…exception types, use Path.Join, flatten nested if Addresses CodeQL and code-quality review comments on PR #4421 — generic catch clauses now use targeted exception types, Path.Combine replaced with Path.Join where input may be rooted, and nested conditionals simplified.
…ProjectReferences are available EnablePackageValidation's ValidatePackageTask needs ref assemblies from all transitive ProjectReferences (e.g. Ivy.Agent.Filter). With --no-build they weren't always produced.
zachwolfe
force-pushed
the
feat/plugin-config-custom-ui
branch
from
June 25, 2026 06:50
07fe159 to
065d212
Compare
…te suppression files On CI there's no parent Directory.Build.props setting Version, so it defaults to 1.0.0.0 which fails the CP0003 baseline check. Set Version=99.0.0 as fallback when unset on CI. Regenerate CompatibilitySuppressions.xml for intentional Plugins v1 API changes.
zachwolfe
force-pushed
the
feat/plugin-config-custom-ui
branch
from
June 25, 2026 06:56
065d212 to
aca0c9f
Compare
Collaborator
Staging removedStaging environment has been deleted for this PR. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
edit: This is now a companion PR to Ivy-Interactive/Ivy-Tendril#555 and the two should be merged at (around) the same time.