Files
Elydora-Go-SDK/cmd/elydora/plugins/gemini.go
T

164 lines
3.7 KiB
Go

package plugins
import (
"fmt"
"path/filepath"
)
// GeminiPlugin manages Gemini CLI global user hooks.
type GeminiPlugin struct {
rename renameFunc
}
// ManagesGuardRuntime reports that Gemini commits both generated runtimes and
// the user settings document through one transaction.
func (p *GeminiPlugin) ManagesGuardRuntime() bool {
return true
}
func requireGeminiHooksEnabled(document *geminiDocument) error {
if !document.hookControls.enabled {
return fmt.Errorf(
"Gemini CLI hooks are disabled by hooksConfig.enabled: %s",
document.filePath,
)
}
disabled, err := disabledManagedGeminiEntries(document.hookControls)
if err != nil {
return err
}
if len(disabled) > 0 {
return fmt.Errorf(
"Gemini CLI hooks are disabled by hooksConfig.disabled: %v",
disabled,
)
}
return nil
}
// PreflightInstall validates settings and runtime identity before any write.
func (p *GeminiPlugin) PreflightInstall(config InstallConfig) error {
document, err := readGeminiDocument()
if err != nil {
return err
}
if err := requireGeminiHooksEnabled(document); err != nil {
return err
}
_, _, err = preflightGeminiInstallation(config, document)
return err
}
func (p *GeminiPlugin) Install(config InstallConfig) error {
document, err := readGeminiDocument()
if err != nil {
return err
}
if err := requireGeminiHooksEnabled(document); err != nil {
return err
}
paths, nodePath, err := preflightGeminiInstallation(config, document)
if err != nil {
return err
}
guardGroup, err := buildGeminiGroup(
nodePath,
paths.guardPath,
geminiGuardHookName,
)
if err != nil {
return err
}
auditGroup, err := buildGeminiGroup(
nodePath,
paths.auditPath,
geminiAuditHookName,
)
if err != nil {
return err
}
rendered, err := renderGeminiDocument(
document,
"",
map[string]map[string]any{
"BeforeTool": guardGroup,
"AfterTool": auditGroup,
},
)
if err != nil {
return fmt.Errorf("render Gemini CLI user settings: %w", err)
}
changes, err := prepareGeminiInstallationChanges(config, paths, rendered)
if err != nil {
return err
}
if err := writeGeminiChanges(
changes,
"Install Gemini CLI hooks",
p.rename,
paths.runtimeRoot,
paths.agentDirectory,
filepath.Dir(document.filePath),
); err != nil {
return err
}
fmt.Printf("Gemini CLI hooks installed at %s.\n", document.filePath)
fmt.Println("Gemini CLI verification: run /hooks list.")
return nil
}
func (p *GeminiPlugin) Uninstall(agentID string) error {
document, err := readGeminiDocument()
if err != nil {
return err
}
rendered, err := renderGeminiDocument(document, agentID, nil)
if err != nil {
return fmt.Errorf("render Gemini CLI user settings: %w", err)
}
change, err := prepareRenderedGeminiChange(rendered)
if err != nil {
return err
}
return writeGeminiChanges(
[]*fileChange{change},
"Uninstall Gemini CLI hooks",
p.rename,
"",
"",
filepath.Dir(document.filePath),
)
}
func (p *GeminiPlugin) Status() (PluginStatus, error) {
configPath, pathErr := geminiSettingsPath()
entry := SupportedAgents[geminiAgentKey]
status := PluginStatus{
AgentName: geminiAgentKey, DisplayName: entry.Name, ConfigPath: configPath,
}
if pathErr != nil {
return status, pathErr
}
document, err := readGeminiDocument()
if err != nil {
return status, err
}
if !managedGeminiHooksEnabled(document.hookControls) {
return status, nil
}
contracts, err := geminiRuntimeContracts(document.hooks)
if err != nil {
return status, err
}
status.HookConfigured = len(contracts) > 0
if !status.HookConfigured {
return status, nil
}
status.HookScriptExists, err = geminiRuntimeFilesExist(contracts)
if err != nil {
return status, err
}
status.Installed = status.HookScriptExists
return status, nil
}