daemon

package
v0.18.0 Latest Latest
Warning

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

Go to latest
Published: Apr 7, 2026 License: MIT Imports: 29 Imported by: 0

Documentation

Index

Constants

View Source
const (
	// DefaultPort is the well-known daemon listening port.
	DefaultPort = 19285
	// DefaultChromePort is the well-known Chrome proxy port.
	DefaultChromePort = 19286
	// DefaultProxyPort is the well-known HTTPS proxy port.
	DefaultProxyPort = 19287

	// DockerHost is the hostname Docker provides for reaching the host machine
	// from inside a container. Enabled by --add-host=host.docker.internal:host-gateway.
	DockerHost = "host.docker.internal"
)

Variables

This section is empty.

Functions

func ConnectedPath added in v0.14.0

func ConnectedPath() string

ConnectedPath returns the default path for the connected PIDs file.

func GenerateToken

func GenerateToken() (string, error)

GenerateToken returns a cryptographically random 32-byte hex string.

func GetHookSnapshot added in v0.15.0

func GetHookSnapshot(addr, token string) (map[string]hookevents.SessionSnapshot, error)

GetHookSnapshot fetches the current per-session hook state from the daemon.

func GetLogMode added in v0.15.0

func GetLogMode(addr, token string) (string, error)

GetLogMode fetches the current traffic log mode from the daemon.

func GetTrackerDiagnose added in v0.15.0

func GetTrackerDiagnose(addr, token string) ([]tracker.TrackerStatus, error)

GetTrackerDiagnose fetches tracker credential status from the daemon.

func InfoPath added in v0.14.0

func InfoPath() string

InfoPath returns the default path for the daemon info file (~/.human/daemon.json).

func IsProcessAlive added in v0.16.0

func IsProcessAlive(pid int) bool

IsProcessAlive checks whether a process with the given PID is still running.

func LoadOrCreateToken

func LoadOrCreateToken() (string, error)

LoadOrCreateToken reads the token from disk, or generates and persists a new one.

func LogPath added in v0.16.0

func LogPath() string

LogPath returns the path to the daemon log file (~/.human/daemon.log).

func ParseHookEventArgs added in v0.15.0

func ParseHookEventArgs(args []string) hookevents.Event

ParseHookEventArgs converts daemon request args into a hook event. Expected args: [event, session_id, cwd, notification_type, tool_name, error_type].

func PidPath added in v0.16.0

func PidPath() string

PidPath returns the path to the daemon PID file (~/.human/daemon.pid).

func ReadAlivePid added in v0.16.0

func ReadAlivePid() (int, bool)

ReadAlivePid reads the PID file and checks if the process is alive. Returns (0, false) if no PID file exists or the process is dead.

func ReadConnected added in v0.14.0

func ReadConnected(path string) []int

ReadConnected reads connected PIDs from path. Returns nil on any error.

func RemoveConnected added in v0.14.0

func RemoveConnected(path string)

RemoveConnected removes the connected PIDs file (best-effort).

func RemoveInfo added in v0.14.0

func RemoveInfo()

RemoveInfo removes the daemon info file (best-effort).

func RemovePidFile added in v0.16.0

func RemovePidFile()

RemovePidFile removes the PID file (best-effort).

func RunRemote

func RunRemote(addr, token string, args []string, version string) (int, error)

RunRemote connects to the daemon at addr, sends the CLI args, and returns the exit code. Stdout and stderr are written to os.Stdout and os.Stderr.

func RunRemoteCapture added in v0.15.0

func RunRemoteCapture(addr, token string, args []string) ([]byte, error)

RunRemoteCapture connects to the daemon and runs args, returning stdout as bytes instead of printing to os.Stdout.

func SendConfirmDecision added in v0.18.0

func SendConfirmDecision(addr, token, id string, approved bool) error

SendConfirmDecision sends a confirmation decision for a pending destructive operation.

func SetLogMode added in v0.15.0

func SetLogMode(addr, token, mode string) (string, error)

SetLogMode sets the traffic log mode on the daemon. Returns the new mode.

func TokenPath

func TokenPath() string

TokenPath returns the default path for the daemon token file.

func WriteConnected added in v0.14.0

func WriteConnected(path string, pids []int) error

WriteConnected atomically writes the connected PIDs to path.

func WriteInfo added in v0.14.0

func WriteInfo(info DaemonInfo) error

WriteInfo writes the daemon info as JSON to InfoPath with restricted permissions.

func WritePidFile added in v0.16.0

func WritePidFile(pid int) error

WritePidFile writes the given PID to the PID file.

Types

type BrowserOpener added in v0.7.0

type BrowserOpener interface {
	Open(url string) error
}

BrowserOpener opens a URL in the browser. Extracted for testability.

type ConnectedTracker added in v0.14.0

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

ConnectedTracker maintains a thread-safe set of recently-seen client PIDs. Each PID has a last-seen timestamp; Prune removes entries older than a TTL.

func NewConnectedTracker added in v0.14.0

func NewConnectedTracker() *ConnectedTracker

NewConnectedTracker creates an empty tracker.

func (*ConnectedTracker) PIDs added in v0.14.0

func (t *ConnectedTracker) PIDs() []int

PIDs returns a sorted snapshot of currently tracked PIDs.

func (*ConnectedTracker) Prune added in v0.14.0

func (t *ConnectedTracker) Prune(ttl time.Duration)

Prune removes PIDs not seen within ttl.

func (*ConnectedTracker) Touch added in v0.14.0

func (t *ConnectedTracker) Touch(pid int)

Touch records or refreshes a PID with the current time.

type DaemonInfo added in v0.14.0

type DaemonInfo struct {
	Addr       string        `json:"addr"`
	ChromeAddr string        `json:"chrome_addr,omitempty"`
	ProxyAddr  string        `json:"proxy_addr,omitempty"`
	Token      string        `json:"token"`
	PID        int           `json:"pid"`
	Projects   []ProjectInfo `json:"projects,omitempty"`
}

DaemonInfo holds the runtime details of a running daemon instance.

func ReadInfo added in v0.14.0

func ReadInfo() (DaemonInfo, error)

ReadInfo reads and unmarshals the daemon info from InfoPath.

func (DaemonInfo) IsAlive added in v0.14.0

func (d DaemonInfo) IsAlive() bool

IsAlive checks whether the daemon process identified by PID is still running.

func (DaemonInfo) IsReachable added in v0.14.0

func (d DaemonInfo) IsReachable() bool

IsReachable checks whether the daemon is accepting TCP connections at its advertised address. This works across process namespaces (e.g. host ↔ devcontainer) where PID-based checks fail.

type HookEventStore added in v0.15.0

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

HookEventStore is a thread-safe ring buffer of recent hook events. It stores raw events and can derive per-session snapshots on demand. Subscribers are notified (non-blocking) whenever a new event is appended.

func NewHookEventStore added in v0.15.0

func NewHookEventStore() *HookEventStore

NewHookEventStore creates an empty store.

func (*HookEventStore) Append added in v0.15.0

func (s *HookEventStore) Append(evt hookevents.Event)

Append adds a hook event. If the buffer exceeds maxHookEvents, the oldest event is dropped. All subscribers are notified.

func (*HookEventStore) Snapshot added in v0.15.0

func (s *HookEventStore) Snapshot() map[string]hookevents.SessionSnapshot

Snapshot returns the current per-session state derived from all stored events.

func (*HookEventStore) Subscribe added in v0.15.0

func (s *HookEventStore) Subscribe() chan struct{}

Subscribe returns a channel that receives a signal whenever a new event is appended. The channel has a buffer of 1 so a single pending notification is coalesced. Call Unsubscribe to clean up.

func (*HookEventStore) Unsubscribe added in v0.15.0

func (s *HookEventStore) Unsubscribe(ch chan struct{})

Unsubscribe removes a previously registered channel and closes it.

type PendingConfirm added in v0.18.0

type PendingConfirm struct {
	ID        string `json:"id"`
	Operation string `json:"operation"` // "DeleteIssue", "EditIssue"
	Tracker   string `json:"tracker"`   // tracker kind, e.g. "jira", "linear"
	Key       string `json:"key"`       // issue key, e.g. "KAN-1"
	Prompt    string `json:"prompt"`
	CreatedAt string `json:"created_at"`
	ClientPID int    `json:"client_pid"` // PID of the Claude instance that triggered the operation
}

PendingConfirm is the wire type for a single pending destructive operation awaiting user confirmation via the TUI.

func GetPendingConfirms added in v0.18.0

func GetPendingConfirms(addr, token string) ([]PendingConfirm, error)

GetPendingConfirms fetches pending destructive operation confirmations from the daemon.

type PendingConfirmStore added in v0.18.0

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

PendingConfirmStore is a thread-safe store for destructive operations awaiting user confirmation. The daemon adds entries when it intercepts destructive commands; the TUI polls the snapshot and resolves them.

func NewPendingConfirmStore added in v0.18.0

func NewPendingConfirmStore() *PendingConfirmStore

NewPendingConfirmStore creates an empty store.

func (*PendingConfirmStore) Add added in v0.18.0

Add stores a pending confirmation. The caller should block on pc.Decision after calling Add.

func (*PendingConfirmStore) Cleanup added in v0.18.0

func (s *PendingConfirmStore) Cleanup(maxAge time.Duration)

Cleanup rejects and removes all pending confirmations older than maxAge.

func (*PendingConfirmStore) Len added in v0.18.0

func (s *PendingConfirmStore) Len() int

Len returns the number of pending confirmations.

func (*PendingConfirmStore) Resolve added in v0.18.0

func (s *PendingConfirmStore) Resolve(id string, approved bool, approverPID int) error

Resolve sends the decision to the waiting goroutine and removes the entry. approverPID is the PID of the client resolving the confirmation; if it matches the original requester's PID (and is non-zero), the call is rejected to prevent self-approval of destructive operations.

func (*PendingConfirmStore) Snapshot added in v0.18.0

func (s *PendingConfirmStore) Snapshot() []PendingConfirm

Snapshot returns all pending confirmations as wire types for the TUI.

type PendingConfirmation added in v0.18.0

type PendingConfirmation struct {
	ID        string
	Operation string // "DeleteIssue", "EditIssue"
	Tracker   string // tracker kind, e.g. "jira"
	Key       string // issue key, e.g. "KAN-1"
	Prompt    string // human-readable, e.g. "Delete KAN-1?"
	ClientPID int    // PID of the Claude instance that triggered the operation
	CreatedAt time.Time
	Decision  chan bool // the blocked goroutine waits on this; true = approved
}

PendingConfirmation represents a destructive operation that is blocked waiting for user confirmation via the TUI.

type ProjectEntry added in v0.18.0

type ProjectEntry struct {
	Name string // from .humanconfig project: field, or directory basename
	Dir  string // absolute path to project directory
}

ProjectEntry holds the loaded config context for one registered project directory.

func (ProjectEntry) EnvLookup added in v0.18.0

func (p ProjectEntry) EnvLookup() config.EnvLookup

EnvLookup returns a per-project scoped environment variable lookup function. It implements a 4-level precedence chain for each key:

  1. HUMAN_{PROJECT}_{KEY} — per-project override (e.g. HUMAN_INFRA_GITHUB_WORK_TOKEN)
  2. {KEY} via os.LookupEnv — global fallback (e.g. GITHUB_WORK_TOKEN)

The caller (ApplyEnvOverrides) constructs keys like PREFIX_SUFFIX and PREFIX_INSTANCE_SUFFIX. This lookup prepends HUMAN_{PROJECT}_ and checks that first, falling back to os.LookupEnv for the original key.

type ProjectInfo added in v0.18.0

type ProjectInfo struct {
	Name string `json:"name"`
	Dir  string `json:"dir"`
}

ProjectInfo describes a registered project in a running daemon.

type ProjectRegistry added in v0.18.0

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

ProjectRegistry maps project directories to their config entries. It is created at daemon startup and is read-only thereafter (no mutex needed).

func NewProjectRegistry added in v0.18.0

func NewProjectRegistry(dirs []string) (*ProjectRegistry, error)

NewProjectRegistry creates a registry from a list of project directories. Each directory must exist and contain a readable .humanconfig. If .humanconfig lacks a project: field, the directory basename is used as the name.

func (*ProjectRegistry) Entries added in v0.18.0

func (r *ProjectRegistry) Entries() []ProjectEntry

Entries returns all registered project entries.

func (*ProjectRegistry) Resolve added in v0.18.0

func (r *ProjectRegistry) Resolve(cwd string) (ProjectEntry, bool)

Resolve finds the ProjectEntry whose Dir is a prefix of the given cwd. Returns (entry, true) on match, (zero, false) if no match. When multiple entries match (nested dirs), the longest prefix wins because entries are sorted by path length descending.

func (*ProjectRegistry) Single added in v0.18.0

func (r *ProjectRegistry) Single() bool

Single returns true if there is exactly one registered project (backward compat mode).

type Request

type Request struct {
	Version   string            `json:"version"`
	Token     string            `json:"token"`
	Args      []string          `json:"args"`
	Env       map[string]string `json:"env,omitempty"`
	ClientPID int               `json:"client_pid,omitempty"` // parent PID (Claude process) for connection tracking
	Cwd       string            `json:"cwd,omitempty"`        // client working directory for project routing
}

Request is sent from the client to the daemon (one JSON line per connection).

type Response

type Response struct {
	Stdout        string `json:"stdout"`
	Stderr        string `json:"stderr"`
	ExitCode      int    `json:"exit_code"`
	AwaitCallback bool   `json:"await_callback,omitempty"`
	Callback      string `json:"callback,omitempty"`
	AwaitConfirm  bool   `json:"await_confirm,omitempty"`  // line 1: daemon paused, awaiting TUI confirmation
	ConfirmID     string `json:"confirm_id,omitempty"`     // unique identifier for the pending operation
	ConfirmPrompt string `json:"confirm_prompt,omitempty"` // human-readable prompt, e.g. "Delete JIRA-123?"
}

Response is sent from the daemon back to the client (one or more JSON lines per connection).

type Server

type Server struct {
	Addr             string
	Token            string
	SafeMode         bool
	CmdFactory       func() *cobra.Command
	Opener           BrowserOpener // used for OAuth relay; defaults to browser.DefaultOpener
	Logger           zerolog.Logger
	ConnectedPIDs    *ConnectedTracker                        // tracks client PIDs that have pinged; nil disables tracking
	HookEvents       *HookEventStore                          // in-memory hook event buffer; nil disables hook event tracking
	IssueFetcher     func() ([]TrackerIssuesResult, error)    // injected; fetches issues from configured trackers
	TrackerDiagnoser func(dir string) []tracker.TrackerStatus // injected; diagnoses tracker status with vault resolution
	Projects         *ProjectRegistry                         // multi-project routing; nil means single-project mode
	PendingConfirms  *PendingConfirmStore                     // pending destructive operation confirmations; nil disables
	// contains filtered or unexported fields
}

Server listens for incoming client connections and executes CLI commands.

func (*Server) ListenAndServe

func (s *Server) ListenAndServe(ctx context.Context) error

ListenAndServe starts the TCP listener and blocks until ctx is cancelled.

type TrackerIssuesResult added in v0.15.0

type TrackerIssuesResult struct {
	TrackerName string          `json:"tracker_name"`
	TrackerKind string          `json:"tracker_kind"`
	TrackerRole string          `json:"tracker_role,omitempty"`
	Project     string          `json:"project"`
	Issues      []tracker.Issue `json:"issues"`
	Err         string          `json:"error,omitempty"`
}

TrackerIssuesResult is the wire type for a single tracker/project's issues.

func GetTrackerIssues added in v0.15.0

func GetTrackerIssues(addr, token string) ([]TrackerIssuesResult, error)

GetTrackerIssues fetches open issues from all configured tracker projects via the daemon.

Jump to

Keyboard shortcuts

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