core/plugin/bridge.go
Alex Dunmow 9e39119555 feat(abi): injection-complete capability surface — provisioner family, content authoring, 4 callback hooks (WO-WZ-019)
Dynamic families added to the ABI + guest SDK:
- provisioner.* (14 methods, 1:1 plugin.Provisioner): wasm provisioning was
  silently dead (RegisterWithProvisioner got a noopProvisioner and the cms
  loader ignored has_provisioner). Now a LOAD-TIME capability via the new
  CoreServices.Provisioner field; EnsureEmbed rejects RenderFunc-only embeds.
- content.* writes (content.Author + CoreServices.ContentAuthor):
  create_page, set_page_blocks, publish_page, set_page_seo, upsert_post.
- settings.update_plugin_settings (settings.Updater grows the method).
- bridge.invoke + plugin.BridgeInvokable: opaque-payload cross-plugin calls
  (typed GetService still returns nil across the sandbox by design).
- jobs.progress: HOOK_JOB handlers' progress() now crosses (was discarded).

New host→guest hooks: HOOK_AI_TOOL_CALL (executes recorded ai.ToolDefinition
handlers — registers tools in Register so every pooled instance has them),
HOOK_BRIDGE_CALL, HOOK_DIRECTORY_PANEL_SECTION, HOOK_DIRECTORY_PIN_DECORATOR.
The ai/bridge stubs now record handlers/values locally in addition to
forwarding names.

buf breaking clean (additive within ABI major 1); golden round-trips added
for the new families (cms host replays the same goldens).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 10:02:21 +08:00

43 lines
1.6 KiB
Go

package plugin
import "context"
// PluginBridge allows plugins to share services with each other.
// Plugins register named services during startup; other plugins look them up at runtime.
//
// In-process (bundled) plugins can share typed Go values via
// RegisterService/GetService. Across the wasm sandbox a typed value cannot
// cross, so cross-plugin calls go through Invoke instead: the provider's
// service implements BridgeInvokable and the consumer calls Invoke with an
// opaque payload (JSON by convention). GetService still reports availability
// only (nil) for wasm consumers.
type PluginBridge interface {
RegisterService(pluginName, serviceName string, service any)
GetService(pluginName, serviceName string) any
// Invoke calls a method on another plugin's registered bridge service.
// The provider answers via its BridgeInvokable implementation (bundled)
// or the BRIDGE_CALL hook (wasm).
Invoke(ctx context.Context, pluginName, serviceName, method string, payload []byte) ([]byte, error)
}
// BridgeInvokable is implemented by bridge service values that support
// method-by-name invocation with opaque payloads, making them callable from
// other plugins across the wasm sandbox boundary.
type BridgeInvokable interface {
InvokeBridge(ctx context.Context, method string, payload []byte) ([]byte, error)
}
// GetServiceAs retrieves a typed service from the bridge.
func GetServiceAs[T any](bridge PluginBridge, pluginName, serviceName string) (T, bool) {
var zero T
if bridge == nil {
return zero, false
}
svc := bridge.GetService(pluginName, serviceName)
if svc == nil {
return zero, false
}
typed, ok := svc.(T)
return typed, ok
}