Expand description
Per-plugin component + marketplace-manifest scan: the fast path
behind the Extensions page. Pure filesystem reads under the config
dir ($CLAUDE_CONFIG_DIR/~/.claude) and its plugins/ subtree,
settings.json included; no CLI call. The plugin registry
(installed_plugins.json) supplies installed-ness, version and the
auto-dependency marker; settings.json’s enabledPlugins the
enabled state; the marketplace manifests the latest version and LSP
server names; each plugin’s own manifest its declared component
paths.
Re-exports§
use std::collections::BTreeMap;🔒use std::path::Path;🔒use std::path::PathBuf;🔒use serde::Deserialize;🔒use serde::Deserialize;🔒use forge_primitives::plugins::MarketplaceHealth;🔒use forge_primitives::plugins::PluginComponents;🔒
Structs§
- DirComponents 🔒
- One plugin dir’s component inventory.
- Enabled
Map 🔒 - Extension
Scan - One combined disk scan: everything a refresh needs without a CLI spawn - registry-derived installed entries, manifest-derived available entries and marketplace sources, per-plugin component inventories, and per-marketplace health, over one shared manifest load so a failed manifest surfaces the same error on both halves.
- Known
Marketplace 🔒Entry - Known
Marketplaces 🔒 - Manifest
Plugin 🔒 - Manifests 🔒
- Every marketplace manifest readable under the clones root, keyed by (marketplace name, plugin name), plus per-marketplace load errors, read or parse, and which clones produced a readable manifest - the distinction a zero-plugin manifest needs to avoid reading as a cache-miss.
- Marketplace
Manifest 🔒 - Plugin
Manifest 🔒 - The component-path fields of
.claude-plugin/plugin.json. TheclaudeCLI resolves each as a string path or an array of paths, hooks and MCP servers additionally as inline objects. - Plugin
Registry 🔒 - Registry
Entry 🔒
Functions§
- declared_
paths 🔒 - The paths one manifest component key declares: a string is one path, an array a list; another shape warns and reads as undeclared.
- declared_
skill_ 🔒names - The skill names one declared path contributes: a dir with its own SKILL.md is one skill, another dir a container of skills, a file its stem.
- enabled_
plugins 🔒 enabledPluginsfromsettings.jsonbeside the plugins root; the CLI’s own enable state. An id absent from the map is enabled. An unreadable or unparseable settings file reads as all-enabled WITH a warning - the page must not silently flip every disabled plugin to Current.- hook_
trigger_ 🔒names - Hook trigger names over the default hooks/hooks.json plus whatever the manifest declares; a declaration adds sources, it never suppresses the default.
- install_
dir_ 🔒reason - The reason shown for a registered install whose dir is unusable. A vanished dir and an unreadable one point the reader at different remedies, so the row says which; an entry recording no path reads as the dir being missing.
- installed_
entries 🔒 - Installed entries derived from the registry and settings, the disk
mirror of
claude plugin list --json. One entry per registry record: a plugin installed in user AND project scope keeps both, like the CLI list does. - is_
regular_ 🔒file - Whether
pathis a regular file.Path::is_filefolds every stat error into “not there”, which reads a permission or io failure as an absent file; this reports it instead. - list_
md_ 🔒files - list_
subdirs 🔒 - manifest_
lsp_ 🔒servers - The manifest’s LSP servers as server key -> binary command; the command is what the PATH check tests, the key the fallback.
- manifest_
marketplace_ 🔒entries - Available entries derived from the manifests, the disk mirror of
claude plugin list --available --json. - marketplace_
health 🔒 - Per-marketplace health over the shared manifest load. A manifest the load could not read or parse surfaces its recorded error; one that loads but shows no plugins is healthy at zero.
- marketplace_
source_ 🔒entries - Configured marketplace sources derived from the registry, the disk
mirror of
claude plugin marketplace list --json. - mcp_
present 🔒 - Whether the plugin carries MCP config: the default
.mcp.json, plus whatever the manifest declares, an inline object counting as present. - md_
component_ 🔒names - Command or agent names: the manifest’s declaration replaces the conventional dir, whose undeclared entries then count nothing; each declared path is a dir of .md files or one file.
- newest_
plugin_ 🔒version - The newest version dir of a cache plugin, with its inventory. A dir
that cannot be read - its own
read_dir, or the stat of its manifest - stops the search: an older version’s inventory shown as this plugin’s own would be confidently wrong. Two arms fall through instead: a vanished dir, and a dir carrying no manifest, which is not a version dir at all. - plugin_
name 🔒 - plugins_
root - The plugins subtree of the config dir the
claudeCLI itself resolves:$CLAUDE_CONFIG_DIR, else$HOME/.claude. Both env reads are launch-directory-independent;Nonewhen neither resolves. - read_
component_ 🔒dir - Read the component parts of one plugin dir.
Erris an io error that stopped the dir being read - its ownread_dir, or for agateddir the stat of its.claude-plugin/plugin.json;Ok(None)when a gated dir carries no such manifest. Registered installs read ungated because the registry’s installPath is authoritative; clone sources read ungated because a marketplace source dir is a plugin by declaration. - read_
json 🔒 - Read and parse a JSON file. All three outcomes return
None, so the caller cannot tell them apart from the value; the warn carries the difference: a missing file is the expected fresh-install case and stays silent, while an unreadable or unparseable one warns with the reason. - read_
marketplace_ 🔒registry - The CLI’s marketplace registry (
known_marketplaces.jsonbeside the clones), read once for both the source entries and the health. A corrupt OR unreadable registry reads empty with its error carried back - the health rows must name it, not render the tab as an absence. Missing is the expected fresh-install case and stays silent. - read_
plugin_ 🔒manifest - The plugin’s own manifest, read for its declared component paths. Missing reads as undeclared in silence; unreadable or unparseable warns and reads as undeclared too.
- read_
registry 🔒 - Read the plugin registry. A missing file is the fresh install and reads as empty in silence; an unreadable or unparseable one warns with the reason and reads as empty too; the page renders identically either way, so the warn is the only place the difference shows.
- scan_
extensions - Scan the plugin cache and marketplace manifests into per-plugin
component inventories, one entry per plugin the registry, a
manifest or the cache knows about. Installed plugins scan their
registry
installPath; uninstalled ones their marketplace clone source. A registry entry with no readable install dir - gone, unreadable, or absent from the entry itself - emits a LoadFailed row carrying its reason rather than disappearing, and so does a marketplace whose manifest could not load. - version_
sort_ 🔒key - A version directory name’s numeric-aware sort key: numeric chunks order before and inside text chunks, so “10.0.0” outranks “9.9.9”.