package services import ( "encoding/json" "os" "path/filepath" "strings" "sproutclaw-web/internal/models" ) // ListExtensions reads the extensions directory and returns metadata. func ListExtensions(agentDir string) []models.ExtensionInfo { extDir := filepath.Join(agentDir, "extensions") entries, err := os.ReadDir(extDir) if err != nil { return nil } var exts []models.ExtensionInfo for _, e := range entries { if !e.IsDir() { continue } ext := buildExtensionInfo(filepath.Join(extDir, e.Name()), e.Name()) exts = append(exts, ext) } return exts } func buildExtensionInfo(path, id string) models.ExtensionInfo { info := models.ExtensionInfo{ ID: id, Name: id, Enabled: true, // assume enabled unless configured otherwise Source: "local", } // try package.json for version/name pkgPath := filepath.Join(path, "package.json") if data, err := os.ReadFile(pkgPath); err == nil { var pkg struct { Name string `json:"name"` Version string `json:"version"` } if json.Unmarshal(data, &pkg) == nil { if pkg.Name != "" { info.Name = pkg.Name } info.Version = pkg.Version // detect npm packages if strings.Contains(pkg.Name, "/") || strings.HasPrefix(pkg.Name, "@") { info.Source = "npm" } } } return info } // ToggleExtension is a placeholder – full implementation requires settings.json management. func ToggleExtension(agentDir, id string, enable bool) error { return updateSettingsExtensions(filepath.Join(agentDir, "settings.json"), id, enable) } func updateSettingsExtensions(settingsPath, id string, enable bool) error { data, err := os.ReadFile(settingsPath) if err != nil && !os.IsNotExist(err) { return err } var settings map[string]any if len(data) > 0 { if err := json.Unmarshal(data, &settings); err != nil { settings = map[string]any{} } } else { settings = map[string]any{} } // extensions is a list of enabled extension IDs extList, _ := settings["extensions"].([]any) set := map[string]bool{} for _, e := range extList { if s, ok := e.(string); ok { set[s] = true } } if enable { set[id] = true } else { delete(set, id) } newList := make([]string, 0, len(set)) for k := range set { newList = append(newList, k) } settings["extensions"] = newList out, err := json.MarshalIndent(settings, "", " ") if err != nil { return err } return os.WriteFile(settingsPath, append(out, '\n'), 0o644) }