152 lines
3.8 KiB
Go
152 lines
3.8 KiB
Go
package plugins
|
|
|
|
import "fmt"
|
|
|
|
// DroidPlugin manages Factory Droid native user hooks.
|
|
type DroidPlugin struct {
|
|
rename renameFunc
|
|
}
|
|
|
|
// ManagesGuardRuntime reports that Droid commits its guard, audit runtime,
|
|
// credentials, and hook documents in one transaction.
|
|
func (p *DroidPlugin) ManagesGuardRuntime() bool {
|
|
return true
|
|
}
|
|
|
|
// PreflightInstall validates every hook source, policy layer, credential,
|
|
// matcher, and runtime identity before any write.
|
|
func (p *DroidPlugin) PreflightInstall(config InstallConfig) error {
|
|
sources, err := readDroidSources()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, _, err = preflightDroidInstallation(config, sources)
|
|
return err
|
|
}
|
|
|
|
func renderDroidInstallation(
|
|
sources *droidSources,
|
|
guardPath, auditPath, nodePath, runtimeRoot string,
|
|
) ([]*droidRenderedDocument, error) {
|
|
target := activeDroidDocument(sources)
|
|
groups := map[string]map[string]any{
|
|
"PreToolUse": buildDroidGroup(nodePath, guardPath),
|
|
"PostToolUse": buildDroidGroup(nodePath, auditPath),
|
|
}
|
|
documents := droidInstallationDocuments(sources)
|
|
rendered := make([]*droidRenderedDocument, 0, len(documents))
|
|
for _, document := range documents {
|
|
item, err := renderDroidDocument(
|
|
document,
|
|
"",
|
|
runtimeRoot,
|
|
droidAdditionsFor(document, target, groups),
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
rendered = append(rendered, item)
|
|
}
|
|
return rendered, nil
|
|
}
|
|
|
|
func (p *DroidPlugin) Install(config InstallConfig) error {
|
|
sources, err := readDroidSources()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
paths, nodePath, err := preflightDroidInstallation(config, sources)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
rendered, err := renderDroidInstallation(
|
|
sources,
|
|
paths.guardPath,
|
|
paths.auditPath,
|
|
nodePath,
|
|
paths.runtimeRoot,
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
prepared, err := prepareDroidInstallation(config, sources, rendered)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err := commitDroidInstallation(prepared, p.rename); err != nil {
|
|
return err
|
|
}
|
|
fmt.Printf("Factory Droid hooks: %s\n", activeDroidDocument(sources).filePath)
|
|
fmt.Println("Factory Droid: run /hooks to review the Elydora hook changes.")
|
|
return nil
|
|
}
|
|
|
|
func renderDroidUninstall(
|
|
sources *droidSources,
|
|
agentID, runtimeRoot string,
|
|
) ([]*droidRenderedDocument, error) {
|
|
documents := droidSourceDocuments(sources)
|
|
rendered := make([]*droidRenderedDocument, 0, len(documents))
|
|
for _, document := range documents {
|
|
item, err := renderDroidDocument(
|
|
document,
|
|
agentID,
|
|
runtimeRoot,
|
|
map[string]map[string]any{},
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
rendered = append(rendered, item)
|
|
}
|
|
return rendered, nil
|
|
}
|
|
|
|
func (p *DroidPlugin) Uninstall(agentID string) error {
|
|
sources, err := readDroidSources()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
runtimeRoot, err := droidRuntimeRoot()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
rendered, err := renderDroidUninstall(sources, agentID, runtimeRoot)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
prepared, err := prepareDroidUninstall(rendered)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return commitDroidUninstall(prepared, p.rename)
|
|
}
|
|
|
|
func (p *DroidPlugin) Status() (PluginStatus, error) {
|
|
entry := SupportedAgents[droidAgentKey]
|
|
status := PluginStatus{AgentName: droidAgentKey, DisplayName: entry.Name}
|
|
sources, err := readDroidSources()
|
|
if err != nil {
|
|
return status, err
|
|
}
|
|
status.ConfigPath = displayDroidConfigPath(sources)
|
|
if droidHookBlocked(sources) != nil {
|
|
return status, nil
|
|
}
|
|
runtimeRoot, err := droidRuntimeRoot()
|
|
if err != nil {
|
|
return status, err
|
|
}
|
|
contracts := droidRuntimeContracts(effectiveDroidHooks(sources), runtimeRoot)
|
|
status.HookConfigured = len(contracts) > 0
|
|
if !status.HookConfigured {
|
|
return status, nil
|
|
}
|
|
status.HookScriptExists, err = droidRuntimeFilesExist(contracts)
|
|
if err != nil {
|
|
return status, err
|
|
}
|
|
status.Installed = status.HookScriptExists
|
|
return status, nil
|
|
}
|