Help us shape the future of Go! Take the 2026 Go Developer Survey

installer

package
v1.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 8, 2026 License: GPL-3.0 Imports: 16 Imported by: 0

Documentation

Overview

Package installer provides the mechanics behind "sync82 install [target]" and "sync82 uninstall [target] [--purge]": the Target type describing each supported MCP client, the fixed Targets list, the Env the targets resolve their paths against, InstallTarget and UninstallTarget, which register or remove sync82 in one target by invoking the client's own MCP subcommands (KindCLI) or editing its JSON config files (KindFile), and the purge helpers listing and deleting the files of sync82's data directory. The command-line flows — listing detected targets, confirming, dispatching across all of them, and summarizing results — live in cmd/sync82's RunInstall and RunUninstall.

Index

Constants

View Source
const InstallTimeout = 30 * time.Second

InstallTimeout bounds how long each of a CLI target's own subcommands may run.

Variables

View Source
var Targets = []Target{
	{
		Kind:      KindCLI,
		Name:      "claude",
		DetectCmd: "claude",
		Command:   "claude",
		Args:      func(bin string) []string { return []string{"mcp", "add", "--scope", "user", serverName, "--", bin} },
		GetArgs:   []string{"mcp", "get", serverName},
		RemoveArgs: func(scope string) []string {
			return []string{"mcp", "remove", "--scope", scope, serverName}
		},
		Scope: claudeScope,
	},
	{
		Kind:  KindFile,
		Name:  "claude-desktop",
		Shape: shapeMCPServers,
		Unsupported: func(env Env) string {
			if claudeDesktopDir(env) == "" {
				return "Claude Desktop is only available for macOS, Windows and Linux"
			}
			return ""
		},
		DetectDirs:  claudeDesktopDirs,
		ConfigPaths: claudeDesktopConfigPaths,
		RemovePaths: func(env Env) []string {
			var paths []string
			for _, dir := range claudeDesktopDirs(env) {
				paths = append(paths, filepath.Join(dir, "claude_desktop_config.json"))
			}
			return paths
		},
	},
	{
		Kind:      KindFile,
		Name:      "antigravity",
		Shape:     shapeMCPServers,
		DetectCmd: "agy",
		DetectDirs: func(env Env) []string {
			return []string{antigravityConfigDir(env), antigravityLegacyDir(env)}
		},
		ConfigPaths: fixedPaths(antigravityGlobalConfigPath),
		RemovePaths: func(env Env) []string {
			return []string{
				antigravityGlobalConfigPath(env),
				filepath.Join(antigravityLegacyDir(env), "mcp_config.json"),
				filepath.Join(env.HomeDir, ".gemini", "antigravity-ide", "mcp_config.json"),
			}
		},
	},
	{
		Kind:       KindCLI,
		Name:       "codex",
		DetectCmd:  "codex",
		Command:    "codex",
		Args:       func(bin string) []string { return []string{"mcp", "add", serverName, "--", bin} },
		GetArgs:    []string{"mcp", "get", serverName},
		RemoveArgs: func(string) []string { return []string{"mcp", "remove", serverName} },
	},
	{
		Kind:        KindFile,
		Name:        "opencode",
		Shape:       shapeOpenCode,
		DetectCmd:   "opencode",
		ConfigPaths: fixedPaths(opencodeInstallPath),
		RemovePaths: opencodeConfigPaths,
	},
	{
		Kind:        KindFile,
		Name:        "cursor",
		Shape:       shapeCursor,
		DetectDirs:  fixedPaths(cursorDir),
		ConfigPaths: fixedPaths(func(env Env) string { return filepath.Join(cursorDir(env), "mcp.json") }),
	},
	{
		Kind:        KindFile,
		Name:        "zed",
		Shape:       shapeZed,
		DetectDirs:  fixedPaths(zedDir),
		ConfigPaths: fixedPaths(func(env Env) string { return filepath.Join(zedDir(env), "settings.json") }),
	},
	{
		Kind:  KindFile,
		Name:  "cline",
		Shape: shapeMCPServers,
		DetectDirs: func(env Env) []string {
			marker, _ := clineCLIDirs(env)
			dirs := []string{clineExtensionDir(env), marker}
			if override := clineSettingsOverride(env); override != "" {
				dirs = append(dirs, filepath.Dir(override))
			}
			return dirs
		},
		ConfigPaths: func(env Env) []string {
			var paths []string
			if ext := clineExtensionDir(env); dirExists(ext) {
				paths = append(paths, clineSettingsPath(ext))
			}
			marker, _ := clineCLIDirs(env)
			if override := clineSettingsOverride(env); dirExists(marker) || (override != "" && dirExists(filepath.Dir(override))) {
				paths = append(paths, clineCLISettingsPath(env))
			}
			return paths
		},
		RemovePaths: func(env Env) []string {
			_, data := clineCLIDirs(env)
			paths := []string{clineSettingsPath(clineExtensionDir(env)), clineSettingsPath(data)}
			if override := clineSettingsOverride(env); override != "" && override != paths[1] {
				paths = append(paths, override)
			}
			return paths
		},
	},
}

Targets is the fixed set of install targets, in the order "install" and "uninstall" process them.

claude and codex are registered through their own CLIs, with the command after "--", after removing any existing registration: claude per scope (local and user; a project registration is reported and left unchanged), codex through its single configuration. Every other target is a JSON config file edited in place.

Functions

func ConfiguredVaults

func ConfiguredVaults(env Env, cwd string) []string

ConfiguredVaults returns the vault paths configured away from the default <homeDir>/.sync82/knowledge.db, which a purge leaves untouched: the SYNC82_DB_PATH variable, the global config's vaultPath and lastVaultPath, and the "path" of a .sync82.json found at cwd or one of its parents. Paths are made absolute and listed once each.

func DataDir

func DataDir(homeDir string) string

DataDir returns sync82's data directory, <homeDir>/.sync82.

func DeleteFiles

func DeleteFiles(homeDir string, files []string) []error

DeleteFiles removes every file in files, then removes the data directory under homeDir when it is left empty. It returns one error per file that could not be removed; a file already gone is not an error.

func PurgeCandidates

func PurgeCandidates(homeDir string) []string

PurgeCandidates returns every existing file a purge deletes from the data directory under homeDir: the purgeFileNames entries plus every config.json.corrupt-* file. Nothing else in the directory is listed.

func TargetNames

func TargetNames() []string

TargetNames returns the names of every install target, in Targets order.

func TargetNamesIn

func TargetNamesIn(targets []Target) []string

TargetNamesIn returns the names of every target in targets, in order.

Types

type Env

type Env struct {
	GOOS     string
	HomeDir  string
	Getenv   func(key string) string
	LookPath func(file string) (string, error)
}

Env is the host environment the targets resolve their paths and detection against: the operating system, the home directory, an environment variable lookup, and a PATH lookup.

func HostEnv

func HostEnv(homeDir string) Env

HostEnv returns the Env of the running process with homeDir as its home directory.

type Kind

type Kind string

Kind distinguishes the two installer strategies: a "cli" target is installed by invoking the client's own MCP subcommands; a "file" target is installed by read-merge-write of a JSON config file.

const (
	KindCLI  Kind = "cli"
	KindFile Kind = "file"
)

Kind values: KindCLI for targets managed through the client's own subcommands, KindFile for targets managed by editing JSON files.

type Result

type Result string

Result is the outcome of installing into, or uninstalling from, a single target.

const (
	ResultOK     Result = "ok"
	ResultSkip   Result = "skip"
	ResultManual Result = "manual"
	ResultFail   Result = "fail"
)

Result values: ResultOK means the registration was written or removed, ResultSkip means the target was unsupported, not detected or had nothing to remove, ResultManual means a config file holds comments or trailing commas, so it was left unchanged and the entry printed to add by hand, and ResultFail means the operation failed.

func InstallTarget

func InstallTarget(ctx context.Context, t Target, env Env, binaryPath string, stdout, stderr io.Writer) Result

InstallTarget installs sync82 into a single target, dispatching by kind, and prints "configured." for a new registration or "updated." when one already existed, followed by any warning. A target unsupported on env.GOOS or not detected is skipped. stdout/stderr receive the progress lines; a CLI target's MCP-add subprocess also inherits them (plus stdin), so its output and prompts reach the user directly.

binaryPath is the absolute path of the sync82 binary the client is configured to launch.

func UninstallTarget

func UninstallTarget(ctx context.Context, t Target, env Env, stdout, stderr io.Writer) Result

UninstallTarget removes sync82's registration from a single target. A CLI target is cleaned through its own CLI and skipped when its client is not detected; a file target has the sync82 key deleted from each of its RemovePaths files whether or not its client is still installed. A target with nothing registered is reported as "not configured, skipping" and returns ResultSkip. Warnings are printed after the status line.

type Shape

type Shape struct {
	Key   string
	Entry func(binaryPath string) map[string]any
}

Shape describes where a client's JSON config keeps its MCP servers: Key is the top-level object holding one entry per server, and Entry builds sync82's entry for binaryPath. Entry is nil for a shape that is only ever read or cleaned, never written.

type Target

type Target struct {
	Name string
	Kind Kind

	// Unsupported, when set and returning a non-empty reason, marks the
	// target as unavailable on env.GOOS; it is then never detected, and
	// install and uninstall skip it.
	Unsupported func(env Env) string
	// A target is detected when DetectCmd is on PATH or any directory
	// returned by DetectDirs exists. Either may be empty.
	DetectCmd  string
	DetectDirs func(env Env) []string

	// CLI targets only. Command is the client's executable. Args returns
	// its MCP-add arguments for binaryPath. GetArgs exits with status 0
	// only while sync82 is registered. RemoveArgs returns the arguments
	// removing sync82 from one scope; a client without scopes receives ""
	// and ignores it. Scope, when set, marks a client keeping
	// registrations in several scopes and extracts from the GetArgs output
	// the scope of the registration it reports, or "" when none is named.
	Command    string
	Args       func(binaryPath string) []string
	GetArgs    []string
	RemoveArgs func(scope string) []string
	Scope      func(getOutput []byte) string

	// File targets only. Shape is the layout of the target's JSON config
	// files. Install merges sync82's entry into every ConfigPaths file.
	// Uninstall cleans every RemovePaths file (ConfigPaths when nil).
	Shape       Shape
	ConfigPaths func(env Env) []string
	RemovePaths func(env Env) []string
}

Target describes one MCP client install target.

func DetectedIn

func DetectedIn(targets []Target, env Env) []Target

DetectedIn returns the targets of targets detected on env, in order.

func Find

func Find(name string) (Target, bool)

Find returns the target named name in Targets, if any.

func FindIn

func FindIn(targets []Target, name string) (Target, bool)

FindIn returns the target named name in targets, if any.

func UninstallCandidatesIn added in v1.2.0

func UninstallCandidatesIn(targets []Target, env Env) []Target

UninstallCandidatesIn returns the targets of targets an uninstall with no target acts on, in targets order: every detected one, plus every file target that isn't detected any more but whose config files still hold a sync82 entry (its client was removed, or moved off PATH), so the entry isn't left behind.

func (Target) Detected

func (t Target) Detected(env Env) bool

Detected reports whether the client is installed on env: the target is supported on env.GOOS and either DetectCmd resolves on PATH or one of the DetectDirs directories exists.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL