Allow scope plugins to declare an optional icon for UI display
## Description Follow-up to: #3586220 ### Summary Scope plugins are shown in several places across `ai_context` (and will likely appear in more over time). Today, when an icon is shown at all, it is hard-coded in the view layer — e.g. `AiContextItemViewBuilder::SCOPE_ICON_CLASSES` for the context item **Details** sidebar — with a generic funnel fallback for unknown plugins. This issue adds an **optional, plugin-level icon** on `AiContextScope` plugins so each scope can define a consistent visual identity wherever that plugin is rendered, without patching core mappings. ### Problem / motivation - Custom/contrib scopes cannot supply their own icon; they always fall back to the default. - Icon mapping lives in presentation code instead of plugin metadata — poor DX and easy to drift. - New core scopes require editing PHP maps in addition to the plugin class. - As scope plugins appear in more UIs, duplicating icon logic per screen does not scale. ### Where scope plugins are (or may be) shown Icons should be resolved from **plugin metadata**, not per-screen hard-coding. Known / likely consumers: | Location | Today | |----------|--------| | Context item full view — Details sidebar | Hard-coded map + default | | Context item edit form — per-scope fieldsets | Label only | | Context item form — scope summary | Text only | | Agent settings — scope subscriptions / context items table | Text only | | Scope settings — overview + per-plugin tabs | Label only | | Revision diff / other admin summaries | Text only | | Future listings, dashboards, selection debug UI | N/A | **This issue defines the API and central resolution.** Individual UIs can adopt icons incrementally; the first consumer may remain the Details panel from #3586220 work. ### Proposed solution 1. **Extend `#[AiContextScope]`** (and/or plugin definition via `hook_ai_context_scope_info_alter()`) with an optional icon field, e.g.: - `icon: 'briefcase'` — logical icon id, **or** - `icon_class: 'ai-icon--scope-use-case'` — explicit CSS class. 2. **Central resolver** (small service or method on `AiContextScopeManager`): - Plugin-declared icon if set - Existing built-in map for core scopes (BC) - Fallback: `ai-icon--scope-default` 3. **Rendering contract** — expose something UI-agnostic, e.g.: - `getIconClass(): string` on `AiContextScopeInterface`, or - render array fragment (`#icon_class`, optional `#icon_url`) for Twig/forms. 4. **Assets** — continue using local Phosphor SVGs + `.ai-icon--scope-*` CSS. Contrib modules may ship their own SVG + library, or register a class via alter hook (exact contrib asset story TBD in implementation). 5. **Documentation** in `docs/developers/custom_scopes.md`: - How to declare an icon - Resolution order and fallback - How to use icons in custom UI that lists scope plugins ### Scope **In scope** - Plugin metadata + alter hook support - Central icon resolution API - BC for existing plugins (no attribute → unchanged behavior) - Tests for resolution order - Docs for extenders - Wire-up of **at least one** consumer (likely Details panel) as proof of API **Out of scope (follow-ups)** - Icons on every UI surface in one MR - Arbitrary uploaded / remote icons - Per-value icons (icon is per **scope plugin**, not per selected value) - Icon pickers in scope settings forms ### Acceptance criteria - [ ] Scope plugin can optionally declare an icon in plugin metadata. - [ ] `hook_ai_context_scope_info_alter()` can set/override icon. - [ ] Single resolver returns icon class (or equivalent) for any plugin instance. - [ ] Existing core scopes render unchanged without attribute updates. - [ ] Unknown/contrib plugins without an icon use the default fallback. - [ ] At least one UI uses the resolver (Details panel acceptable for v1). - [ ] Tests cover: declared icon, core BC map, default fallback, alter override. - [ ] Developer docs updated with API + example. ### Technical notes - Current Details implementation: `AiContextItemViewBuilder::getScopeIconClass()` + `icons/scope/*.svg`. - `ai_context_test_scope` is a good manual QA plugin for custom icon behavior. - Prefer resolver on manager/service over scattering maps in form builders, view builders, and derivers. ### Related - Context item full view / Details panel (#3586220) - Custom scopes: `docs/developers/custom_scopes.md` ## AI usage - [x] AI assisted issue - [ ] AI generated code
issue