* fix(plugins): web mode lookups use the modes the display registered (#668)
A plugin may compute its display modes from its config: soccer-scoreboard
registers soccer_<league>_live/recent/upcoming for every custom_leagues
entry, which no manifest can list ahead of time. The display always rotated
them (_register_loaded_plugin prefers plugin.modes), but the web process
reads plugins as files, so /display/modes, the on-demand dialog and
on-demand/start with a mode and no plugin_id saw only manifests -- a custom
league's mode was missing from every list and 404'd on lookup.
- PluginStateManager.record_modes(): the controller records what it
registered, on the loaded record (an unload or reload forgets it)
- the runtime snapshot carries it per plugin as "modes" (bounded), and
PluginRuntimeView.display_modes() reports it only while live
- PluginCatalog takes a runtime_source; get_plugin_display_modes and
find_plugin_for_mode prefer the live modes, falling back to the manifest
when the display is stopped or has not loaded the plugin. The view is read
at most once a second, so a listing is one read, not one per plugin.
No manifest or plugin change needed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(plugins): call the runtime view's display_modes directly
Codacy flagged the getattr/callable indirection as 'lookup is not callable'.
The view is a PluginRuntimeView or None; anything else raises inside the
existing try and falls back to the manifest.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(plugins): address review -- no manifest fallback for live plugins, keep mode names whole, send registered spelling
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>