feat(plugin): provider plugins declare option controls and receive option changes

A provider plugin reports `controls` and the `providerOptions` it runs in
`session.config`, and receives running-session changes as
`session.configure` `changes.providerOptions` (null returns a key to its
default), under the same apply-or-throw contract as built-in providers.
A control may declare a `defaultValue`; a value a plugin reports at that
default for a key nobody set stays unset instead of being pinned to the agent.

A plugin that still reports `settings` keeps working: the daemon reads each
setting as a control plus an option and sends changes in both shapes
(COMPAT(plugin-provider-settings)).

The app resolves a control's icon as a Lucide name when it is not one of the
built-in kebab-case names, so a plugin's icon shows live and in drafts.
Public docs and the provider-direct example use only `providerOptions` and
controls; the migration doc gains the rows.
This commit is contained in:
Mohamed Boudra
2026-11-05 20:25:11 +01:00
parent 152a5ae731
commit 448f258583
19 changed files with 519 additions and 183 deletions
+5
View File
@@ -25,6 +25,11 @@ function findLucideIcon(name: string): LucideIcon | null {
return isComponent(candidate) ? (candidate as LucideIcon) : null;
}
/** Whether `name` is a Lucide icon, so a caller can fall back before drawing nothing. */
export function isLucideIconName(name: string): boolean {
return findLucideIcon(name) !== null;
}
function isComponent(value: unknown): boolean {
return (
typeof value === "function" ||