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