Add plugin REST API, thv plugin CLI, and HTTP client (Phase 4)#5782
Add plugin REST API, thv plugin CLI, and HTTP client (Phase 4)#5782JAORMX wants to merge 4 commits into
Conversation
Expose the frozen PluginService interface over REST at /api/v1beta/plugins, add the thv plugin cobra command tree mirroring thv skill, and implement an HTTP client in pkg/plugins/client. Wire the plugin service into the API server with Claude Code and Codex materialization adapters, SQLite plugin store, and OCI registry client. The plugin info text output surfaces the executable surface inventory (hooks, commands, agents, skills) separately from declared-but-unmanaged components (mcpServers, lspServers) per the issue exit gate. Closes #5528
There was a problem hiding this comment.
Large PR Detected
This PR exceeds 1000 lines of changes and requires justification before it can be reviewed.
How to unblock this PR:
Add a section to your PR description with the following format:
## Large PR Justification
[Explain why this PR must be large, such as:]
- Generated code that cannot be split
- Large refactoring that must be atomic
- Multiple related changes that would break if separated
- Migration or data transformationAlternative:
Consider splitting this PR into smaller, focused changes (< 1000 lines each) for easier review and reduced risk.
See our Contributing Guidelines for more details.
This review will be automatically dismissed once you add the justification section.
The plugin store opens the same SQLite DB file as the skill store. TestNewServer_ReadTimeoutConfigured already injected a mock skill manager to avoid SQLITE_BUSY; it now also injects a mock plugin manager for the same reason.
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #5782 +/- ##
==========================================
+ Coverage 70.78% 70.85% +0.06%
==========================================
Files 684 686 +2
Lines 69353 69729 +376
==========================================
+ Hits 49091 49404 +313
- Misses 16654 16717 +63
Partials 3608 3608 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Large PR justification has been provided. Thank you!
|
✅ Large PR justification has been provided. The size review has been dismissed and this PR can now proceed with normal review. |
- Fix 'Declared (NOT managed):' to 'Declared (NOT managed by ToolHive):' per issue #5528 exit gate requirement - Delete parsePluginInstallClients (byte-identical to parseSkillInstallClients), call the existing parseSkillInstallClients instead - Replace custom sortedKeys generic with slices.Sorted(maps.Keys(m)) from Go stdlib
CodeQL false positivesThe CodeQL check reports 20 "Uncontrolled data used in path expression" ( Why they're false positivesThe taint flow is: REST API request → CodeQL can't see through the validation barrier, but the input is sanitized at multiple layers:
What's affectedAll 20 alerts are on pre-existing files from Phases 2-3 (not files changed by this PR):
This PR adds new REST API call paths that reach these existing functions, which is why CodeQL reports them as "new." ResolutionFollowing the established repo pattern (49 previously dismissed |
Summary
Exposes the frozen
PluginServiceinterface (Phases 2–3) over REST, CLI, and HTTP client — Phase 4 of the plugin lifecycle management effort (RFC THV-0077).This is a "mirror the skills system" change: the
PluginServiceinterface was already complete from Phases 2–3; this phase adds the exposure layer.Changes
REST API (
pkg/api/v1/plugins.go+plugins_types.go)/api/v1beta/plugins: list, install, uninstall, info, validate, build, push, builds, builds/remove, contentValidatePluginNameon path-param endpoints (uninstall, info)HTTP client (
pkg/plugins/client/)Clientimplementingplugins.PluginServiceover HTTPNewDefaultClient(env var → server discovery → default URL)ErrServerUnreachablesentinel errorvar _ plugins.PluginService = (*Client)(nil)CLI (
cmd/thv/app/plugin*.go)skill*.go: install, uninstall, list, info, validate, build, push, builds, builds/removeplugin infotext output surfaces the executable surface inventory (commands/agents/skills/hooks) separately from declared-but-unmanaged components (mcpServers/lspServers) with aDeclared (NOT managed):annotation — per the issue exit gateServer wiring (
pkg/api/server.go)pluginManagerfield onServerBuilderandServercreateDefaultPluginManagerblock: SQLite plugin store, OCI store, packager, registry client, Claude Code + Codex materialization adapters, group managerdevModePluginRegistryClientmirrors the skills dev-mode OCI registry dispatch/api/v1beta/plugins+ plugin store cleanupTests
pkg/api/v1/plugins_test.go— table-driven, all 10 handlers + JSON key assertions + edge cases (empty fields, group filter, nil-slice)pkg/plugins/client/client_test.go— all 10 methods viahttptest.Server+ connection error + URL encodingLarge PR Justification
This PR is large because it is a templated exposure layer — it mirrors the existing skills system (API + CLI + client) for plugins in a single atomic change. The 6700 lines break down as:
docs/server/docs.go,swagger.json,swagger.yaml) — auto-generated bytask docs, cannot be split or hand-edited.docs/cli/thv_plugin*.md) — auto-generated bytask docs.plugins_test.go+client_test.go) — test-only, exempt per contributing guidelines.skills.go,skill*.go,client.go); splitting them would produce non-functional partials (e.g., CLI commands without their server route, or an API handler without the client). The issue ([plugins] Phase 4: REST API + thv plugin CLI + content preview (THV-0077) #5528) explicitly scopes this as one deliverable.The change is purely additive — no existing files are modified in their logic (only
server.goandcommands.goget new wiring). Per.claude/rules/pr-creation.md: "Large PRs acceptable for: generated code, dependency updates, docs-only, test-only changes."Related Issues
Part of #5525 (Epic: Plugin lifecycle management)
Closes #5528 (Phase 4: REST API + thv plugin CLI + content preview)
Refs RFC PR stacklok/toolhive-rfcs#77
Testing
task build✅task test✅ (all unit tests pass)task lint-fix✅ (0 issues)task docs✅ (CLI docs + swagger regenerated)