feat(plugins): plugin contract v2 and one provider registry

TH
2h ago
+2803-722

Summary

Part 1 of 4 of #3755 (umbrella #3747). Blocked by #3748: do not merge before it.

One plugin contract and one provider registry. Built-in providers, store plugins and (later) embedder plugins register through the same shape, in that order.

  • agent-device/plugins exports the type-only v2 contract: AgentDevicePluginFactory, { apiVersion: 2, provider, credentials, connection?, setup(host) }. { webDriver } stays a data descriptor.
  • A package's ./agent-device export is resolved with import conditions. The root export is used only when that subpath is absent. A throwing subpath never falls back.
  • v1 packages load through an adapter, dispatched by manifest before any factory runs.
  • A plugin that fails to load, validate or set up is recorded and skipped. The first registration of a provider id claims it; later ones fail with duplicate_provider. cloud and proxy stay reserved.
  • The inventory (active/failed, typed error.reason, credentials with byBackend) is published in daemon.json. The client fingerprint reads variable names from it and falls back to v1 manifests.
  • Retires RESERVED_PLUGIN_PROVIDERS and DEFAULT_PROVIDER_RUNTIME_REQUIRED_IDS; their consumers (provider policy, fingerprint, connect capabilities, daemon composition) move in this PR.
  • A v2 plugin declares connect capabilities in code, so the client loads the store (factories only, no setup) before reading them.

Also: a Limrun fingerprint now hashes untrimmed values, like the other providers. 59 files; ~3k gross lines, mostly the replaced loader and its tests.

Stack: this → feat/plugin-registry-v2-status (daemon status) → docs/ADR 0034 → @agent-device/testmu.

Validation

pnpm check:affected --run --head f8555c9010 (the stack top, which contains this layer): passed (exactCommit). Packed-types consumer type-check added to the installed-package test. CI owns integration, coverage and device lanes.

🤖 Generated with Claude Code