Install and update pinned whatever the marketplace head was when the
click landed, so a background refresh between review and click could
pin content nobody saw (including a hook's shell commands).
install_marketplace_item and update_marketplace_item now take
expected_commit and refuse with "changed since you reviewed this item —
review it again" unless it is still the head. The UI passes the head the
selected item was read at (Browse), the head frozen with a pending hook
confirm (whose commands are frozen too), and the head of the accepted
diff (Installed).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- The import preview counts global plugin installs and warns on them:
a plugin can bring hooks and MCP servers into every container and an
imported install skips the confirm step, like a hook.
- Item keys, hosts and branches in errors are quoted with {:?} and
capped, since they can come from an import file.
- After an import, caches and snapshots of marketplaces the import
dropped are removed (under the repo lock) and pins are refreshed for
the imported installs.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The 21 marketplace commands, registered and granted; marketplace fields
kept store-owned in update_settings/update_project; a background refresh
of every marketplace at app start.
- apply_marketplace_now emits marketplace-sync-finished per project (F4).
- Settings export carries marketplace account tokens in ExportedSecrets
(account id -> token) and import restores them; imported accounts,
marketplaces and global installs are validated with the commands' own
rules before anything is written. The import preview discloses the
marketplace count, token count and global hook installs, and warns on
the latter (F10).
- refresh_pins and cache removal hold the repo lock (F11).
- ops::validate_host/validate_branch delegate to auth::valid_host and
git::valid_branch (F13).
- A finished gh container login frees only its own cancel slot.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>