Files
Elydora-Go-SDK/cmd/elydora/plugins/droid_config.go
T
雷电芽衣 1ede03d989 chore(go): audit providers copilot droid augment cline
Move the four providers onto managed_runtime.go and shell_command.go;
keep the Auggie wrappers, Cline metadata wrappers, and the Copilot and
Droid precondition handling provider-local.

Claude-Session: https://claude.ai/code/session_01Agoc9bRVE9KL7mmWtey9Vq
2026-09-03 01:56:07 -04:00

405 lines
11 KiB
Go

package plugins
import (
"bytes"
"fmt"
"path/filepath"
"reflect"
"sort"
)
type droidDocument struct {
kind string
filePath string
exists bool
raw []byte
snapshot *managedFileSnapshot
root map[string]any
hooks droidHookSettings
basePath []any
hasHooksContainer bool
hooksDisabled *bool
showHookOutput *bool
ownedFile bool
}
type droidSources struct {
root *droidDocument
legacy *droidDocument
settings *droidDocument
localSettings *droidDocument
policy *droidPolicyState
}
type droidRenderedDocument struct {
document *droidDocument
changed bool
next []byte
remove bool
}
type droidHookBlock struct {
field string
filePath string
label string
}
func parseDroidDocument(
exists bool,
filePath, kind string,
raw []byte,
snapshot *managedFileSnapshot,
) (*droidDocument, error) {
label := droidDocumentLabel(kind, filePath)
root, err := decodeJSONCObject(raw, label, true)
if err != nil {
return nil, err
}
document := &droidDocument{
kind: kind, filePath: filePath, exists: exists,
raw: append([]byte(nil), raw...), snapshot: snapshot, root: root,
ownedFile: bytes.HasPrefix(raw, []byte(droidOwnedFileMarker)),
}
if kind == "settings" || kind == "local-settings" {
document.basePath = []any{"hooks"}
document.hooksDisabled, err = droidOptionalBoolean(root, "hooksDisabled", label)
if err != nil {
return nil, err
}
document.showHookOutput, err = droidOptionalBoolean(root, "showHookOutput", label)
if err != nil {
return nil, err
}
hooksValue, hasHooks := root["hooks"]
document.hasHooksContainer = hasHooks
if !hasHooks {
document.hooks = droidHookSettings{}
return document, nil
}
document.hooks, err = readDroidHookSettings(hooksValue, label+` field "hooks"`)
return document, err
}
if hooksValue, hasHooks := root["hooks"]; hasHooks {
document.basePath = []any{"hooks"}
document.hasHooksContainer = true
document.hooks, err = readDroidHookSettings(hooksValue, label+` field "hooks"`)
return document, err
}
document.hooksDisabled, err = droidOptionalBoolean(root, "hooksDisabled", label)
if err != nil {
return nil, err
}
document.showHookOutput, err = droidOptionalBoolean(root, "showHookOutput", label)
if err != nil {
return nil, err
}
direct := make(map[string]any, len(root))
for key, value := range root {
if key != "hooksDisabled" && key != "showHookOutput" {
direct[key] = value
}
}
document.hooks, err = readDroidHookSettings(direct, label)
return document, err
}
func droidOptionalBoolean(
root map[string]any,
field, label string,
) (*bool, error) {
value, exists := root[field]
if !exists {
return nil, nil
}
boolean, ok := value.(bool)
if !ok {
return nil, fmt.Errorf(`%s field %q must be a boolean`, label, field)
}
return &boolean, nil
}
func droidDocumentLabel(kind, filePath string) string {
switch kind {
case "settings":
return fmt.Sprintf("Factory Droid settings at %s", filePath)
case "local-settings":
return fmt.Sprintf("Factory Droid local settings at %s", filePath)
case "legacy":
return fmt.Sprintf("Factory Droid legacy hooks at %s", filePath)
default:
return fmt.Sprintf("Factory Droid hooks at %s", filePath)
}
}
func createDroidDocument(filePath, kind string, raw []byte) (*droidDocument, error) {
return parseDroidDocument(false, filePath, kind, raw, nil)
}
func createOwnedDroidDocument(filePath string) (*droidDocument, error) {
return createDroidDocument(
filePath,
"hooks",
[]byte(droidOwnedFileMarker+"\n{\n \"hooks\": {}\n}\n"),
)
}
func activeDroidDocument(sources *droidSources) *droidDocument {
switch {
case sources.root.exists:
return sources.root
case sources.legacy.exists:
return sources.legacy
case sources.localSettings.hasHooksContainer:
return sources.localSettings
case sources.settings.hasHooksContainer:
return sources.settings
default:
return sources.root
}
}
func effectiveDroidHooks(sources *droidSources) droidHookSettings {
return activeDroidDocument(sources).hooks
}
func droidHookBlocked(sources *droidSources) *droidHookBlock {
if sources.policy != nil && sources.policy.allowManagedHooksOnlyBy != nil {
origin := sources.policy.allowManagedHooksOnlyBy
return &droidHookBlock{"allowManagedHooksOnly", origin.filePath, origin.label}
}
if sources.policy != nil && sources.policy.hooksDisabled != nil {
if *sources.policy.hooksDisabled {
origin := sources.policy.hooksDisabledBy
return &droidHookBlock{"hooksDisabled", origin.filePath, origin.label}
}
return nil
}
selected := sources.settings
if sources.localSettings.hooksDisabled != nil {
selected = sources.localSettings
}
if selected.hooksDisabled != nil && *selected.hooksDisabled {
return &droidHookBlock{
"hooksDisabled", selected.filePath,
droidDocumentLabel(selected.kind, selected.filePath),
}
}
active := activeDroidDocument(sources)
if active.hooksDisabled != nil && *active.hooksDisabled {
return &droidHookBlock{
"hooksDisabled", active.filePath,
droidDocumentLabel(active.kind, active.filePath),
}
}
return nil
}
func droidSourceDocuments(sources *droidSources) []*droidDocument {
return []*droidDocument{
sources.root, sources.legacy, sources.settings, sources.localSettings,
}
}
func droidInstallationDocuments(sources *droidSources) []*droidDocument {
target := activeDroidDocument(sources)
candidates := []*droidDocument{target}
if sources.root.exists {
candidates = append(candidates, sources.root)
}
if sources.legacy.exists {
candidates = append(candidates, sources.legacy)
}
if sources.settings.hasHooksContainer {
candidates = append(candidates, sources.settings)
}
if sources.localSettings.hasHooksContainer {
candidates = append(candidates, sources.localSettings)
}
return uniqueDroidDocuments(candidates...)
}
func uniqueDroidDocuments(documents ...*droidDocument) []*droidDocument {
result := make([]*droidDocument, 0, len(documents))
seen := map[string]bool{}
for _, document := range documents {
if document == nil {
continue
}
normalized := filepath.Clean(document.filePath)
if seen[normalized] {
continue
}
seen[normalized] = true
result = append(result, document)
}
return result
}
func droidAdditionsFor(
document, target *droidDocument,
groups map[string]map[string]any,
) map[string]map[string]any {
if sameManagedPath(document.filePath, target.filePath) {
return groups
}
return map[string]map[string]any{}
}
func renderDroidDocument(
document *droidDocument,
agentID, runtimeRoot string,
additions map[string]map[string]any,
) (*droidRenderedDocument, error) {
if len(additions) > 0 && droidHasExactInstallation(document, additions, runtimeRoot) {
return &droidRenderedDocument{document: document, next: document.raw}, nil
}
editor, err := newJSONCEditor(
document.raw,
droidDocumentLabel(document.kind, document.filePath),
true,
)
if err != nil {
return nil, err
}
removals := managedDroidRemovals(document.hooks, agentID, runtimeRoot)
sort.SliceStable(removals, func(left, right int) bool {
if removals[left].event == removals[right].event {
return removals[left].groupIndex > removals[right].groupIndex
}
return removals[left].event < removals[right].event
})
for _, event := range droidToolEvents {
removedEvent := false
for _, removal := range removals {
if removal.event != event {
continue
}
removedEvent = true
groupPath := appendDroidPath(document.basePath, removal.event, removal.groupIndex)
if removal.removeGroup {
if err := editor.remove(groupPath); err != nil {
return nil, err
}
continue
}
sort.Sort(sort.Reverse(sort.IntSlice(removal.handlerIndexes)))
for _, handlerIndex := range removal.handlerIndexes {
if err := editor.remove(appendDroidPath(groupPath, "hooks", handlerIndex)); err != nil {
return nil, err
}
}
}
if removedEvent {
current, parseErr := droidHooksFromRaw(document, editor.pack())
if parseErr != nil {
return nil, parseErr
}
groups, exists := current[event].([]any)
if exists && len(groups) == 0 {
if err := editor.remove(appendDroidPath(document.basePath, event)); err != nil {
return nil, err
}
}
}
}
for _, event := range droidToolEvents {
group, exists := additions[event]
if !exists {
continue
}
current, parseErr := droidHooksFromRaw(document, editor.pack())
if parseErr != nil {
return nil, parseErr
}
eventPath := appendDroidPath(document.basePath, event)
if _, exists := current[event]; exists {
err = editor.appendArray(eventPath, group)
} else {
err = editor.addProperty(document.basePath, event, []any{group})
}
if err != nil {
return nil, err
}
}
next := editor.pack()
nextDocument, err := parseDroidDocument(
document.exists, document.filePath, document.kind, next, document.snapshot,
)
if err != nil {
return nil, err
}
remove := len(additions) == 0 && document.exists && document.ownedFile &&
droidHookDocumentEmpty(nextDocument)
return &droidRenderedDocument{
document: document,
changed: remove || !bytes.Equal(next, document.raw),
next: next,
remove: remove,
}, nil
}
func droidHasExactInstallation(
document *droidDocument,
additions map[string]map[string]any,
runtimeRoot string,
) bool {
if len(additions) != len(droidToolEvents) {
return false
}
removals := managedDroidRemovals(document.hooks, "", runtimeRoot)
if len(removals) != len(droidToolEvents) {
return false
}
for _, event := range droidToolEvents {
matches := make([]droidManagedRemoval, 0, 1)
for _, removal := range removals {
if removal.event == event {
matches = append(matches, removal)
}
}
if len(matches) != 1 || !matches[0].removeGroup {
return false
}
groups := document.hooks[event].([]any)
if !reflect.DeepEqual(groups[matches[0].groupIndex], additions[event]) {
return false
}
}
return true
}
func droidHooksFromRaw(
document *droidDocument,
raw []byte,
) (droidHookSettings, error) {
current, err := parseDroidDocument(
document.exists, document.filePath, document.kind, raw, document.snapshot,
)
if err != nil {
return nil, err
}
return current.hooks, nil
}
func droidHookDocumentEmpty(document *droidDocument) bool {
if document.kind == "settings" || document.kind == "local-settings" || len(document.hooks) > 0 {
return false
}
for field := range document.root {
if field != "hooks" {
return false
}
}
return true
}
func appendDroidPath(base []any, parts ...any) []any {
path := make([]any, 0, len(base)+len(parts))
path = append(path, base...)
return append(path, parts...)
}
func displayDroidConfigPath(sources *droidSources) string {
return activeDroidDocument(sources).filePath
}