* refactor(plugins): one resolver for plugin id -> directory
Five places mapped a plugin id to its directory, each with its own rules
and each re-reading manifests per lookup: PluginManager discovery and
get_plugin_directory, PluginLoader.find_plugin_directory,
PluginStoreManager._find_plugin_path / list_installed_plugins, and
state_reconciliation.disk_plugin_ids. They disagreed on backup dirs,
on whether the manifest id or the directory name is the id, on duplicate
ids and on path safety.
src/plugin_system/plugin_dirs.py now holds the rules once:
PluginDirectoryIndex scans one directory and reads each manifest once;
resolve_plugin_dir() searches directories in order. What legitimately
differs per caller is an explicit argument: search dirs (discovery and
the loader: configured dir only; the store: configured then sibling
plugins/), ledmatrix- prefix (not for the store), case folding (loader
only), manifest pass (not for get_plugin_directory, whose discovery map
already holds it).
Behaviour changes, all for layouts installs do not produce:
- a directory whose manifest declares the id beats one merely named for
it (discovery already worked this way; the loader and store now agree)
- the store searches the configured dir completely before plugins/
- backup and hidden dirs are skipped everywhere (the loader's case and
manifest scans and list_installed_plugins used to return them)
- duplicate ids resolve deterministically (exact name, then
ledmatrix-<id>, then by name) with a one-time warning; discovery no
longer lists the id twice
- disk_plugin_ids / list_installed_plugins report manifest ids, falling
back to the directory name; auto-update looks the directory up
- ids that are not one plain path segment resolve to nothing in every
caller (the loader used to truncate them, the store to join them)
The .standalone-backup- marker is one constant, BACKUP_MARKER, used by
store_manager's rename-aside names and every lookup.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* docs(changelog): one plugin-directory resolver
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>