onboard#

import "github.com/jbcom/radioactive-ralph/internal/onboard"

Package onboard implements the guided first-run wizard: when a user runs the client cold on an interactive terminal and no supervisor is reachable, it OFFERS (with explicit consent) to install and start the background service, falling back to a foreground supervisor or the plain print-the-commands path. See docs/superpowers/specs/2026-07-17-guided-first-run-onboarding-design.md.

The wizard is pure orchestration: every side effect (prompting, installing the service, discovering the supervisor) is an injected dependency, so the whole decision tree is unit-testable without touching the real system.

Index#

Variables#

ErrQuit is returned by a Prompter when the user asks to quit the wizard.

var ErrQuit = errors.New("onboard: user quit")

type Deps#

Deps are the injected dependencies. Every field is required.

type Deps struct {
    // Out receives the wizard's human-facing output.
    Out io.Writer
    // Prompt drives the yes/no questions.
    Prompt Prompter
    // Plan describes what installing the service will create.
    Plan Plan
    // InstallService installs AND (best-effort) starts the background service.
    InstallService func() error
    // WaitReachable blocks until a supervisor answers or the timeout elapses,
    // returning true when one became reachable.
    WaitReachable func(timeout time.Duration) bool
    // ForegroundHint is the exact command a user runs to start a foreground
    // supervisor (printed on the fallback path).
    ForegroundCmd string
    // ManualCommands is the multi-line fallback text (the pre-wizard message).
    ManualCommands string
}

type Outcome#

Outcome reports how the wizard ended so the caller knows whether to proceed to the TUI.

type Outcome int

const (
    // SupervisorReady means a supervisor is now reachable — proceed to the TUI.
    SupervisorReady Outcome = iota
    // PrintedForegroundHint means the wizard printed the `--supervisor`
    // command for the user to run themselves; the caller should exit cleanly.
    PrintedForegroundHint
    // PrintedCommands means the wizard fell back to printing the manual
    // commands; the caller returns its usual no-supervisor error.
    PrintedCommands
)

func Run#

func Run(d Deps) (Outcome, error)

Run drives the first-run flow. It assumes the caller already confirmed the session is interactive and no supervisor is currently reachable.

type Plan#

Plan is the “what will be created” summary shown before any outward-facing action, so the user consents to concrete paths, not a vague promise.

type Plan struct {
    StateDir        string
    DBPath          string
    ServiceUnit     string
    ServiceUnitPath string
}

type Prompter#

Prompter asks the user a yes/no question. Confirm returns (true, nil) for yes, (false, nil) for no, and a non-nil error to abort the whole wizard (e.g. the user typed ‘q’ to quit, or stdin closed).

type Prompter interface {
    Confirm(question string, defaultYes bool) (bool, error)
}

type StdinPrompter#

StdinPrompter is the real Prompter: it writes the question to Out and reads one line from In, interpreting y/yes → true, n/no → false, q/quit → ErrQuit, and an empty line → the supplied default. Any other input re-asks (bounded, so a closed stdin doesn’t loop forever).

type StdinPrompter struct {
    In  io.Reader
    Out io.Writer
    // contains filtered or unexported fields
}

func NewStdinPrompter#

func NewStdinPrompter(in io.Reader, out io.Writer) *StdinPrompter

NewStdinPrompter builds a StdinPrompter over in/out.

func (*StdinPrompter) Confirm#

func (p *StdinPrompter) Confirm(question string, defaultYes bool) (bool, error)

Confirm implements Prompter.

Generated by gomarkdoc