Plugin marketplace client implementation
## Summary
Adds plugin marketplace support to Duo CLI, compatible with the existing plugin
marketplace ecosystem. Users can register third-party marketplaces (git repos or local
directories) and install plugins from them. Plugins bundle skills initially, with agents,
slash commands, hooks, MCP servers and other plugin artifacts to follow.
## Approach
We follow the established plugin ecosystem's on-disk semantics, so existing community
marketplaces work with Duo CLI unmodified:
- Marketplace catalogs read from `marketplace.json` or `.claude-plugin/marketplace.json`
- Plugin manifests from `plugin.json` or `.claude-plugin/plugin.json`
- Lifecycle behaviour (install/enable/disable/uninstall, cascade on marketplace removal,
cache left for GC) follows established ecosystem conventions
- Symlink and trust boundary behaviour preserved
## Command surface
```
duo plugin marketplace add <source> # git URL or local directory
duo plugin marketplace list
duo plugin marketplace remove <name> # cascade-uninstalls its plugins
duo plugin install <plugin@marketplace> [--scope user|project|local]
duo plugin list
duo plugin enable|disable <plugin>
duo plugin uninstall <plugin>
```
Commands are hidden from the CLI reference until the feature is usable end to end.
## On-disk model
User-facing configuration (records which plugins are enabled per scope):
```
<duoConfigDir>/plugins.json # user scope (e.g. ~/.config/gitlab/duo)
<workspace>/.gitlab/duo/plugins.json # project scope (committable)
<workspace>/.gitlab/duo/plugins.local.json # local scope (gitignored)
```
Internal state, managed by the CLI (not user facing):
```
<duoConfigDir>/known_marketplaces.json # registered marketplaces
<duoConfigDir>/installed_plugins.json # install ledger
<duoConfigDir>/marketplaces/<name>/ # catalog copies (git metadata stripped)
<duoConfigDir>/plugins/<mkt>/<plugin>/<version>/ # shared version-keyed plugin cache
```
Install copies plugin files from the marketplace catalog into the shared cache
(containment-checked, atomic stage-then-rename) and records them in the scope's ledger.
Uninstall drops records but leaves the cache. A cache manager self-heals missing files
and garbage-collects unused versions after 14 days.
epic