c53f699714
- go plugin backends ship as release tarballs (per-platform binaries, checksums) that kandev installs from url/upload or filesystem sideload+sync, then spawns and supervises via hashicorp/go-plugin (unix socket / loopback tcp+automtls) - strict typed grpc contract (kandev.plugin.v1): DeliverEvent/InvokeTool/HandleWebhook plus a capability-gated host service (state, secrets, emit); author sdk in pkg/pluginsdk; packaging cli in cmd/plugin-pack - native frontend bundles: window.registerKandevPlugin + registry/host loader with dynamic routes, nav items, slots and ws handlers; plugins settings page with install dialog, sync button and enable/disable/uninstall - gated behind the plugins feature flag (prod off, dev/e2e on); covered by unit and integration tests plus playwright e2e against a real packaged fixture plugin Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
49 lines
1.6 KiB
Go
49 lines
1.6 KiB
Go
package plugins
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/kandev/kandev/pkg/pluginsdk"
|
|
)
|
|
|
|
// DefaultToolTimeout bounds a single agent tool invocation
|
|
// (Service.InvokeTool), per docs/specs/plugins/spec.md ("Agent tool
|
|
// invocation").
|
|
const DefaultToolTimeout = 30 * time.Second
|
|
|
|
// InvokeTool routes a tool call to id's live subprocess via the runtime
|
|
// manager's RemotePlugin.InvokeTool RPC, applying DefaultToolTimeout on top
|
|
// of ctx. Returns an error if id has no live process (not active, or
|
|
// mid-restart).
|
|
func (s *Service) InvokeTool(ctx context.Context, id string, req *pluginsdk.ToolRequest) (*pluginsdk.ToolResponse, error) {
|
|
remote, ok := s.pluginRemote(id)
|
|
if !ok {
|
|
return nil, fmt.Errorf("plugins: plugin %q is not running", id)
|
|
}
|
|
reqCtx, cancel := context.WithTimeout(ctx, DefaultToolTimeout)
|
|
defer cancel()
|
|
return remote.InvokeTool(reqCtx, req)
|
|
}
|
|
|
|
// InvokeWebhook routes an inbound webhook to id's live subprocess via the
|
|
// runtime manager's RemotePlugin.HandleWebhook RPC. Used by
|
|
// POST/GET /api/plugins/:id/webhooks/:key.
|
|
func (s *Service) InvokeWebhook(ctx context.Context, id string, req *pluginsdk.WebhookRequest) (*pluginsdk.WebhookResponse, error) {
|
|
remote, ok := s.pluginRemote(id)
|
|
if !ok {
|
|
return nil, fmt.Errorf("plugins: plugin %q is not running", id)
|
|
}
|
|
return remote.HandleWebhook(ctx, req)
|
|
}
|
|
|
|
// pluginRemote returns the live RemotePlugin for id, if the runtime manager
|
|
// is wired and currently tracking a running process for it.
|
|
func (s *Service) pluginRemote(id string) (*pluginsdk.RemotePlugin, bool) {
|
|
if s.runtime == nil {
|
|
return nil, false
|
|
}
|
|
return s.runtime.Get(id)
|
|
}
|