Files
kandev/docs/decisions/2026-07-31-plugin-repository-provider-extensions.md
T

82 lines
4.6 KiB
Markdown

# ADR-2026-07-31-plugin-repository-provider-extensions: Plugin Repository Provider Extensions
**Status:** accepted
**Date:** 2026-07-31
**Area:** frontend, backend, protocol
## Context
Kandev task creation, Link menus, and review panels contain provider-specific GitHub/
GitLab assumptions. A connector plugin must contribute repository discovery, pull-
request actions, and native review UI without adding a Bitbucket branch or leaving
mobile as a compressed desktop-only escape hatch.
## Decision
The frontend plugin registry gains revocable, manifest-owned registrations for:
- `registerRepositoryProvider(...)` with repository listing, URL matching, branch
listing, and credential-free `inspectURL` descriptors whose clone URL is HTTPS;
- `registerTaskAction(...)` for children of the existing **Link** submenu, with
visibility and an async handler receiving read-only current
workspace/task/repository context;
- `registerReviewProvider(...)` with normalized task-item summaries, external-store
`getSnapshot`/`subscribe`/cancellable `refresh`, and a plugin-owned `ReviewPanel`.
The frontend author boundary is the independently consumable, runtime-free
`@kandev/plugin-sdk` package. It exposes named provider/review/UI contracts and a
typed `host.context` read service. Private Zustand `AppState` access remains only as
legacy runtime compatibility and is not part of the public SDK; official and new
plugins must request provider-neutral context additions instead of copying host store
shapes.
Registration icon fields accept either a backwards-compatible curated host icon
name or a plugin-owned component rendered through the supplied host React runtime.
Provider brand glyphs belong to the provider plugin, so adding another code host
does not require a brand import or lookup-table edit in Kandev production code.
Repository URL ownership is established by cancellable, workspace-scoped structured
inspection. `matchesURL` is optional and only narrows candidates; `inspectURL` returns
`null` when the configured provider does not own the URL. The host rejects multiple
successful inspectors as ambiguous rather than selecting registration order. This is
required for overlapping self-hosted URL shapes.
Providers have unique active ownership, are removed on plugin disable/unload, and
abort their in-flight work. Activation is transactional: a failed or timed-out
`initialize` revokes partial registrations and fences late callbacks from restoring
them. The host adapts GitHub, GitLab, and Azure implementations to the same contracts.
It accepts a complete plugin-inspected provider descriptor, including an exact
credential-free HTTPS clone URL, rather than parsing plugin provider URLs.
Task link actions render in existing desktop and visible mobile menus. A generic
top-level `action` placement is deliberately deferred until Kandev has a host-owned
workflow contract for command eligibility, result handling, and review navigation;
accepting registrations with no consumer would be a false public API. Review panels use
provider-neutral IDs and params `{ providerId, reviewKey }`; legacy GitHub/GitLab
layout names remain aliases. The host's native desktop and mobile review surfaces own
navigation and placement, while the plugin owns provider data and rendering.
Task-link surfaces remain host-owned through `openTaskLinkDialog`; `openModal` remains
available for plugin-owned workflows but is not a substitute for native task actions.
Native review surfaces expose provider-neutral selection when
multiple built-in or plugin reviews exist instead of silently choosing the first.
Selections are revalidated by provider and review key after unload/reload, so a stale
same-ID provider instance cannot keep an obsolete item selected.
## Consequences
Repository providers and review actions become extensible without host provider
knowledge. Registry lifecycle and normalized item contracts are more deliberate, and
existing built-ins require adapter work. Plugin review components must tolerate host
selection, persistence, task switching, close, and mobile presentation changes.
Released frontend plugins compile against a semver contract instead of the host
application's private module graph.
## Alternatives Considered
- Hard-code Bitbucket alongside GitHub/GitLab: rejected because every new provider
would enlarge host provider unions and duplicate routing logic.
- Give plugins only a standalone route: rejected because it omits native Link and
review flows users already rely on.
- Register React hooks for reviews: rejected because plugin load/unload can violate
hook ordering; an external-store source is lifecycle-safe.