feat(plugin): plugin marketplace, durable install persistence, skill manager

Add an in-app plugin marketplace fed by a remote web catalog: the host
plugin-inventory gateway gains marketplaceList/Install/Uninstall remotes,
a durable per-user install table reconciled against the actual profile, and
git/npm/tarball/bundle install paths with non-interactive git and vendored
pnpm. The Web Settings surface gains a sibling 插件市场 tab that lists the
catalog with recommended badges, repository links, and a combined sort
(recommended first, then catalog priority, then id).

Add a host + client skill manager: list local skills by direct filesystem
discovery, and install/uninstall/toggle/edit their SKILL.md from git/npm/
tarball/local sources in the writable user root.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Pine
2026-08-15 17:01:48 +08:00
parent 5f348f9b1c
commit a53769955b
57 changed files with 5168 additions and 129 deletions
@@ -74,9 +74,11 @@ describe('ui-settings-plugin-inventory browser plugin', () => {
expect(b.slots.entries('settings.plugins.tab')).toHaveLength(0)
const stop = declare(b.slots)
await vi.waitFor(() => { expect(b.slots.entries('settings.plugins.tab')).toHaveLength(1) })
// The plugin registers two sibling tabs: the plugin list and the marketplace.
await vi.waitFor(() => { expect(b.slots.entries('settings.plugins.tab')).toHaveLength(2) })
b.locale.setLocale('en')
expect(resolveSlotLabel(b.slots.entries('settings.plugins.tab')[0]!.options.label)).toBe('Plugin list')
expect(resolveSlotLabel(b.slots.entries('settings.plugins.tab')[1]!.options.label)).toBe('Plugin marketplace')
stop()
expect(b.slots.entries('settings.plugins.tab')).toHaveLength(0)