package plugins import ( "fmt" "os" "path/filepath" ) func grokHomePath() (string, error) { configured := os.Getenv("GROK_HOME") if configured == "" { home, err := os.UserHomeDir() if err != nil { return "", fmt.Errorf("resolve home directory: %w", err) } return filepath.Join(home, ".grok"), nil } home, err := filepath.Abs(configured) if err != nil { return "", fmt.Errorf("resolve GROK_HOME at %s: %w", configured, err) } return home, nil } func grokConfigPath() (string, error) { home, err := grokHomePath() if err != nil { return "", err } return filepath.Join(home, "hooks", grokConfigFile), nil } func readGrokDocument() (*grokDocument, error) { configPath, err := grokConfigPath() if err != nil { return nil, err } home := filepath.Dir(filepath.Dir(configPath)) if _, err := managedPhysicalDirectoryExists(home, "Grok home directory"); err != nil { return nil, err } hooksDirectory := filepath.Dir(configPath) if _, err := managedPhysicalDirectoryExists( hooksDirectory, "Grok hooks directory", ); err != nil { return nil, err } snapshot, err := readManagedFile( configPath, "Grok user hooks", maxManagedSourceBytes, ) if err != nil { return nil, err } if snapshot == nil { return createGrokDocument(configPath), nil } return parseGrokDocument(configPath, snapshot.contents) } func prepareRenderedGrokChange( rendered *grokRenderedDocument, ) (*fileChange, error) { if rendered == nil || !rendered.changed { return nil, nil } return prepareSourceChange( rendered.document.configPath, "Grok user hooks", rendered.document.raw, rendered.document.exists, rendered.next, 0600, rendered.remove, ) } func writeGrokChanges( changes []*fileChange, label string, rename renameFunc, runtimeRoot string, agentDirectory string, hooksDirectory string, ) error { if !hasFileChanges(changes) { return nil } if err := ensureManagedDirectory( filepath.Dir(hooksDirectory), "Grok home directory", ); err != nil { return err } return writeManagedChanges( changes, label, rename, runtimeRoot, agentDirectory, hooksDirectory, "Grok hooks directory", ) }