Skip to content

daemon

import "github.com/linuskendall/cosmonaut/internal/daemon"

Package daemon implements the cosmonaut menu bar applet which hosts a system tray icon, global hotkey listener, and codespace lifecycle management.

Doctor-driven warning banners shown at the top of the main window.

Create-new flows: GitHub codespace form (repo/branch/label) and the Coder workspace forms (target-based and template-based).

Detail panel for a Coder workspace: hero header, actions, info form, and the configured-port-forwards section.

Detail panel for a GitHub codespace: hero header, actions, info form, and the forwarded-ports section.

Port-forward dialogs (ad-hoc + configured) and the config mutations backing the Coder port-forward list.

The main window's left pane: logo row, search, workspace tree, and account footer.

Cosmonaut unified window: native Fyne implementation of the redesign.

Layout:

┌────────────┬──────────────────────────────────────┐
│  Sidebar   │  Detail panel                        │
│  (logo,    │  (codespace detail / create / repo)  │
│   search,  │                                      │
│   tree,    │                                      │
│   account) │                                      │
└────────────┴──────────────────────────────────────┘

The bulk of structure mirrors the existing gui_window.go; this file rewrites the visual wrapping (title bar, search chrome, captions, action buttons) to match the design system.

Package daemon: Cosmonaut Fyne theme.

Thin wrapper around the default Fyne theme. Overrides only the Cosmonaut lime brand accent (primary / focus / selection) and a few type-scale tweaks. Backgrounds, foregrounds, and dark/light variant switching delegate to theme.DefaultTheme(), so the app follows the OS appearance just like every other Fyne app.

Cosmonaut native UI primitives.

Small building blocks reused across the unified window, codespace detail, create flow, and settings: keeps widget wiring consistent.

Index

func DefaultHotkey

func DefaultHotkey() string

DefaultHotkey returns the platform default hotkey string.

type Daemon

Daemon is the long-running background process that hosts the system tray, hotkey listener, and codespace poller.

type Daemon struct {
    Cfg        *config.Config
    ConfigPath string
    Runner     codespace.GHRunner
    // contains filtered or unexported fields
}

func New

func New(cfg *config.Config, configPath string) *Daemon

New creates a new Daemon with the given config.

func (*Daemon) AddWorkspaceListener

func (d *Daemon) AddWorkspaceListener(fn func()) (remove func())

AddWorkspaceListener registers fn to be invoked on the Fyne main thread after each poll where the workspace set has actually changed. Returns a remove function that the caller MUST invoke when the owning window closes — otherwise fn will keep firing into freed widgets.

Listeners are an alternative to polling d.Workspaces() on every render: the GUI sidebar uses one to refresh its tree the moment new data lands, instead of waiting for the user to click somewhere.

func (*Daemon) Codespaces

func (d *Daemon) Codespaces() []codespace.Codespace

Codespaces returns the last-polled codespace list.

func (*Daemon) DismissCheck

func (d *Daemon) DismissCheck(id string)

DismissCheck marks a doctor check ID as dismissed for the current session. Banners hide it; the Settings page health section still shows it so the user can come back to it.

func (*Daemon) IsDismissed

func (d *Daemon) IsDismissed(id string) bool

IsDismissed reports whether the given check ID has been dismissed.

func (*Daemon) ListErr

func (d *Daemon) ListErr() error

ListErr returns the error from the most recent codespace list attempt, or nil on success.

func (*Daemon) Run

func (d *Daemon) Run() error

Run starts all applet components. It blocks until Stop is called. This must be called from the main OS thread.

func (*Daemon) SetCodespaces

func (d *Daemon) SetCodespaces(cs []codespace.Codespace)

SetCodespaces updates the cached codespace list.

func (*Daemon) SetListErr

func (d *Daemon) SetListErr(err error)

SetListErr stores the error from the most recent codespace list attempt.

func (*Daemon) SetWorkspaces

func (d *Daemon) SetWorkspaces(ws []provider.Workspace)

SetWorkspaces updates the cached combined workspace list.

func (*Daemon) StatusFor

func (d *Daemon) StatusFor(name string) ProviderStatus

StatusFor returns a copy of the cached ProviderStatus for the given provider, or a zero value if none was recorded yet. Named StatusFor rather than ProviderStatus to avoid shadowing the type name.

func (*Daemon) Stop

func (d *Daemon) Stop()

Stop signals the applet to shut down. Safe to call from any goroutine and more than once (tray Quit racing a SIGTERM must not double-close stopCh or run cleanup twice).

func (*Daemon) UndismissCheck

func (d *Daemon) UndismissCheck(id string)

UndismissCheck clears a previous dismissal so the banner can show again.

func (*Daemon) Workspaces

func (d *Daemon) Workspaces() []provider.Workspace

Workspaces returns the last-polled combined workspace list.

type Inhibitor

Inhibitor prevents the system from sleeping (and optionally shutting down) while at least one codespace session is active. Implementations are platform-specific; see inhibit_darwin.go and inhibit_linux.go.

type Inhibitor interface {
    // Engage asks the OS to hold a sleep inhibit assertion. Mode is one of
    // "sleep" or "sleep+shutdown". Safe to call when already engaged (no-op).
    Engage(mode string) error
    // Release drops any held assertion. Safe to call when not engaged.
    Release() error
}

type PortForwardManager

PortForwardManager supervises long-running workspace port-forward processes started by the daemon.

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

func NewPortForwardManager

func NewPortForwardManager() *PortForwardManager

NewPortForwardManager constructs an empty PortForwardManager. Exported so the TUI applet (in internal/tui) can reuse the same supervisor logic that the Fyne applet uses, rather than reimplementing it.

func (*PortForwardManager) IsActive

func (m *PortForwardManager) IsActive(providerName, workspaceName string, remotePort, localPort int) bool

func (*PortForwardManager) IsActiveProtocol

func (m *PortForwardManager) IsActiveProtocol(providerName, workspaceName, protocol string, remotePort, localPort int) bool

func (*PortForwardManager) Start

func (m *PortForwardManager) Start(providerName, workspaceName string, remotePort, localPort int) error

func (*PortForwardManager) StartProtocol

func (m *PortForwardManager) StartProtocol(providerName, workspaceName, protocol string, remotePort, localPort int) error

func (*PortForwardManager) Stop

func (m *PortForwardManager) Stop(providerName, workspaceName string, remotePort, localPort int) bool

func (*PortForwardManager) StopAll

func (m *PortForwardManager) StopAll()

func (*PortForwardManager) StopProtocol

func (m *PortForwardManager) StopProtocol(providerName, workspaceName, protocol string, remotePort, localPort int) bool

type ProviderStatus

ProviderStatus records the local-setup health of a workspace provider: whether its CLI is on PATH and whether the last list/auth call succeeded. Cached so the tray menu can show why a provider is empty (CLI missing, not authenticated) rather than silently hiding the section.

type ProviderStatus struct {
    Available bool      // CLI is on PATH
    Err       error     // last list/auth error, nil on success
    CheckedAt time.Time // when this snapshot was taken
}

type SessionTracker

SessionTracker ref-counts live codespace SSH sessions across the whole daemon. When the count transitions from 0→1 it engages the inhibitor; when it drops back to 0 it releases.

Each call to TrackSession launches a background scan for ssh processes matching the given alias and watches their exit via kernel events (pidfd on Linux, kqueue on macOS). Reconnections after the initial scan window are not tracked: the next Cosmonaut launch re-scans.

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

func (*SessionTracker) SetMode

func (s *SessionTracker) SetMode(mode string)

SetMode hot-swaps the inhibit mode. If sessions are currently tracked, the inhibitor is re-engaged with the new mode.

func (*SessionTracker) Stop

func (s *SessionTracker) Stop()

Stop releases any held inhibitor; watcher goroutines keep running but their decrement calls become no-ops.

func (*SessionTracker) TrackSession

func (s *SessionTracker) TrackSession(alias string)

TrackSession scans for SSH processes whose command line contains the given alias, registers each and watches them for exit. Safe to call when mode is "off": it still runs but the inhibitor is a no-op.

The scan retries for a short window because the launch chain (osascript → Terminal.app, or terminal emulator fork) means the ssh pid may not exist the instant LaunchRemote returns.

Generated by gomarkdoc