test(plugins): cover _discover_all_plugins recursion + cross-link loader
Add a TestDiscoverAllPlugins class covering the six cases the recursive scan needs to handle: - flat plugin uses its manifest ``name:`` as the key - category-namespaced plugin keys off ``<category>/<dirname>`` even when the manifest ``name:`` is bare (regression test for the original bug — ``plugins/observability/langfuse/`` with ``name: langfuse`` must surface as ``observability/langfuse``, not ``langfuse``) - user-installed plugin overrides bundled on key collision - depth cap: anything below ``<root>/<category>/<plugin>/`` is ignored - bundled ``memory/`` and ``context_engine/`` are skipped (they have their own loaders), but user plugins under those category names are still scanned Also add an in-source comment next to the key derivation pointing at the loader's matching line (``PluginManager._parse_manifest`` in plugins.py:1027-1028), so future renames of one site flag the other. Both items raised in Copilot review on #27161. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -761,6 +761,11 @@ def _discover_all_plugins() -> list:
|
||||
description = manifest.get("description", "")
|
||||
except Exception:
|
||||
pass
|
||||
# Path-derived key, intentionally ignoring the manifest
|
||||
# ``name:`` field for category-namespaced plugins — mirrors
|
||||
# ``PluginManager._parse_manifest`` in plugins.py:1027-1028
|
||||
# so renaming a directory (without touching plugin.yaml) shifts
|
||||
# the registry key in both places consistently.
|
||||
key = f"{prefix}/{d.name}" if prefix else manifest_name
|
||||
src_label = source
|
||||
if source == "user" and (d / ".git").exists():
|
||||
|
||||
Reference in New Issue
Block a user