151 lines
4.1 KiB
Go
151 lines
4.1 KiB
Go
package mounts
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"regexp"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
const (
|
|
codexManagedMCPBlockStart = "# BEGIN XWORKMATE MANAGED MCP BLOCK"
|
|
codexManagedMCPBlockEnd = "# END XWORKMATE MANAGED MCP BLOCK"
|
|
opencodeManagedMCPBlockStart = "# BEGIN XWORKMATE MANAGED MCP BLOCK"
|
|
opencodeManagedMCPBlockEnd = "# END XWORKMATE MANAGED MCP BLOCK"
|
|
)
|
|
|
|
var mcpServerSectionPattern = regexp.MustCompile(
|
|
`(?m)^\[mcp_servers\.[^\]]+\]`,
|
|
)
|
|
|
|
func countMCPSections(content string) int {
|
|
return len(mcpServerSectionPattern.FindAllStringIndex(content, -1))
|
|
}
|
|
|
|
func defaultCodexHome() string {
|
|
home, err := os.UserHomeDir()
|
|
if err != nil || strings.TrimSpace(home) == "" {
|
|
return ""
|
|
}
|
|
return filepath.Join(home, ".codex")
|
|
}
|
|
|
|
func defaultOpencodeHome() string {
|
|
home, err := os.UserHomeDir()
|
|
if err != nil || strings.TrimSpace(home) == "" {
|
|
return ""
|
|
}
|
|
return filepath.Join(home, ".opencode")
|
|
}
|
|
|
|
func defaultOpenClawHome() string {
|
|
home, err := os.UserHomeDir()
|
|
if err != nil || strings.TrimSpace(home) == "" {
|
|
return ""
|
|
}
|
|
return filepath.Join(home, ".openclaw")
|
|
}
|
|
|
|
func stripManagedBlock(content, startMarker, endMarker string) string {
|
|
if strings.TrimSpace(content) == "" {
|
|
return content
|
|
}
|
|
|
|
remaining := content
|
|
for {
|
|
start := strings.Index(remaining, startMarker)
|
|
if start < 0 {
|
|
break
|
|
}
|
|
end := strings.Index(remaining[start:], endMarker)
|
|
if end < 0 {
|
|
remaining = remaining[:start]
|
|
break
|
|
}
|
|
end += start
|
|
remaining = remaining[:start] + remaining[end+len(endMarker):]
|
|
}
|
|
return remaining
|
|
}
|
|
|
|
func mergeManagedBlock(content, block, startMarker, endMarker string) string {
|
|
preserved := strings.TrimRight(
|
|
stripManagedBlock(content, startMarker, endMarker),
|
|
"\n",
|
|
)
|
|
if preserved == "" {
|
|
return block + "\n"
|
|
}
|
|
return preserved + "\n\n" + block + "\n"
|
|
}
|
|
|
|
func buildCodexManagedMCPBlock(servers []ManagedMCPServer) string {
|
|
var buffer strings.Builder
|
|
buffer.WriteString(codexManagedMCPBlockStart)
|
|
buffer.WriteString("\n# Generated by XWorkmate - Managed MCP Server Configuration\n")
|
|
buffer.WriteString(
|
|
fmt.Sprintf("# Last updated: %s\n\n", time.Now().Format(time.RFC3339Nano)),
|
|
)
|
|
for _, server := range servers {
|
|
buffer.WriteString(fmt.Sprintf("[mcp_servers.%s]\n", server.ID))
|
|
buffer.WriteString(fmt.Sprintf("command = %q\n", server.Command))
|
|
if len(server.Args) > 0 {
|
|
buffer.WriteString(fmt.Sprintf("args = %s\n", formatTOMLArray(server.Args)))
|
|
}
|
|
buffer.WriteString("\n")
|
|
}
|
|
buffer.WriteString(codexManagedMCPBlockEnd)
|
|
return strings.TrimRight(buffer.String(), "\n")
|
|
}
|
|
|
|
func buildOpencodeManagedMCPBlock(servers []ManagedMCPServer) string {
|
|
var buffer strings.Builder
|
|
buffer.WriteString(opencodeManagedMCPBlockStart)
|
|
buffer.WriteString("\n# Generated by XWorkmate - Managed MCP Server Configuration\n")
|
|
buffer.WriteString(
|
|
fmt.Sprintf("# Last updated: %s\n\n", time.Now().Format(time.RFC3339Nano)),
|
|
)
|
|
for _, server := range servers {
|
|
buffer.WriteString(fmt.Sprintf("[mcp_servers.%s]\n", server.ID))
|
|
if strings.TrimSpace(server.URL) != "" {
|
|
buffer.WriteString(fmt.Sprintf("url = %q\n", strings.TrimSpace(server.URL)))
|
|
} else {
|
|
buffer.WriteString("type = \"stdio\"\n")
|
|
buffer.WriteString(fmt.Sprintf("command = %q\n", server.Command))
|
|
if len(server.Args) > 0 {
|
|
buffer.WriteString(fmt.Sprintf("args = %s\n", formatTOMLArray(server.Args)))
|
|
}
|
|
}
|
|
buffer.WriteString("\n")
|
|
}
|
|
buffer.WriteString(opencodeManagedMCPBlockEnd)
|
|
return strings.TrimRight(buffer.String(), "\n")
|
|
}
|
|
|
|
func formatTOMLArray(items []string) string {
|
|
if len(items) == 0 {
|
|
return "[]"
|
|
}
|
|
var quoted []string
|
|
for _, item := range items {
|
|
quoted = append(quoted, fmt.Sprintf("%q", item))
|
|
}
|
|
return "[" + strings.Join(quoted, ", ") + "]"
|
|
}
|
|
|
|
func applyManagedBlock(configPath, block, startMarker, endMarker string) error {
|
|
configDir := filepath.Dir(configPath)
|
|
if err := os.MkdirAll(configDir, 0o755); err != nil {
|
|
return err
|
|
}
|
|
|
|
content, err := os.ReadFile(configPath)
|
|
if err != nil && !os.IsNotExist(err) {
|
|
return err
|
|
}
|
|
merged := mergeManagedBlock(string(content), block, startMarker, endMarker)
|
|
return os.WriteFile(configPath, []byte(merged), 0o644)
|
|
}
|