hookinstaller

package
v0.0.0-beta.32 Latest Latest
Warning

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

Go to latest
Published: Apr 17, 2026 License: MIT Imports: 9 Imported by: 0

Documentation

Overview

Package hookinstaller registers docsiq's SessionStart hook with the various AI clients (Claude Code, Cursor, GitHub Copilot, Codex CLI).

Port of kgraph's hooks/install.ts. Key differences:

  • POSIX-only: no hook.mjs, no hook.ps1, no Windows branches.
  • Stdlib JSON with json.RawMessage for deep-merge safety.
  • Atomic writes (temp-file + rename).
  • Per-client "recognize our entry" is driven by the hook command path — so a user who moves ~/.docsiq/hooks/hook.sh can still uninstall the stale entry by rerunning against the old path.

Index

Constants

This section is empty.

Variables

View Source
var ErrConfigUnavailable = errors.New("config path unavailable")

ErrConfigUnavailable is returned by ConfigPath when the client's config directory cannot be derived (no $HOME, etc).

View Source
var HookScript []byte

HookScript is the POSIX shell SessionStart hook. It ships embedded in the binary so `docsiq hooks install` never has to shell out to locate a source tree. See assets/hook.sh for the script itself.

Functions

func ExtractHookScript

func ExtractHookScript(dest string) error

ExtractHookScript writes the embedded hook.sh to dest with 0o755 perms. Creates the parent directory if missing. Overwrites existing files — callers that want to preserve a user-modified hook should check first.

func Names

func Names() []string

Names returns the sorted list of supported client names. Useful for flag validation and help text.

Types

type ClaudeInstaller

type ClaudeInstaller struct{}

ClaudeInstaller targets ~/.claude/settings.json.

Config shape (Claude Code, current as of kgraph reference):

{
  "hooks": {
    "SessionStart": [
      { "hooks": [ { "type": "command", "command": "/path/to/hook.sh" } ] }
    ]
  }
}

We preserve all other top-level keys (mcpServers, permissions, etc) and only mutate hooks.SessionStart. Within SessionStart, we also preserve any entries that aren't ours.

func (ClaudeInstaller) ConfigPath

func (ClaudeInstaller) ConfigPath() (string, error)

func (ClaudeInstaller) Install

func (c ClaudeInstaller) Install(hookPath string) error

func (ClaudeInstaller) Name

func (ClaudeInstaller) Name() string

func (ClaudeInstaller) Status

func (c ClaudeInstaller) Status() (bool, string)

func (ClaudeInstaller) Uninstall

func (c ClaudeInstaller) Uninstall() error

type CodexInstaller

type CodexInstaller struct{}

CodexInstaller targets ~/.codex/hooks.json (per kgraph reference).

Shape — kgraph wrote a flat map:

{"hooks":{"SessionStart":"<cmd>"}}

We keep the same shape for wire compatibility. Codex CLI's hook API is less stable than Claude Code's, so this is also flagged as a best-effort integration.

func (CodexInstaller) ConfigPath

func (CodexInstaller) ConfigPath() (string, error)

func (CodexInstaller) Install

func (c CodexInstaller) Install(hookPath string) error

func (CodexInstaller) Name

func (CodexInstaller) Name() string

func (CodexInstaller) Status

func (c CodexInstaller) Status() (bool, string)

func (CodexInstaller) Uninstall

func (c CodexInstaller) Uninstall() error

type CopilotInstaller

type CopilotInstaller struct{}

CopilotInstaller — GitHub Copilot CLI/VSCode integration.

NOTE — config path taken from kgraph's install.ts:

~/.config/github-copilot/hooks.json

kgraph's shape was a flat {"hooks":{"session-start":"<cmd>"}} map. That's what we mirror. GitHub Copilot does not officially document a SessionStart hook surface area as of this writing — treat this as a best-effort placeholder until Copilot publishes stable hook APIs.

func (CopilotInstaller) ConfigPath

func (CopilotInstaller) ConfigPath() (string, error)

func (CopilotInstaller) Install

func (c CopilotInstaller) Install(hookPath string) error

func (CopilotInstaller) Name

func (CopilotInstaller) Name() string

func (CopilotInstaller) Status

func (c CopilotInstaller) Status() (bool, string)

func (CopilotInstaller) Uninstall

func (c CopilotInstaller) Uninstall() error

type CursorInstaller

type CursorInstaller struct{}

CursorInstaller writes to ~/.cursor/docsiq-hooks.json.

NOTE — schema guess flagged for verification: kgraph's install.ts does not wire Cursor into hook registration (only into MCP registration). Cursor has no canonical "SessionStart hook" primitive the way Claude Code does, so we stash our entry in a sibling docsiq-specific file and document that a user-level shell wrapper / workspace automation is expected to call hook.sh themselves. The JSON we write tracks WHICH hook is registered, so `status` and `uninstall` still work.

Shape:

{
  "hooks": { "SessionStart": { "command": "/path/to/hook.sh" } }
}

func (CursorInstaller) ConfigPath

func (CursorInstaller) ConfigPath() (string, error)

func (CursorInstaller) Install

func (c CursorInstaller) Install(hookPath string) error

func (CursorInstaller) Name

func (CursorInstaller) Name() string

func (CursorInstaller) Status

func (c CursorInstaller) Status() (bool, string)

func (CursorInstaller) Uninstall

func (c CursorInstaller) Uninstall() error

type Installer

type Installer interface {
	Name() string
	ConfigPath() (string, error)
	Install(hookPath string) error
	Uninstall() error
	Status() (installed bool, detail string)
}

Installer is the contract every per-client installer satisfies.

Name — short client identifier ("claude", "cursor", ...). ConfigPath — absolute path the installer will read/write. Returning

an error here means "config dir cannot be determined"
(e.g. $HOME is unset); this is not a user-visible error
unless Install/Status is actually called.

Install — writes the hook entry to the config, merging with any

pre-existing content. Idempotent.

Uninstall — removes ONLY our entry; leaves unrelated keys intact. Status — returns (installed, detail) where detail is a short

human-readable string (path, reason missing, etc).

func All

func All() []Installer

All returns one Installer per supported client. Callers typically iterate this list for the "install/uninstall everything" path. The slice order is stable so CLI output is deterministic.

func ByName

func ByName(name string) (Installer, error)

ByName returns the Installer for name, or an error if the name is not one of the supported clients. Names are lowercase.

Jump to

Keyboard shortcuts

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