hookinstaller

package
v0.0.2 Latest Latest
Warning

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

Go to latest
Published: Apr 23, 2026 License: MIT Imports: 10 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 0o700 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 {
	// contains filtered or unexported fields
}

ClaudeInstaller targets ~/.claude/settings.json.

Config shape — schema source: https://docs.claude.com/en/docs/claude-code/hooks fetched 2026-04-17. Claude Code's SessionStart hook is a three-level nested structure: event -> matcher-group -> command-list:

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

Per docs, SessionStart supports optional matcher values ("startup", "resume", "clear", "compact"); omitting the matcher means the group activates on every occurrence. We omit it so our hook always fires.

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 (c 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 {
	// contains filtered or unexported fields
}

CodexInstaller targets ~/.codex/hooks.json.

UNVERIFIED — OpenAI Codex CLI does not publicly document a SessionStart hook API as of 2026-04-17. Doc sources checked:

Schema below mirrors kgraph's original guess (wrong config format AND wrong event name relative to real Codex, but preserved for wire compatibility with existing kgraph users until Codex publishes a stable hook API):

config path: ~/.codex/hooks.json
shape:       {"hooks": {"SessionStart": "<cmd>"}}

func (CodexInstaller) ConfigPath

func (c 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 {
	// contains filtered or unexported fields
}

CopilotInstaller — GitHub Copilot CLI integration.

UNVERIFIED — GitHub Copilot CLI does not publicly document a SessionStart hook API as of 2026-04-17. Doc sources checked:

Schema below mirrors kgraph's original guess:

config path: ~/.config/github-copilot/hooks.json
shape:       {"hooks": {"session-start": "<cmd>"}}

func (CopilotInstaller) ConfigPath

func (c 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 {
	// contains filtered or unexported fields
}

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

UNVERIFIED — Cursor does not publicly document a SessionStart hook API as of 2026-04-17. Attempted doc sources returned empty / 404:

Cursor's primary extensibility surface is MCP (not shell hooks) and kgraph's install.ts only wires Cursor into MCP registration. Schema below mirrors kgraph's original guess; we stash our entry in a sibling docsiq-specific file so we at least have a place to track `status` and `uninstall` without polluting ~/.cursor/settings.json.

Shape (unverified guess):

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

func (CursorInstaller) ConfigPath

func (c 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