Files
airi/docs
leafyy 3692652154 feat(plugin-sdk): add hosted Kit registration (#2687)
## Summary

This PR adds the registration foundation for Extension-hosted Kits. An
Extension can declare provided Kits in its manifest and fill those
declarations during root setup. The Host publishes the complete set only
after setup succeeds.

`KitProviderRegistry` now owns Kit identity, source composition,
generation numbers, transactions, and exact cleanup leases. Host
descriptors, Host Client factories, and Extension endpoints keep
separate payload models, while one slot per Kit ID enforces shared
ownership rules.

This is a registration-only phase. It does not add Consumer routing,
method calls, event delivery, permissions, remote transport, or
draining. Phase 2 is already part of `main`, so this PR is independent
rather than stacked.

## Change map

| Module | Before | After | Description |
| --- | --- | --- | --- |
| Kit authoring contract | Extensions could declare provided Kit
metadata, but had no typed runtime Contract or Provider endpoint |
`defineKitContract`, typed methods and events, exposure policies, and
exact Provider handlers | Keeps authoring data serializable and captures
caller-owned input before validation |
| Provider registry | Host descriptors and Client factories used
separate stores and ID-based cleanup | One `KitProviderRegistry` slot
union owns Host sources, Extension transactions, generations, tokens,
and leases | Centralizes collision, publication, snapshot, and
stale-cleanup policy |
| Extension Host lifecycle | Setup had no Provider transaction | Setup
reserves declarations, fills them through `ctx.kits.provide`, commits
atomically, and rolls back on failure | Makes pending Providers
invisible and ties cleanup to the Extension session |
| Built-in Kit runtime | Built-in Kits registered through separate
helper paths | One source list drives manifest declarations and exact
Host-source leases | Keeps declaration, registration, rollback, and
disposal order aligned |
| Examples and decisions | Activation Planner examples only covered
Host-provided Kits | Adds a registration-only hosted Provider example
and an ADR | Gives reviewers and Kit authors a runnable contract and the
ownership rationale |

## Architecture and behavior

The transaction is correlated by the globally unique Extension
`sessionId`. Private transaction tokens isolate pending slots and
rollback. Separate registration tokens isolate Provider handles and
leases after publication.

```mermaid
sequenceDiagram
  participant H as ExtensionHost
  participant R as KitProviderRegistry
  participant E as Extension setup

  H->>R: beginExtensionSession(owner, declarations)
  R-->>H: pending transaction
  H->>E: setup(ctx.kits.provide)
  E->>R: provide(contract, handlers)
  R-->>E: exact Provider handle

  alt setup succeeds and every declaration is filled
    H->>R: commit()
    R->>R: validate and build all ready records
    R->>R: publish all records synchronously
    R-->>H: Provider snapshots and session lease
  else setup or commit fails
    H->>R: rollback()
    R->>R: remove matching pending reservations
  end

  H->>R: session lease dispose before cleanup callbacks
  R->>R: withdraw only matching registration tokens
```

Changed behavior scenarios:

- `HK-1`: Host descriptor and Client factory sources can compose only
when Kit ID and exact version match.
- `EK-1`: Extension setup reserves every declared Provider before any
Extension code runs.
- `EK-2`: A successful commit publishes every Provider in one
synchronous operation.
- `EK-3`: Setup or commit failure rolls back pending reservations
without advancing generations.
- `EK-4`: Stop and reload withdraw the session lease before Extension
cleanup callbacks.
- `EK-5`: Stale handles and leases cannot remove replacement
registrations.

## Boundaries and risks

| Invariant or boundary | Failure mode | Protection | Evidence or gap |
| --- | --- | --- | --- |
| Caller-owned Contract and Provider input is not stored directly |
Getters, proxies, or later mutation change accepted state | Capture
external properties once, then validate and freeze accepted models |
Plugin SDK Contract and Provider registry tests |
| A multi-Kit session is visible as one unit | A partial Provider set
becomes ready | Pending slots plus a validation/build pass before the
synchronous publication pass | Provider registry transaction tests |
| Cleanup affects only its own registration | A stale handle removes a
reloaded Provider | Exact source, transaction, and registration tokens |
Stale handle, reload, and lease tests |
| Host descriptor and Client factory payloads stay distinct | A shared
ID silently combines incompatible versions or duplicate source kinds |
One slot checks exact version and rejects duplicate current sources |
Host source composition tests |
| Built-in runtime cleanup keeps dependencies valid | Runtime state is
destroyed while a Client factory remains available | Dispose Host leases
before destroying the built-in runtime, with reverse-order rollback on
install failure | Built-in Kit runtime tests |
| Consumer execution stays outside Phase 3 | Registration code starts
routing calls or events early | Public API stores endpoints but exposes
no invocation or event transport | Verified by diff and both Spec
reviews |

## Verification

```text
pnpm -F @proj-airi/plugin-sdk exec vitest run
# 15 files passed, 163 tests passed

pnpm exec vitest run apps/stage-tamagotchi/src/main/services/airi/plugins/index.test.ts
# 1 file passed, 66 tests passed

pnpm exec vitest run apps/stage-tamagotchi/src/main/services/airi/plugins/kits/index.test.ts
# 1 file passed, 5 tests passed

pnpm typecheck
# 52 tasks passed

pnpm lint
# 0 errors, 651 repository warnings

sem diff --staged --no-cosmetics -v --file-exts .ts .tsx
# Completed before each commit. No unresolved caller was found.

git diff --check upstream/main...HEAD
# Passed
```

The final fixed-range code reviews reported 0 Standards findings and 0
Spec findings. No visual evidence is needed because this PR changes
Plugin SDK contracts, main-process lifecycle code, tests, examples, and
documentation without changing user-visible UI.

## Rollout and follow-up

This PR has no migration or persisted-data change. Existing Host
descriptor inputs are intentionally validated more strictly, as recorded
in the ADR. Consumer routing, invocation, events, permissions,
transport, and draining remain separate follow-up work.
2026-10-26 11:15:38 +08:00
..
2025-06-16 01:52:54 +08:00

Please refer to README.md for the main documentation.