Files
sproutclaw-web/backend/internal/services/extensions.go
2026-06-13 20:16:09 +08:00

106 lines
2.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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)
}