Skip to content

Plugins v1#4421

Merged
zachwolfe merged 63 commits into
developmentfrom
feat/plugin-config-custom-ui
Jun 25, 2026
Merged

Plugins v1#4421
zachwolfe merged 63 commits into
developmentfrom
feat/plugin-config-custom-ui

Conversation

@zachwolfe

@zachwolfe zachwolfe commented May 14, 2026

Copy link
Copy Markdown
Collaborator

edit: This is now a companion PR to Ivy-Interactive/Ivy-Tendril#555 and the two should be merged at (around) the same time.

zachwolfe added 11 commits May 14, 2026 03:53
…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.
@zachwolfe zachwolfe changed the title Plugin configuration custom UI Complete Plugins v1 May 16, 2026
@zachwolfe zachwolfe changed the title Complete Plugins v1 Finish Plugins v1 May 16, 2026
@zachwolfe zachwolfe changed the title Finish Plugins v1 Plugins v1 May 16, 2026
zachwolfe added 12 commits May 16, 2026 01:25
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.
Comment thread src/Ivy/Core/Plugins/PluginContext.cs Fixed
Comment thread src/Ivy/Core/Plugins/PluginContext.cs Fixed
Comment thread src/Ivy/Core/Plugins/PluginLoader.cs Fixed
zachwolfe added 2 commits May 29, 2026 01:01
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.
Comment thread src/Ivy/Core/Plugins/PluginLoader.cs Fixed
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.
Comment thread src/Ivy.Plugin.Abstractions/IIvyPluginConfig.cs Fixed
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.
Comment thread src/Ivy/Core/Plugins/PluginLoader.cs Fixed
Comment thread src/Ivy/Core/Plugins/PluginLoader.cs Fixed
zachwolfe added 10 commits June 19, 2026 01:07
…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
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
zachwolfe force-pushed the feat/plugin-config-custom-ui branch from 07fe159 to 065d212 Compare June 25, 2026 06:50
…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
zachwolfe force-pushed the feat/plugin-config-custom-ui branch from 065d212 to aca0c9f Compare June 25, 2026 06:56
@zachwolfe
zachwolfe merged commit 7ab12fc into development Jun 25, 2026
11 checks passed
@artem-ivy-ai

Copy link
Copy Markdown
Collaborator

Staging removed

Staging environment has been deleted for this PR.

@zachwolfe
zachwolfe deleted the feat/plugin-config-custom-ui branch June 25, 2026 07:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants