Marketplace sync: track plugin state per marketplace (final review I1)

Two marketplaces shipping a plugin of the same name shared one
"plugin:<key>" state record, so every sync reinstalled one copy and
reported it updated, and removing one marketplace never uninstalled its
copy. Plugin state ids are now "plugin:<slug>/<key>"; the slug and key
for an uninstall are derived from the id and re-validated. Older
"plugin:<key>" records are migrated using their recorded slug, so
existing installs are neither reinstalled nor orphaned. Reports keep
"plugin:<key>".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-09-27 10:07:57 -07:00
co-authored by Claude Opus 5.5
parent 2c1d6d8713
commit f2ebddd073
3 changed files with 182 additions and 18 deletions
@@ -252,7 +252,9 @@ installed last time, including the exact hook entries it inserted).
- Plugins: marketplace name `triple-c-<slug>`; copy the generated tree to
`~/.claude/triple-c/plugins/<slug>/`; `claude plugin marketplace add` it the first time, else
`claude plugin marketplace update triple-c-<slug>`; `install` newly selected, `uninstall`
removed; drop the marketplace registration when it has no plugins left.
removed; drop the marketplace registration when it has no plugins left. Plugin state is kept
per marketplace (`plugin:<slug>/<key>`), so two marketplaces may ship a plugin of the same
name; older `plugin:<key>` records are migrated using their recorded slug.
- Emits a report: `{installed, updated, removed, skipped: [{item, reason}], errors: [...]}`.
**Failure handling.** A sync failure never fails the container start; it is logged, stored as the