148 lines
3.3 KiB
Go
148 lines
3.3 KiB
Go
package plugins
|
|
|
|
import "fmt"
|
|
|
|
func validateClineHookDirectories(paths clineHookPaths) error {
|
|
if _, err := managedPhysicalDirectoryExists(
|
|
paths.clineDirectory,
|
|
"Cline configuration directory",
|
|
); err != nil {
|
|
return err
|
|
}
|
|
_, err := managedPhysicalDirectoryExists(
|
|
paths.hooksDirectory,
|
|
"Cline hooks directory",
|
|
)
|
|
return err
|
|
}
|
|
|
|
func readClineHookFile(filePath string) (clineHookFile, error) {
|
|
snapshot, err := readManagedFile(filePath, "Cline hook", maxManagedSourceBytes)
|
|
if err != nil {
|
|
return clineHookFile{}, err
|
|
}
|
|
if snapshot == nil {
|
|
return clineHookFile{filePath: filePath}, nil
|
|
}
|
|
source := string(snapshot.contents)
|
|
metadata, err := parseClineMetadata(filePath, source)
|
|
if err != nil {
|
|
return clineHookFile{}, err
|
|
}
|
|
return clineHookFile{
|
|
exists: true, filePath: filePath, source: source, metadata: metadata,
|
|
}, nil
|
|
}
|
|
|
|
func readClineHookPair() (
|
|
clineHookPaths,
|
|
clineHookFile,
|
|
clineHookFile,
|
|
error,
|
|
) {
|
|
paths, err := resolveClineHookFiles()
|
|
if err != nil {
|
|
return clineHookPaths{}, clineHookFile{}, clineHookFile{}, err
|
|
}
|
|
if err := validateClineHookDirectories(paths); err != nil {
|
|
return paths, clineHookFile{}, clineHookFile{}, err
|
|
}
|
|
guard, err := readClineHookFile(paths.guardPath)
|
|
if err != nil {
|
|
return paths, clineHookFile{}, clineHookFile{}, err
|
|
}
|
|
audit, err := readClineHookFile(paths.auditPath)
|
|
if err != nil {
|
|
return paths, clineHookFile{}, clineHookFile{}, err
|
|
}
|
|
return paths, guard, audit, nil
|
|
}
|
|
|
|
func requireAvailableClineHook(file clineHookFile) error {
|
|
if file.exists && file.metadata == nil {
|
|
return fmt.Errorf(
|
|
"Cline hook at %s already exists and is owned by another integration",
|
|
file.filePath,
|
|
)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func writeClineHookChanges(
|
|
changes []*fileChange,
|
|
label string,
|
|
rename renameFunc,
|
|
paths clineHookPaths,
|
|
) error {
|
|
if !hasClineChanges(changes) {
|
|
return nil
|
|
}
|
|
if err := ensureManagedDirectory(
|
|
paths.clineDirectory,
|
|
"Cline configuration directory",
|
|
); err != nil {
|
|
return err
|
|
}
|
|
if err := ensureManagedDirectory(paths.hooksDirectory, "Cline hooks directory"); err != nil {
|
|
return err
|
|
}
|
|
return writeChanges(changes, label, rename)
|
|
}
|
|
|
|
func writeClineChanges(
|
|
changes []*fileChange,
|
|
label string,
|
|
rename renameFunc,
|
|
paths *clineRuntimePaths,
|
|
) error {
|
|
if !hasClineChanges(changes) {
|
|
return nil
|
|
}
|
|
if err := EnsurePrivateDirectory(paths.runtimeRoot); err != nil {
|
|
return err
|
|
}
|
|
if err := EnsurePrivateDirectory(paths.agentDirectory); err != nil {
|
|
return err
|
|
}
|
|
return writeClineHookChanges(changes, label, rename, paths.hooks)
|
|
}
|
|
|
|
func hasClineChanges(changes []*fileChange) bool {
|
|
for _, change := range changes {
|
|
if change != nil {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func prepareClineUninstallChanges(
|
|
files []clineHookFile,
|
|
agentID string,
|
|
) ([]*fileChange, error) {
|
|
changes := make([]*fileChange, 0, len(files))
|
|
for _, file := range files {
|
|
if file.metadata == nil ||
|
|
(agentID != "" && !sameClineAgentID(file.metadata.AgentID, agentID)) {
|
|
continue
|
|
}
|
|
if err := assertClineWrapperIntegrity(file); err != nil {
|
|
return nil, err
|
|
}
|
|
change, err := prepareSourceChange(
|
|
file.filePath,
|
|
fmt.Sprintf("Cline %s hook", file.metadata.Kind),
|
|
[]byte(file.source),
|
|
file.exists,
|
|
nil,
|
|
0700,
|
|
true,
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
changes = append(changes, change)
|
|
}
|
|
return changes, nil
|
|
}
|