Documentation
¶
Overview ¶
Package install is the agent-neutral configuration engine behind `graphmaster install` / `uninstall`.
Agent adapters describe the edits they want as a Plan: a list of FileChange values, each targeting one file in one Format:
- FormatJSON: JSON or JSONC edited through github.com/tailscale/hujson so comments, ordering and unrelated keys survive. Ops: JSONSet (object member at a JSON pointer) and JSONAppend (array element).
- FormatTOML: a marker block (# graphmaster:begin v1 ... # graphmaster:end) appended or replaced in place; the whole file is re-parsed with go-toml before anything is written.
- FormatMarkdown: a marker block (<!-- graphmaster:begin v1 --> ... <!-- graphmaster:end -->).
- FormatGenerated: a file graphmaster owns entirely (e.g. the OpenCode plugin).
The Engine applies plans, taking a timestamped backup of every file it touches the first time and recording pre/post hashes plus the exact insertions in install-state.json. Install is idempotent. Uninstall restores a file byte-for-byte from its backup when the file still has the post-install hash; otherwise it surgically removes only graphmaster's own insertions. Every operation can run as a dry run that reports unified diffs.
Index ¶
- Constants
- func Pointer(tokens ...string) string
- func StandardizeJSON(b []byte) ([]byte, error)
- type Action
- type BinaryLocator
- type BinaryPath
- type Block
- type CheckStatus
- type Component
- type Container
- type Engine
- type Env
- type FileChange
- type FileRecord
- type FileResult
- type Format
- type Insertion
- type InsertionKind
- type JSONAppend
- type JSONSet
- type Op
- type OpCheck
- type Options
- type Plan
- type Report
- type State
Constants ¶
const BinaryName = "graphmaster"
BinaryName is the executable name looked up on PATH.
const MarkerVersion = 1
MarkerVersion is written into every begin marker.
const StateFileName = "install-state.json"
StateFileName is the manifest written next to graphmaster's config.toml.
Variables ¶
This section is empty.
Functions ¶
func Pointer ¶
Pointer builds an RFC 6901 JSON pointer from unescaped reference tokens, e.g. Pointer("mcpServers", "graphmaster") == "/mcpServers/graphmaster".
func StandardizeJSON ¶
StandardizeJSON converts JSONC (comments, trailing commas) to standard JSON suitable for encoding/json, e.g. for doctor checks.
Types ¶
type Action ¶
type Action string
Action is what an operation did (or would do) to a file.
const ( ActionNone Action = "unchanged" ActionCreate Action = "create" ActionUpdate Action = "update" ActionRestore Action = "restore" // byte-exact restore from backup ActionDelete Action = "delete" // file graphmaster created removed ActionSurgical Action = "remove-entries" // only graphmaster entries removed ActionMissing Action = "missing" // recorded file no longer exists )
type BinaryLocator ¶
type BinaryLocator struct {
Executable func() (string, error)
LookPath func(string) (string, error)
EvalSymlinks func(string) (string, error)
// TempDirs are roots whose binaries are considered ephemeral
// (default: os.TempDir()).
TempDirs []string
}
BinaryLocator finds a stable absolute path to the graphmaster binary for agent configs. Function fields default to the os/exec/filepath versions.
func (BinaryLocator) Resolve ¶
func (l BinaryLocator) Resolve() (BinaryPath, error)
Resolve picks, in order:
- the Homebrew prefix bin symlink when running from a Cellar/Caskroom version directory (survives `brew upgrade`);
- a PATH entry resolving to the running executable (keeps symlinks);
- the running executable itself, unless it is a temporary build (`go run`, go-build dirs, TempDir), in which case an installed graphmaster on PATH is used or an error is returned.
type BinaryPath ¶
BinaryPath is a resolved binary location.
func ResolveBinary ¶
func ResolveBinary() (BinaryPath, error)
ResolveBinary resolves the running graphmaster binary with defaults.
type Block ¶
type Block struct {
// ID distinguishes several blocks in one file; "" is the default block.
ID string
Body string
}
Block is a marker-delimited text block for TOML and Markdown files.
type CheckStatus ¶
type CheckStatus string
CheckStatus is how far a file matches one desired plan edit.
const ( CheckOK CheckStatus = "ok" // exactly what the plan wants CheckStale CheckStatus = "stale" // a graphmaster entry exists but differs CheckMissing CheckStatus = "missing" // no graphmaster entry CheckInvalid CheckStatus = "invalid" // the file cannot be read or parsed )
type Component ¶
type Component string
Component groups plan edits by what they do for the agent.
func Classify ¶
func Classify(fc FileChange, op Op) Component
Classify guesses what an edit is for from its target and content; it needs no knowledge of a particular agent.
type Container ¶
Container is a JSON object or array created by an agent's insertions; it is removed on uninstall once empty.
type Engine ¶
type Engine struct {
// contains filtered or unexported fields
}
Engine applies and reverts plans, keeping install-state.json in sync.
func (*Engine) Install ¶
Install brings every file in plans to its desired state. All files are parsed and edited in memory first; any error (corrupt JSON, invalid TOML, conflicting definitions) aborts before a single byte is written. Files an agent touched in an earlier install but no longer lists are reverted.
type Env ¶
type Env struct {
// LookupEnv defaults to os.LookupEnv.
LookupEnv func(string) (string, bool)
// Now defaults to time.Now; it names backup directories.
Now func() time.Time
}
Env abstracts the process environment so tests can inject a temp HOME. The zero value uses the real environment and clock.
func EnvWithHome ¶
EnvWithHome returns an Env whose HOME is home and which ignores every other variable (XDG_CONFIG_HOME included). Intended for tests.
func (Env) ConfigHome ¶
ConfigHome returns $XDG_CONFIG_HOME when absolute, else $HOME/.config.
type FileChange ¶
type FileChange struct {
// Path is absolute.
Path string
Format Format
// Ops apply to FormatJSON (JSONSet, JSONAppend) and to FormatTOML /
// FormatMarkdown (Block).
Ops []Op
// Content is the full file for FormatGenerated.
Content []byte
// Mode is used when FormatGenerated creates the file (default 0644).
Mode fs.FileMode
}
FileChange describes the desired graphmaster state of one file.
type FileRecord ¶
type FileRecord struct {
Path string `json:"path"`
Format Format `json:"format"`
// Existed reports whether the file existed before the first install.
Existed bool `json:"existed"`
// PreHash is the sha256 of the file before the first install ("" if absent).
PreHash string `json:"pre_hash,omitempty"`
// PostHash is the sha256 after graphmaster's latest write.
PostHash string `json:"post_hash"`
// Backup holds the pre-install bytes ("" if the file did not exist).
Backup string `json:"backup,omitempty"`
// Restorable is false once the user edited the file between two
// graphmaster writes: a backup restore would then lose their edit.
Restorable bool `json:"restorable"`
Insertions []Insertion `json:"insertions"`
Created []Container `json:"created,omitempty"`
// CreatedDirs are parent directories graphmaster created, innermost last.
CreatedDirs []string `json:"created_dirs,omitempty"`
}
FileRecord is the manifest entry for one touched file.
type FileResult ¶
type FileResult struct {
Path string
Agents []string
Action Action
// Diff is a unified diff of the change ("" when unchanged).
Diff string
Note string
}
FileResult reports one file.
type Insertion ¶
type Insertion struct {
Agent string `json:"agent"`
Kind InsertionKind `json:"kind"`
Pointer string `json:"pointer,omitempty"`
Value json.RawMessage `json:"value,omitempty"`
// Prev is the member value graphmaster replaced; restored on removal.
Prev json.RawMessage `json:"prev,omitempty"`
// Marker is the block id ("" for the default block).
Marker string `json:"marker,omitempty"`
// Sep is the separator inserted before an appended marker block.
Sep string `json:"sep,omitempty"`
}
Insertion is one exact edit graphmaster made to a file.
type InsertionKind ¶
type InsertionKind string
InsertionKind names what an insertion added.
const ( KindJSONMember InsertionKind = "json_member" // object member at Pointer KindJSONElement InsertionKind = "json_element" // array element Value at Pointer KindMarker InsertionKind = "marker" // marker block Marker KindFile InsertionKind = "file" // whole generated file )
type JSONAppend ¶
JSONAppend ensures the array at Pointer contains Value, creating the array and missing parents. Elements recorded by an earlier install that are no longer desired are removed first, so changing a hook command replaces the old element instead of accumulating copies.
type JSONSet ¶
type JSONSet struct {
Pointer string
// Value is any JSON-marshalable value; json.RawMessage is used verbatim
// (key order preserved).
Value any
}
JSONSet makes the object member at Pointer equal Value, creating missing parent objects. A different pre-existing value is replaced and restored on uninstall.
type Op ¶
type Op interface {
// contains filtered or unexported methods
}
Op is one desired edit; see JSONSet, JSONAppend and Block.
type OpCheck ¶
type OpCheck struct {
Path string
Format Format
Op Op
Component Component
Status CheckStatus
// Found is graphmaster's current text in the file: the JSON member, the
// array elements recognized as graphmaster's, the marker block or the
// whole generated file.
Found []string
// Index is the array position of the matching (or stale) element for
// JSONAppend; -1 otherwise.
Index int
// Binaries are the absolute graphmaster executable paths Found refers to.
Binaries []string
// Err explains CheckInvalid.
Err error
}
OpCheck is the read-only verdict for one op of a plan (or one generated file, whose Op is nil).
func CheckPlan ¶
CheckPlan compares p with the files on disk without modifying anything. st (may be nil) identifies array elements graphmaster wrote earlier, so a hook installed with another binary path is reported stale, not missing; without it, elements mentioning graphmaster are recognized by content.
type Options ¶
type Options struct {
// DryRun computes the report (with diffs) without writing anything.
DryRun bool
}
Options tunes Install and Uninstall.
type Plan ¶
type Plan struct {
// Agent identifies the adapter ("claude", "codex", ...). Insertions are
// recorded per agent so agents can be uninstalled independently.
Agent string
Files []FileChange
}
Plan is the set of edits one agent adapter wants.
type Report ¶
type Report struct {
DryRun bool
Files []FileResult
}
Report is the outcome of Install or Uninstall.
type State ¶
type State struct {
Version int `json:"version"`
Files map[string]*FileRecord `json:"files"`
}
State is the install-state.json manifest.
func (*State) FilesOf ¶
func (s *State) FilesOf(agent string) []*FileRecord
FilesOf returns the records touched by agent, sorted by path.