// Package target maps content types to runtime-specific deployment paths. // The OpenCode target is the thin v2 implementation: a type filter plus // path mapping, leaving the door open for future targets. package target import ( "os" "path/filepath" "strings" "github.com/m3tam3re/agent-lib/internal/lockfile" ) // OpenCode maps items into the OpenCode runtime layout, rooted at the // user's home directory. type OpenCode struct { Home string } // NewOpenCode resolves the home directory once for all path mappings. func NewOpenCode() (*OpenCode, error) { home, err := os.UserHomeDir() if err != nil { return nil, err } return &OpenCode{Home: home}, nil } // DeployPath returns the absolute destination for an item; ok is false for // types this target never deploys (MCP stays under fleet control). func (o *OpenCode) DeployPath(typ, name string) (path string, ok bool) { switch typ { case lockfile.TypeSkill: return filepath.Join(o.Home, ".agents", "skills", name), true case lockfile.TypeCommand: return filepath.Join(o.Home, ".config", "opencode", "commands", name+".md"), true case lockfile.TypeAgent: return filepath.Join(o.Home, ".config", "opencode", "agents", name+".md"), true default: return "", false } } // ScanTargetDirs lists every item currently present in the target dirs, // keyed "/" — the raw material for detecting unmanaged occupants. func (o *OpenCode) ScanTargetDirs() map[string]bool { out := map[string]bool{} skillsDir := filepath.Join(o.Home, ".agents", "skills") if entries, err := os.ReadDir(skillsDir); err == nil { for _, e := range entries { if e.IsDir() { out[lockfile.TypeSkill+"/"+e.Name()] = true } } } for typ, dir := range map[string]string{ lockfile.TypeCommand: filepath.Join(o.Home, ".config", "opencode", "commands"), lockfile.TypeAgent: filepath.Join(o.Home, ".config", "opencode", "agents"), } { entries, err := os.ReadDir(dir) if err != nil { continue } for _, e := range entries { if !e.IsDir() && strings.HasSuffix(e.Name(), ".md") { out[typ+"/"+strings.TrimSuffix(e.Name(), ".md")] = true } } } return out }