Files
Elydora-Go-SDK/cmd/elydora/plugins/qwen_io.go
T

151 lines
3.8 KiB
Go

package plugins
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"regexp"
)
var qwenPathSeparatorPattern = regexp.MustCompile(`[/\\]+`)
func defaultQwenHome() (string, error) {
home, err := os.UserHomeDir()
if err != nil {
return "", fmt.Errorf("resolve home directory: %w", err)
}
return filepath.Join(home, ".qwen"), nil
}
func resolveQwenStoragePath(value string) (string, error) {
resolved := value
if value == "~" || len(value) >= 2 && value[0] == '~' && (value[1] == '/' || value[1] == '\\') {
home, err := os.UserHomeDir()
if err != nil {
return "", fmt.Errorf("resolve home directory: %w", err)
}
resolved = home
if value != "~" {
for _, segment := range qwenPathSeparatorPattern.Split(value[2:], -1) {
if segment != "" {
resolved = filepath.Join(resolved, segment)
}
}
}
}
if filepath.IsAbs(resolved) {
return filepath.Clean(resolved), nil
}
absolute, err := filepath.Abs(resolved)
if err != nil {
return "", fmt.Errorf("resolve Qwen Code storage path %q: %w", value, err)
}
return absolute, nil
}
func qwenHomeFromEnvFile(filePath string) (string, bool, error) {
raw, exists, err := readOptionalFile(filePath, "Qwen home environment")
if err != nil || !exists {
return "", false, err
}
value := parseDotenv(raw)["QWEN_HOME"]
if value == "" {
return "", false, nil
}
resolved, err := resolveQwenStoragePath(value)
return resolved, err == nil, err
}
func resolveQwenHome() (string, error) {
defaultHome, err := defaultQwenHome()
if err != nil {
return "", err
}
value, explicit := os.LookupEnv("QWEN_HOME")
initialHome := defaultHome
if value != "" {
initialHome, err = resolveQwenStoragePath(value)
if err != nil {
return "", err
}
}
if explicit {
return initialHome, nil
}
for _, candidate := range []string{
filepath.Join(initialHome, ".env"), filepath.Join(filepath.Dir(initialHome), ".env"),
} {
if discovered, exists, readErr := qwenHomeFromEnvFile(candidate); readErr != nil {
return "", readErr
} else if exists {
return discovered, nil
}
}
return initialHome, nil
}
func readQwenDocument() (*qwenDocument, error) {
home, err := resolveQwenHome()
if err != nil {
return nil, err
}
configPath := filepath.Join(home, "settings.json")
raw, exists, err := readOptionalFile(configPath, "Qwen Code settings")
if err != nil {
return nil, err
}
if !exists {
return createOwnedQwenDocument(configPath)
}
return parseQwenDocument(true, configPath, raw)
}
func prepareRenderedQwenChange(rendered *qwenRenderedDocument) (*fileChange, error) {
if rendered == nil || !rendered.changed {
return nil, nil
}
return prepareSourceChange(
rendered.document.filePath,
"Qwen Code settings",
rendered.document.raw,
rendered.document.exists,
rendered.next,
os.FileMode(0600),
rendered.remove,
)
}
func qwenRuntimeFilesExist(contracts []qwenRuntimeContract) (bool, error) {
for _, contract := range contracts {
configPath := filepath.Join(filepath.Dir(contract.guardPath), "config.json")
raw, exists, err := readOptionalFile(configPath, "Elydora runtime config")
if err != nil {
return false, err
}
if !exists {
continue
}
var config map[string]any
if err := json.Unmarshal(raw, &config); err != nil {
return false, fmt.Errorf("parse Elydora runtime config at %s: %w", configPath, err)
}
agentID, ok := config["agent_id"].(string)
if !ok || config["agent_name"] != qwenAgentKey || !sameQwenAgentID(agentID, contract.agentID) {
continue
}
guardExists, err := regularFileExists(contract.guardPath, "Elydora guard runtime")
if err != nil {
return false, err
}
auditExists, err := regularFileExists(contract.auditPath, "Elydora audit runtime")
if err != nil {
return false, err
}
if guardExists && auditExists {
return true, nil
}
}
return false, nil
}