Documentation
¶
Index ¶
- Constants
- func ConnectedPath() string
- func GenerateToken() (string, error)
- func GetHookSnapshot(addr, token string) (map[string]hookevents.SessionSnapshot, error)
- func GetLogMode(addr, token string) (string, error)
- func GetToolStats(addr, token string) (*stats.ToolStats, error)
- func GetTrackerDiagnose(addr, token string) ([]tracker.TrackerStatus, error)
- func InfoPath() string
- func IsProcessAlive(pid int) bool
- func IsReviewComplete(body string) bool
- func LoadOrCreateToken() (string, error)
- func LogPath() string
- func ParseEngineeringKeysFromHandoff(body string) []string
- func ParseHookEventArgs(args []string) hookevents.Event
- func PidPath() string
- func ReadAlivePid() (int, bool)
- func ReadConnected(path string) []int
- func RemoveConnected(path string)
- func RemoveInfo()
- func RemovePidFile()
- func RunAgentCleanup(ctx context.Context, store *HookEventStore, cleaner AgentCleaner, ...)
- func RunAgentZombieSweep(ctx context.Context, sweeper AgentZombieSweeper, logger zerolog.Logger)
- func RunRemote(addr, token string, args []string, version string) (int, error)
- func RunRemoteCapture(addr, token string, args []string) ([]byte, error)
- func SendConfirmDecision(addr, token, id string, approved bool) error
- func SetLogMode(addr, token, mode string) (string, error)
- func Subscribe(addr, token string) (<-chan SubscribeEvent, func(), error)
- func TokenPath() string
- func WriteConnected(path string, pids []int) error
- func WriteInfo(info DaemonInfo) error
- func WritePidFile(pid int) error
- type AgentCleaner
- type AgentInfo
- type AgentZombieSweeper
- type BrowserOpener
- type ConnectedTracker
- type DaemonInfo
- type HookEventStore
- func (s *HookEventStore) Append(evt hookevents.Event)
- func (s *HookEventStore) EventsSince(since uint64) ([]hookevents.Event, uint64)
- func (s *HookEventStore) RecentEvents() []hookevents.Event
- func (s *HookEventStore) Snapshot() map[string]hookevents.SessionSnapshot
- func (s *HookEventStore) Subscribe() chan struct{}
- func (s *HookEventStore) Unsubscribe(ch chan struct{})
- type NetworkEvent
- type NetworkEventStore
- type PendingConfirm
- type PendingConfirmStore
- func (s *PendingConfirmStore) Add(pc *PendingConfirmation)
- func (s *PendingConfirmStore) Cleanup(maxAge time.Duration)
- func (s *PendingConfirmStore) Len() int
- func (s *PendingConfirmStore) Resolve(id string, approved bool, approverPID int) error
- func (s *PendingConfirmStore) ResolveTimeout(id string)
- func (s *PendingConfirmStore) Snapshot() []PendingConfirm
- type PendingConfirmation
- type ProjectEntry
- type ProjectInfo
- type ProjectRegistry
- type Request
- type Response
- type Server
- type SubscribeEvent
- type TrackerIssuesResult
Constants ¶
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" )
const ReadyForReviewHeader = "[human:ready-for-review]"
ReadyForReviewHeader is the single-line magic header that identifies a review handoff in a PM-ticket comment. See cli/CLAUDE.md "Review handoff".
const ReviewCompleteHeader = "[human:review-complete]"
ReviewCompleteHeader is the matching follow-up header posted after the reviewer agent finishes. Presence of a *newer* review-complete comment clears the ready-for-review flag, so the TUI stops showing (R) once a review has actually landed.
Variables ¶
This section is empty.
Functions ¶
func ConnectedPath ¶
func ConnectedPath() string
ConnectedPath returns the default path for the connected PIDs file.
func GenerateToken ¶
GenerateToken returns a cryptographically random 32-byte hex string.
func GetHookSnapshot ¶
func GetHookSnapshot(addr, token string) (map[string]hookevents.SessionSnapshot, error)
GetHookSnapshot fetches the current per-session hook state from the daemon.
func GetLogMode ¶
GetLogMode fetches the current traffic log mode from the daemon.
func GetToolStats ¶
GetToolStats fetches pre-aggregated tool call statistics from the daemon.
func GetTrackerDiagnose ¶
func GetTrackerDiagnose(addr, token string) ([]tracker.TrackerStatus, error)
GetTrackerDiagnose fetches tracker credential status from the daemon.
func InfoPath ¶
func InfoPath() string
InfoPath returns the default path for the daemon info file (~/.human/daemon.json).
func IsProcessAlive ¶
IsProcessAlive checks whether a process with the given PID is still running.
func IsReviewComplete ¶
IsReviewComplete reports whether the comment body is a review-complete follow-up, which supersedes any earlier handoff for the same engineering keys.
func LoadOrCreateToken ¶
LoadOrCreateToken reads the token from disk, or generates and persists a new one.
func LogPath ¶
func LogPath() string
LogPath returns the path to the daemon log file (~/.human/daemon.log).
func ParseEngineeringKeysFromHandoff ¶
ParseEngineeringKeysFromHandoff extracts the engineering ticket keys listed on the `engineering:` line of a [human:ready-for-review] comment body. Returns nil if the body is not a handoff block or has no engineering line.
The comment body must START with ReadyForReviewHeader so a comment that merely quotes the header (e.g. in a discussion) does not trigger a handoff.
func ParseHookEventArgs ¶
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, agent_name].
Every field is length-capped and Cwd must be absolute — both as defence against abusive clients that could otherwise poison the in-memory hook store or write relative paths that collide with registered project directories.
func PidPath ¶
func PidPath() string
PidPath returns the path to the daemon PID file (~/.human/daemon.pid).
func ReadAlivePid ¶
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 ¶
ReadConnected reads connected PIDs from path. Returns nil on any error.
func RemoveConnected ¶
func RemoveConnected(path string)
RemoveConnected removes the connected PIDs file (best-effort).
func RunAgentCleanup ¶
func RunAgentCleanup(ctx context.Context, store *HookEventStore, cleaner AgentCleaner, logger zerolog.Logger)
RunAgentCleanup watches for SessionEnd hook events from devcontainer agents and automatically stops the container and removes the worktree.
func RunAgentZombieSweep ¶
func RunAgentZombieSweep(ctx context.Context, sweeper AgentZombieSweeper, logger zerolog.Logger)
RunAgentZombieSweep periodically checks for agent containers that are still running but have no Claude process. This catches cases where Claude failed to start, crashed without firing hook events, or the user killed the tmux pane.
func RunRemote ¶
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 ¶
RunRemoteCapture connects to the daemon and runs args, returning stdout as bytes instead of printing to os.Stdout.
func SendConfirmDecision ¶
SendConfirmDecision sends a confirmation decision for a pending destructive operation.
func SetLogMode ¶
SetLogMode sets the traffic log mode on the daemon. Returns the new mode.
func Subscribe ¶
func Subscribe(addr, token string) (<-chan SubscribeEvent, func(), error)
Subscribe opens a persistent connection to the daemon's subscribe endpoint. It returns a channel that receives a signal each time the daemon's state changes, and a cleanup function that closes the connection. The channel is closed when the connection drops or cleanup is called.
func TokenPath ¶
func TokenPath() string
TokenPath returns the default path for the daemon token file.
func WriteConnected ¶
WriteConnected atomically writes the connected PIDs to path. On rename failure the temporary file is removed so a crashed daemon does not leave orphan .tmp files that survive across restarts when the process is killed with SIGKILL.
func WriteInfo ¶
func WriteInfo(info DaemonInfo) error
WriteInfo writes the daemon info as JSON to InfoPath with restricted permissions.
func WritePidFile ¶
WritePidFile writes the given PID to the PID file.
Types ¶
type AgentCleaner ¶
type AgentCleaner interface {
DeleteAgent(ctx context.Context, name string) error
// DecommissionAgent removes the agent from the list immediately and
// returns the container ID for background teardown. This makes
// "human agent list" responsive while the slow container stop happens
// asynchronously.
DecommissionAgent(name string) (containerID string, err error)
// StopContainer stops and removes a container by ID.
StopContainer(ctx context.Context, containerID string) error
}
AgentCleaner stops and removes an agent by name.
type AgentZombieSweeper ¶
type AgentZombieSweeper interface {
RunningAgents() ([]AgentInfo, error)
IsProcessRunning(ctx context.Context, containerID string, process string) (bool, error)
DeleteAgent(ctx context.Context, name string) error
}
AgentZombieSweeper checks for orphaned agent containers whose main process has exited but the container is still running.
type BrowserOpener ¶
BrowserOpener opens a URL in the browser. Extracted for testability.
type ConnectedTracker ¶
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 ¶
func NewConnectedTracker() *ConnectedTracker
NewConnectedTracker creates an empty tracker.
func (*ConnectedTracker) PIDs ¶
func (t *ConnectedTracker) PIDs() []int
PIDs returns a sorted snapshot of currently tracked PIDs.
func (*ConnectedTracker) Prune ¶
func (t *ConnectedTracker) Prune(ttl time.Duration)
Prune removes PIDs not seen within ttl.
func (*ConnectedTracker) Touch ¶
func (t *ConnectedTracker) Touch(pid int)
Touch records or refreshes a PID with the current time.
type DaemonInfo ¶
type DaemonInfo struct {
Addr string `json:"addr"`
ChromeAddr string `json:"chrome_addr,omitempty"`
ProxyAddr string `json:"proxy_addr,omitempty"`
Token string `json:"token,omitempty"`
PID int `json:"pid,omitempty"`
// Version carries the daemon binary's build version so clients can warn
// about skew between the running daemon and the CLI binary.
// omitempty preserves backward-compatibility with daemon.json files
// written by older builds that do not emit this field.
Version string `json:"version,omitempty"`
Projects []ProjectInfo `json:"projects,omitempty"`
}
DaemonInfo holds the runtime details of a running daemon instance.
func ReadInfo ¶
func ReadInfo() (DaemonInfo, error)
ReadInfo reads and unmarshals the daemon info from InfoPath.
func (DaemonInfo) IsAlive ¶
func (d DaemonInfo) IsAlive() bool
IsAlive checks whether the daemon process identified by PID is still running.
func (DaemonInfo) IsReachable ¶
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 ¶
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 ¶
func NewHookEventStore() *HookEventStore
NewHookEventStore creates an empty store.
func (*HookEventStore) Append ¶
func (s *HookEventStore) Append(evt hookevents.Event)
Append adds a hook event. Before appending, events for the same session beyond maxHookEventsPerSession are dropped so one chatty client cannot push other sessions out of the shared buffer. The aggregate cap then drops the oldest events across all sessions.
func (*HookEventStore) EventsSince ¶
func (s *HookEventStore) EventsSince(since uint64) ([]hookevents.Event, uint64)
EventsSince returns the events appended after the given sequence, plus the current high-water sequence to pass on the next call. Sequences are monotonic and independent of the ring's length, so a subscriber keeps receiving new events even after the ring saturates and stops growing — the failure mode of tracking deltas by slice length. Pass 0 for the first call.
func (*HookEventStore) RecentEvents ¶
func (s *HookEventStore) RecentEvents() []hookevents.Event
RecentEvents returns a copy of all stored events.
func (*HookEventStore) Snapshot ¶
func (s *HookEventStore) Snapshot() map[string]hookevents.SessionSnapshot
Snapshot returns the current per-session state derived from all stored events.
func (*HookEventStore) Subscribe ¶
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 ¶
func (s *HookEventStore) Unsubscribe(ch chan struct{})
Unsubscribe removes a previously registered channel from the subscriber list. The channel is not closed — subscribers must stop reading from it after calling Unsubscribe and let it be garbage collected. This avoids coordinating with any concurrent Append on a removed channel.
type NetworkEvent ¶
type NetworkEvent struct {
Source string `json:"source"` // "proxy" | "oauth" | "fail"
Status string `json:"status"` // "forward" | "intercept" | "block" | "no-sni" | "parse-fail" | "dial-fail" | "callback"
Host string `json:"host"` // may be empty for pre-SNI failures
Count int `json:"count"` // >=1
LastSeen time.Time `json:"last_seen"`
}
NetworkEvent is a single ambient network activity row as rendered by the TUI activity panel. Consecutive events with the same Host and Source are collapsed into one row with an incrementing Count and a refreshed LastSeen timestamp.
func GetNetworkEvents ¶
func GetNetworkEvents(addr, token string) ([]NetworkEvent, error)
GetNetworkEvents fetches the current ambient network activity buffer from the daemon. Returns a nil slice (not a nil error) when the daemon replies with an empty list so the TUI can collapse the panel.
type NetworkEventStore ¶
type NetworkEventStore struct {
// contains filtered or unexported fields
}
NetworkEventStore is a thread-safe ring buffer of recent network events with consecutive-host deduplication. It models HookEventStore but collapses bursts at write time so the panel stays calm under sustained repeats.
func NewNetworkEventStore ¶
func NewNetworkEventStore() *NetworkEventStore
NewNetworkEventStore creates an empty store using time.Now as its clock. Tests can override the clock via NewNetworkEventStoreWithClock.
func NewNetworkEventStoreWithClock ¶
func NewNetworkEventStoreWithClock(nowFn func() time.Time) *NetworkEventStore
NewNetworkEventStoreWithClock is the test constructor that injects a deterministic clock so dedup timestamps are reproducible.
func (*NetworkEventStore) Emit ¶
func (s *NetworkEventStore) Emit(source, status, host string)
Emit satisfies proxy.NetworkEventEmitter. Consecutive events with the same (source, host) pair are collapsed into the tail row: Count is incremented and LastSeen is refreshed. A different host or source starts a new row, even if the host was seen earlier in the buffer. Collapsing at write time keeps memory flat under sustained bursts so the panel stays calm under noise.
func (*NetworkEventStore) Snapshot ¶
func (s *NetworkEventStore) Snapshot() []NetworkEvent
Snapshot returns a copy of all current rows in insertion order (oldest first). Callers that want newest-first should reverse the slice; the store keeps events in insertion order so testing and JSON serialization remain predictable.
type PendingConfirm ¶
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 ¶
func GetPendingConfirms(addr, token string) ([]PendingConfirm, error)
GetPendingConfirms fetches pending destructive operation confirmations from the daemon.
type PendingConfirmStore ¶
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 ¶
func NewPendingConfirmStore() *PendingConfirmStore
NewPendingConfirmStore creates an empty store.
func (*PendingConfirmStore) Add ¶
func (s *PendingConfirmStore) Add(pc *PendingConfirmation)
Add stores a pending confirmation. The caller should block on pc.Decision after calling Add.
func (*PendingConfirmStore) Cleanup ¶
func (s *PendingConfirmStore) Cleanup(maxAge time.Duration)
Cleanup rejects and removes all pending confirmations older than maxAge.
func (*PendingConfirmStore) Len ¶
func (s *PendingConfirmStore) Len() int
Len returns the number of pending confirmations.
func (*PendingConfirmStore) Resolve ¶
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 and must be a positive integer.
The approverPID != requester PID check below is only a best-effort sanity guard, NOT an authorization boundary: ClientPID is supplied by the client and the requester's PID is typically resolved inside the agent's container namespace while the approver's is on the host, so the two are not comparable as a trust signal. Actual authorization is the daemon token required to reach this endpoint at all — do not rely on the PID check for security.
Resolve is for client-initiated decisions. Internal lifecycle events (timeouts, encode failures) must use ResolveTimeout instead.
func (*PendingConfirmStore) ResolveTimeout ¶
func (s *PendingConfirmStore) ResolveTimeout(id string)
ResolveTimeout removes a pending confirmation without a client approver. It is used by internal lifecycle events (request timeouts, response-write failures) that need to unblock the waiting goroutine. The decision is always "not approved".
Returns nil even when the id is unknown — the caller is typically running in a deferred cleanup path where the entry may have already been resolved by another lifecycle event, and that is not a failure.
func (*PendingConfirmStore) Snapshot ¶
func (s *PendingConfirmStore) Snapshot() []PendingConfirm
Snapshot returns all pending confirmations as wire types for the TUI.
type PendingConfirmation ¶
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 ¶
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 ¶
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:
- HUMAN_{PROJECT}_{KEY} — per-project override (e.g. HUMAN_INFRA_GITHUB_WORK_TOKEN)
- {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 ¶
ProjectInfo describes a registered project in a running daemon.
type ProjectRegistry ¶
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 ¶
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 ¶
func (r *ProjectRegistry) Entries() []ProjectEntry
Entries returns all registered project entries.
func (*ProjectRegistry) Resolve ¶
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 ¶
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
NetworkEvents *NetworkEventStore // in-memory ambient network activity buffer; nil disables
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
StatsWriter *stats.Writer // async SQLite writer for tool event persistence; nil disables
StatsStore *stats.StatsStore // for query-time aggregation; nil disables tool-stats route
AgentCleaner AgentCleaner // async agent cleanup; nil disables agent-stop-async route
VaultResolver *vault.Resolver // session-scoped vault resolver; reused across requests to avoid repeated op.exe calls
// contains filtered or unexported fields
}
Server listens for incoming client connections and executes CLI commands.
func (*Server) ListenAndServe ¶
ListenAndServe starts the TCP listener and blocks until ctx is cancelled. On shutdown it waits for all in-flight handler goroutines to return before closing, so a client request that's already accepted is never torn down mid-flight by listener close alone.
type SubscribeEvent ¶
type SubscribeEvent struct {
Type string `json:"type"` // "change", "agent-stopped"
AgentName string `json:"agent,omitempty"` // set for agent lifecycle events
}
SubscribeEvent is a notification sent over a persistent subscribe connection. For "agent-stopped" events, AgentName identifies the agent to remove immediately without waiting for the next discovery cycle.
type TrackerIssuesResult ¶
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"`
ReadyForReview []string `json:"ready_for_review,omitempty"`
Err string `json:"error,omitempty"`
}
TrackerIssuesResult is the wire type for a single tracker/project's issues.
ReadyForReview carries the engineering ticket keys that a PM tracker has currently flagged for review via a [human:ready-for-review] comment. It is populated on engineering-tracker results (where the keys actually live) so the TUI can join it against Issues without a separate lookup. See cli/CLAUDE.md "Review handoff" for the comment convention.
func GetTrackerIssues ¶
func GetTrackerIssues(addr, token string) ([]TrackerIssuesResult, error)
GetTrackerIssues fetches open issues from all configured tracker projects via the daemon.