Initial commit: Elydora Go SDK
Go SDK for Elydora agent operations, cryptographic signing, and audit trail integration. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
commit
8916506ebc
26 files changed
+3381
No files matched your search
@@ -0,0 +1,161 @@
|
||||
package plugins
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// OpenCodePlugin manages the Elydora audit hook for OpenCode.
|
||||
// It writes .opencode/plugins/elydora-audit.js in the home directory.
|
||||
type OpenCodePlugin struct{}
|
||||
|
||||
func (p *OpenCodePlugin) configPath() (string, error) {
|
||||
home, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("resolve home directory: %w", err)
|
||||
}
|
||||
return filepath.Join(home, ".opencode", "plugins", "elydora-audit.js"), nil
|
||||
}
|
||||
|
||||
func (p *OpenCodePlugin) Install(config InstallConfig) error {
|
||||
scriptPath, err := hookScriptPath("opencode")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if config.HookScript != "" {
|
||||
scriptPath = config.HookScript
|
||||
}
|
||||
|
||||
if err := GenerateHookScript(scriptPath, config); err != nil {
|
||||
return fmt.Errorf("generate hook script: %w", err)
|
||||
}
|
||||
|
||||
guardPath := config.GuardScriptPath
|
||||
if guardPath == "" {
|
||||
guardPath, err = guardScriptPath("opencode")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
pluginFile, err := p.configPath()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dir := filepath.Dir(pluginFile)
|
||||
if err := os.MkdirAll(dir, 0755); err != nil {
|
||||
return fmt.Errorf("create directory %s: %w", dir, err)
|
||||
}
|
||||
|
||||
content := buildOpenCodePlugin(scriptPath, guardPath)
|
||||
if err := os.WriteFile(pluginFile, []byte(content), 0644); err != nil {
|
||||
return fmt.Errorf("write %s: %w", pluginFile, err)
|
||||
}
|
||||
|
||||
fmt.Printf("Installed Elydora hook for OpenCode at %s\n", pluginFile)
|
||||
return nil
|
||||
}
|
||||
|
||||
func buildOpenCodePlugin(scriptPath, guardPath string) string {
|
||||
return fmt.Sprintf(`// Elydora Audit Plugin for OpenCode
|
||||
// Generated by @elydora/sdk — DO NOT EDIT
|
||||
|
||||
const { spawn, spawnSync } = require('node:child_process');
|
||||
|
||||
module.exports = {
|
||||
name: 'elydora-audit',
|
||||
version: '1.0.0',
|
||||
description: 'Sends tool-use events to the Elydora tamper-evident audit platform',
|
||||
|
||||
hooks: {
|
||||
preToolUse(context) {
|
||||
// Synchronous guard — blocks tool if agent is frozen
|
||||
try {
|
||||
const result = spawnSync('node', [%q], {
|
||||
timeout: 5000,
|
||||
stdio: ['pipe', 'ignore', 'pipe'],
|
||||
});
|
||||
if (result.status !== 0) {
|
||||
const msg = result.stderr ? result.stderr.toString().trim() : 'Agent is frozen by Elydora.';
|
||||
return { blocked: true, reason: msg };
|
||||
}
|
||||
} catch {
|
||||
// Fail-open — allow if guard can't run
|
||||
}
|
||||
},
|
||||
|
||||
postToolUse(context) {
|
||||
try {
|
||||
const input = JSON.stringify({
|
||||
tool_name: context.toolName || context.tool_name || 'unknown',
|
||||
tool_input: context.toolInput || context.tool_input || {},
|
||||
session_id: context.sessionId || context.session_id || 'unknown',
|
||||
});
|
||||
|
||||
const child = spawn('node', [%q], {
|
||||
detached: true,
|
||||
stdio: ['pipe', 'ignore', 'ignore'],
|
||||
});
|
||||
child.stdin.write(input);
|
||||
child.stdin.end();
|
||||
child.unref();
|
||||
} catch {
|
||||
// Fire-and-forget — never block the developer
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
`, guardPath, scriptPath)
|
||||
}
|
||||
|
||||
func (p *OpenCodePlugin) Uninstall() error {
|
||||
pluginFile, err := p.configPath()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.Remove(pluginFile); err != nil && !os.IsNotExist(err) {
|
||||
return fmt.Errorf("remove %s: %w", pluginFile, err)
|
||||
}
|
||||
|
||||
scriptPath, _ := hookScriptPath("opencode")
|
||||
if scriptPath != "" {
|
||||
os.Remove(scriptPath)
|
||||
}
|
||||
gPath, _ := guardScriptPath("opencode")
|
||||
if gPath != "" {
|
||||
os.Remove(gPath)
|
||||
}
|
||||
|
||||
fmt.Println("Uninstalled Elydora hook for OpenCode.")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *OpenCodePlugin) Status() (PluginStatus, error) {
|
||||
scriptPath, err := hookScriptPath("opencode")
|
||||
if err != nil {
|
||||
return PluginStatus{}, err
|
||||
}
|
||||
|
||||
pluginFile, err := p.configPath()
|
||||
if err != nil {
|
||||
return PluginStatus{}, err
|
||||
}
|
||||
|
||||
status := PluginStatus{
|
||||
AgentName: "opencode",
|
||||
DisplayName: "OpenCode",
|
||||
ConfigPath: pluginFile,
|
||||
}
|
||||
|
||||
if _, err := os.Stat(scriptPath); err == nil {
|
||||
status.HookScriptExists = true
|
||||
}
|
||||
|
||||
if _, err := os.Stat(pluginFile); err == nil {
|
||||
status.HookConfigured = true
|
||||
}
|
||||
|
||||
status.Installed = status.HookConfigured && status.HookScriptExists
|
||||
return status, nil
|
||||
}
|
||||
Reference in new issue
Block a user