hooks

package
v0.3.22 Latest Latest
Warning

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

Go to latest
Published: Jun 12, 2026 License: MIT Imports: 14 Imported by: 0

Documentation

Overview

Package hooks installs and uninstalls the per-agent shell hooks that drive questmaster's state tracker. Each Installer knows how to render the small shell script, write it to the agent's config directory, and merge its hook entries into the agent-native config file with a `_questmaster` tag for safe round-trip uninstall.

Index

Constants

View Source
const AssetTag = "v1"

AssetTag is the tag value written into agent config files alongside hook entries we own. The tag identifies entries the installer is allowed to remove on uninstall. Bumping this value requires reviewing the round-trip behaviour for every agent's config format.

View Source
const QuestmasterSidecarVersion = "phase2-v1"

QuestmasterSidecarVersion is the marker version emitted by the Pi activity-sidecar contract that shells out to `questmaster hook pi`.

Variables

View Source
var ScriptTemplate string

ScriptTemplate is the embedded shell-script body. The `__AGENT__` placeholder is substituted with the agent name at install time.

Functions

func AgentList

func AgentList() []string

AgentList returns the canonical agent identifiers (sorted) — exported so cmd/hooks.go can render the human-readable status output without having to instantiate a Manager.

func RenderScript

func RenderScript(agent string) string

RenderScript fills the embedded template for a given agent. Exposed for installer implementations (and tests).

func ScriptHash

func ScriptHash(agent string) string

ScriptHash exposes a sha256 of the rendered script for the named agent. The Codex installer uses this for the `trusted_hash` field; surfaced here so tests can exercise the helper too.

Types

type ClaudeInstaller

type ClaudeInstaller struct {
	// Home is the resolved Claude config directory (~/.claude or
	// $CLAUDE_CONFIG_DIR). Override only in tests.
	Home string
}

ClaudeInstaller manages the Claude Code hook surface. Writes the script to ~/.claude/hooks/questmaster-state.sh and merges hook entries into ~/.claude/settings.json — Claude Code does not load hooks from settings.local.json, so writing there is a no-op.

func NewClaudeInstaller

func NewClaudeInstaller(home string) *ClaudeInstaller

NewClaudeInstaller resolves the Claude config directory. Pass an explicit home for tests; pass "" to honour $CLAUDE_CONFIG_DIR / $HOME.

func (*ClaudeInstaller) Install

func (c *ClaudeInstaller) Install() error

Install implements Installer.

func (*ClaudeInstaller) InstallWithOptions

func (c *ClaudeInstaller) InstallWithOptions(opts InstallOptions) error

InstallWithOptions installs Claude hooks with optional dry-run logging.

func (*ClaudeInstaller) Name

func (c *ClaudeInstaller) Name() string

Name implements Installer.

func (*ClaudeInstaller) Status

func (c *ClaudeInstaller) Status() Report

Status implements Installer.

func (*ClaudeInstaller) Uninstall

func (c *ClaudeInstaller) Uninstall() error

Uninstall implements Installer. Removes questmaster hook entries from settings.json (identified by command path) and deletes the installed script. Other user-managed hooks are left alone.

type CodexInstaller

type CodexInstaller struct {
	Home string
}

CodexInstaller manages the Codex hook surface. Writes the script to ~/.codex/hooks/questmaster-state.sh, merges tagged entries into ~/.codex/hooks.json, and records Codex's required trusted_hash state in ~/.codex/config.toml.

func NewCodexInstaller

func NewCodexInstaller(home string) *CodexInstaller

NewCodexInstaller resolves $CODEX_HOME / $HOME. Pass an explicit home for tests; pass "" to honour $CODEX_HOME / $HOME.

func (*CodexInstaller) Install

func (c *CodexInstaller) Install() error

Install implements Installer.

func (*CodexInstaller) InstallWithOptions

func (c *CodexInstaller) InstallWithOptions(opts InstallOptions) error

InstallWithOptions installs Codex hooks with optional dry-run logging.

func (*CodexInstaller) Name

func (c *CodexInstaller) Name() string

Name implements Installer.

func (*CodexInstaller) Status

func (c *CodexInstaller) Status() Report

Status implements Installer.

func (*CodexInstaller) Uninstall

func (c *CodexInstaller) Uninstall() error

Uninstall implements Installer. Removes tagged entries from hooks.json, removes questmaster's managed trust block from config.toml, and deletes the installed script. Untagged user hooks and config keys are left alone.

type InstallOptions

type InstallOptions struct {
	DryRun bool
	Log    io.Writer
	Now    func() time.Time
}

InstallOptions configures hook install side effects.

type Installer

type Installer interface {
	// Name is the agent identifier ("claude", "codex", "pi") used in CLI
	// arguments and the hook payload command.
	Name() string
	// Install writes/updates hooks on disk. Idempotent: re-running must
	// produce a byte-identical config file when nothing changed.
	Install() error
	// Uninstall removes only the entries the installer owns (tagged with
	// `_questmaster: v1`) and deletes the installed script file. Leaves
	// other user-managed hooks alone.
	Uninstall() error
	// Status reports the current install state. Never returns an error;
	// installer-internal problems surface in Report.Detail.
	Status() Report
}

Installer is the per-agent contract. Implementations are registered with Manager via RegisterDefault.

type Manager

type Manager struct {
	// contains filtered or unexported fields
}

Manager orchestrates a fixed set of installers.

func NewManager

func NewManager() *Manager

NewManager returns a Manager seeded with the built-in installers.

func (*Manager) CheckCurrent

func (m *Manager) CheckCurrent(agents []string) (bool, []Report, error)

CheckCurrent returns false if any selected agent isn't Current. Used by `hooks install --check`.

func (*Manager) Install

func (m *Manager) Install(agents []string) error

Install runs Install for the named agents (or all if empty).

func (*Manager) InstallWithOptions

func (m *Manager) InstallWithOptions(agents []string, opts InstallOptions) error

InstallWithOptions runs installation with optional dry-run/logging.

func (*Manager) Names

func (m *Manager) Names() []string

Names returns the registered agent names in stable order.

func (*Manager) Register

func (m *Manager) Register(inst Installer)

Register adds an installer to the manager. Used by tests to inject stub installers rooted at temp directories.

func (*Manager) Resolve

func (m *Manager) Resolve(name string) (Installer, error)

Resolve returns the installer for the named agent.

func (*Manager) Status

func (m *Manager) Status(agents []string) ([]Report, error)

Status returns one Report per requested agent (or all if empty).

func (*Manager) Uninstall

func (m *Manager) Uninstall(agents []string) error

Uninstall runs Uninstall for the named agents (or all if empty).

type OmpInstaller added in v0.3.12

type OmpInstaller struct {
	// AgentDir is the resolved omp agent directory ($PI_CODING_AGENT_DIR or
	// ~/.omp/agent). Override only in tests.
	AgentDir string
}

OmpInstaller manages the oh-my-pi activity-sidecar extension.

Unlike the Pi installer — which only tracks a marker for a sidecar published out-of-band — questmaster ships the omp sidecar itself and writes it directly into omp's auto-discovered extensions directory (~/.omp/agent/extensions). Status is therefore content-based: Current iff the on-disk file matches the shipped extension byte-for-byte.

func NewOmpInstaller added in v0.3.12

func NewOmpInstaller(agentDir string) *OmpInstaller

NewOmpInstaller resolves the omp agent directory. Pass an explicit dir for tests; pass "" to honour $PI_CODING_AGENT_DIR / $HOME.

func (*OmpInstaller) Install added in v0.3.12

func (o *OmpInstaller) Install() error

Install implements Installer.

func (*OmpInstaller) InstallWithOptions added in v0.3.12

func (o *OmpInstaller) InstallWithOptions(opts InstallOptions) error

InstallWithOptions writes the sidecar extension, optionally as a dry run. Idempotent: re-running writes a byte-identical file.

func (*OmpInstaller) Name added in v0.3.12

func (o *OmpInstaller) Name() string

Name implements Installer.

func (*OmpInstaller) Status added in v0.3.12

func (o *OmpInstaller) Status() Report

Status implements Installer.

func (*OmpInstaller) Uninstall added in v0.3.12

func (o *OmpInstaller) Uninstall() error

Uninstall implements Installer. Removes the installed sidecar; leaves any other user-managed omp extensions alone.

type PiInstaller

type PiInstaller struct {
	// Home is the resolved Pi config directory ($PI_HOME or ~/.pi).
	// Override only in tests.
	Home string
}

PiInstaller manages the Pi activity-sidecar marker file. The TypeScript sidecar writes the same marker at runtime so `questmaster hooks status pi` can detect stale non-symlink installs.

func NewPiInstaller

func NewPiInstaller(home string) *PiInstaller

NewPiInstaller resolves $PI_HOME / $HOME.

func (*PiInstaller) Install

func (p *PiInstaller) Install() error

Install implements Installer. It writes the current sidecar marker atomically and is idempotent.

func (*PiInstaller) InstallWithOptions

func (p *PiInstaller) InstallWithOptions(opts InstallOptions) error

InstallWithOptions writes the current marker.

func (*PiInstaller) Name

func (p *PiInstaller) Name() string

Name implements Installer.

func (*PiInstaller) Status

func (p *PiInstaller) Status() Report

Status implements Installer.

func (*PiInstaller) Uninstall

func (p *PiInstaller) Uninstall() error

Uninstall implements Installer.

type Report

type Report struct {
	Agent  string
	Status Status
	Detail string
}

Report is the per-agent status row.

type Status

type Status string

Status enumerates the per-agent installation states reported by `questmaster hooks status`.

const (
	StatusCurrent      Status = "Current"
	StatusOutdated     Status = "Outdated"
	StatusUntrusted    Status = "Untrusted"
	StatusModified     Status = "Modified"
	StatusNotInstalled Status = "NotInstalled"
)

Jump to

Keyboard shortcuts

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