Utilities for building Delve plugins. This repository ships two packages that work together:
- Go module
github.com/PortableSheep/delve-sdkfor authoring plugin backends - npm package
@delve/plugin-sdkfor frontend command bridging
The sections below describe what each package provides today.
- The current Go SDK version is exposed as
sdk.Version(e.g.v0.5.0). Plugins should include this value in their registration payloads so the host can reject incompatible builds early. sdk.CompatibleHostRangedocuments the Delve host versions the SDK is tested with. Future releases will expand this range; treat it as the source of truth when shipping plugins.- JSON schema helpers
sdk.PluginManifestSchema()andsdk.LayoutSchema()are available for validatingplugin.jsonmanifests and persisted docking layout state. These are the same schemas the Delve host enforces at runtime.
- go-utility: Full-featured Go plugin with frontend
- theme: CSS theme plugin
- integration: API integration plugin
- dashboard: Data visualization plugin
customTemplate := &sdk.PluginTemplate{
Name: "custom-api",
Description: "Custom API integration template",
Type: "integration",
Language: "go",
Files: []sdk.TemplateFile{
{
Path: "main.go",
Template: true,
Content: "// Custom template content with {{.Variables}}",
},
},
Variables: map[string]interface{}{
"APIVersion": "v1",
},
}
enhancedSDK.Generator().RegisterTemplate(customTemplate)config := sdk.SDKConfig{
RegistryURL: "https://registry.delve.sh",
SecurityLevel: sdk.SecurityLevelMedium,
CacheEnabled: true,
DevMode: false,
LogLevel: sdk.LogLevelInfo,
CustomTemplates: map[string]*sdk.PluginTemplate{
"my-template": customTemplate,
},
}
sdk := sdk.NewEnhancedSDK(config)EnhancedSDK- Main SDK interfaceEnhancedPlugin- Enhanced plugin interface with lifecycle methodsSecurityManager- Handles security policies and sandboxingEnhancedRegistry- Advanced plugin registry with search and metadataSchemaValidator- Plugin configuration validationPluginGenerator- Template-based plugin generationDevTools- Development and build tools
SecurityLevel- Security level enumerationSecurityPolicy- Security policy configurationPermission- Permission request structureSandbox- Isolated execution environment
EnhancedPluginInfo- Complete plugin metadataRegistrySearchFilter- Advanced search filteringPluginMetrics- Usage and performance metrics
- Fork the repository
- Create a feature branch:
git checkout -b feature/amazing-feature - Commit your changes:
git commit -m 'Add amazing feature' - Push to the branch:
git push origin feature/amazing-feature - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
- Issues: GitHub Issues
Store a key-value pair in plugin storage.
Retrieve a value from plugin storage.
Delete a key from plugin storage.
List all keys in plugin storage.
Clear all plugin storage.
The heartbeat system provides robust connection monitoring:
- Plugin sends heartbeat every
intervalseconds - Host responds with heartbeat acknowledgment
- Plugin tracks last successful heartbeat response
- If no heartbeat response received within
timeout - Plugin logs timeout warning
- Calls
StateManager.SaveState()if configured - Plugin shuts down gracefully
- Prevents zombie processes when host crashes
- Saves plugin state before unexpected shutdown
- Reduces resource usage by cleaning up orphaned plugins
- Improves system stability
plugin, err := sdk.Start(pluginInfo)
if err != nil {
log.Printf("Failed to connect: %v", err)
// Handle connection failure
}err := plugin.SetItem("key", "value")
if err != nil {
log.Printf("Storage error: %v", err)
// Handle storage failure
}// Recommended for all production plugins
plugin.StartHeartbeat(30*time.Second, 60*time.Second)type MyPlugin struct {
importantData map[string]interface{}
configPath string
}
func (p *MyPlugin) SaveState() error {
// Save critical state that should survive restarts
return saveToFile(p.configPath, p.importantData)
}import (
"os"
"os/signal"
"syscall"
)
// Listen for OS signals
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
go func() {
<-sigChan
log.Println("Shutting down gracefully...")
plugin.Close()
os.Exit(0)
}()ctx, cancel := context.WithCancel(context.Background())
defer cancel()
go func() {
ticker := time.NewTicker(10 * time.Second)
defer ticker.Stop()
for {
select {
case <-ctx.Done():
return
case <-ticker.C:
// Do background work
}
}
}()plugin.Listen(func(messageType int, data []byte) {
log.Printf("Received message type %d: %s", messageType, string(data))
// Process message
})Plugins can extend the Delve UI with sidebar items and footer widgets, and update them live at runtime.
Helpers on Plugin:
SetUIContributions(c UIContributions)– replace all sidebar/footer entriesUpsertSidebarItem(item SidebarItem)– insert or replace a sidebar item and emit an updateUpsertFooterWidget(w FooterWidget)– insert or replace a footer widget and emit an updateSetFooterBadgeCount(identifier string, count int)– update a footer widget badge by ElementTag or Title
Minimal usage:
// During registration
pluginInfo := &sdk.RegisterRequest{
Name: "my-plugin",
Description: "Demo",
CustomElementTag: "my-plugin",
UiComponentPath: "frontend/component.js",
}
plugin, _ := sdk.Start(pluginInfo)
// Contribute a sidebar item and a footer icon
_ = plugin.SetUIContributions(sdk.UIContributions{
Sidebar: []sdk.SidebarItem{
{ Title: "My Plugin", ElementTag: "my-plugin", ComponentPath: "frontend/component.js", OnClickCommand: &sdk.CommandRef{ID: "my-plugin.open"} },
},
Footer: []sdk.FooterWidget{
{ Title: "My Plugin", Icon: "mdi:rocket", OnClickCommand: &sdk.CommandRef{ID: "my-plugin.open"} },
},
})
// Update badge later (e.g., unread count)
_ = plugin.SetFooterBadgeCount("My Plugin", 5)
// Default click handler returns an activation hint for the frontend
plugin.OnCommand("my-plugin.open", func(ctx context.Context, args []any) (any, error) {
return map[string]any{"activateUI": map[string]any{"plugin": "my-plugin", "tag": "my-plugin"}}, nil
})- Startup: Plugin connects and registers with host
- Running: Plugin processes messages and performs work
- Heartbeat: Regular health checks with host
- Shutdown: Graceful cleanup when connection lost or timeout
- State Save: Critical data persisted before exit
To make your plugin available through the Delve Plugin Registry:
- Create plugin.json with complete metadata including screenshots
- Add screenshots to a
screenshots/directory in your repository - Submit to registry via pull request
Directory Structure:
my-plugin/
├── plugin.json # Plugin metadata
├── main.go # Plugin source code
├── frontend/
│ └── component.js # Frontend component
├── screenshots/ # Plugin screenshots
├── overview.png
├── settings.png
└── features.png
Your plugin's frontend component should match the CustomElementTag:
// If CustomElementTag is "my-plugin"
class MyPlugin extends HTMLElement {
connectedCallback() {
this.innerHTML = '<h1>My Plugin UI</h1>';
}
}
customElements.define('my-plugin', MyPlugin);- Check host-config.yml has plugin enabled
- Verify plugin executable exists and is executable
- Check plugin registration logs
- Ensure host is running on correct WebSocket port
- Check firewall settings
- Verify --ws-port flag is passed correctly
- Check host system resources
- Adjust timeout values for slower systems
- Monitor network connectivity
- Verify StateManager interface implementation
- Check file permissions for state files
- Review error logs during shutdown
See example.go for a complete plugin implementation with:
- Heartbeat monitoring
- State management
- Background work
- Graceful shutdown
- Signal handling
- Go 1.19 or later
- Delve host application
- WebSocket support