installer

package
v0.22.162 Latest Latest
Warning

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

Go to latest
Published: May 25, 2026 License: MIT Imports: 5 Imported by: 0

Documentation

Overview

Package installer is the transport-agnostic core of the ten-step zero-touch bootstrap that `clawtool install` runs.

It exists so two surfaces can drive the SAME sequence without duplicating orchestration:

  • the CLI (`clawtool install`), which executes each step in-process via the App dispatch surface and renders progress as stderr status lines; and
  • the GUI installer (cmd/clawtool-installer, a separate Wails binary), which executes each step by shelling out to the clawtool binary and renders progress as a native splash.

The orchestration (which steps run, in what order, which are hard-required vs best-effort, the idempotency contract) lives here as the single source of truth. HOW a step executes (Exec) and HOW progress is surfaced (Emit) are injected, so this package imports neither internal/cli nor any GUI framework — both callers depend on it, not the reverse.

Scope note: steps 1–9 are the cross-surface core. The CLI's step 7.5 (tmux auto-spawn) and --attach handoff are terminal-only and stay in internal/cli; the GUI has no use for them.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Actions

type Actions struct {
	StartDaemon  DaemonStart
	VerifyDaemon DaemonVerify
	DetectHosts  HostDetect
	Run          Exec
	PeerRegister PeerRegisterFn
	InitAll      InitAllFn

	AfterPeerRegister func()
}

Actions bundles the injected executors so Run stays transport- and framework-agnostic.

Run, StartDaemon, VerifyDaemon and DetectHosts are required. The remaining fields are optional hooks the CLI uses to route two steps through its dedicated seams instead of shelling the verb through Exec — the GUI leaves them nil and those steps fall back to Exec:

  • PeerRegister (step 7): the CLI's seam carries display-name logic the bare `peer register` verb argv can't express.
  • InitAll (step 8): the CLI's seam returns the applied-recipe count that feeds the install summary; a bare `init --all` verb reports only an exit code.
  • AfterPeerRegister: a flow hook fired immediately after step 7 and before step 8, so the CLI can inject its terminal-only tmux auto-spawn (step 7.5) at the correct position without the core knowing tmux exists. The GUI has no use for it.

type DaemonStart

type DaemonStart func(ctx context.Context) (port int, err error)

DaemonStart ensures the daemon is up and returns its listen port. Bound to daemon.Ensure in production.

type DaemonVerify

type DaemonVerify func() (diag string, err error)

DaemonVerify probes daemon health. Returns "" when healthy, or a short diagnostic describing why the probe failed.

type Emit

type Emit func(Event)

Emit is the progress sink. It is called once per status line, in step order, on the calling goroutine — callers that marshal to a UI thread are responsible for their own hand-off.

type Event

type Event struct {
	Step       int    `json:"step"`
	Label      string `json:"label"`
	Level      Level  `json:"level"`
	Message    string `json:"message"`
	DurationMs int64  `json:"duration_ms"`
}

Event is a single progress update emitted as a step runs. The CLI renders it to a stderr status line; the GUI pushes it to the frontend over a Wails binding. DurationMs is the wall-clock cost of the step's action (0 for steps that emit without timing).

type Exec

type Exec func(args []string) (rc int, output string)

Exec runs a single `clawtool <args...>` verb and returns the verb's exit code plus a trimmed one-line tail of its output (for the status message on failure). The CLI binds this to in-process App dispatch with captured stderr; the GUI binds it to a subprocess self-exec of the clawtool binary. A non-nil error is reserved for failures that prevented the verb from running at all (couldn't spawn); a verb that ran and exited non-zero reports via rc.

type HostDetect

type HostDetect func() []string

HostDetect probes for installed agent CLIs and returns their family names (claude / codex / gemini / opencode).

type InitAllFn

type InitAllFn func(workdir string) (applied int, err error)

InitAllFn applies the Core recipes to workdir and returns the count of recipes applied (or a negative sentinel when the count is unknown). Optional override for step 8 (see Actions).

type Level

type Level int

Level discriminates a step's outcome on its progress event. The three states mirror the operator-facing precedent (the onboard wizard's summary rows use the same ✓ / ⚠ / ✗ glyphs).

const (
	// LevelOK — the step did its work (or was already satisfied).
	LevelOK Level = iota
	// LevelWarn — a best-effort step failed; the run continues.
	LevelWarn
	// LevelFail — a hard-required step failed; the run aborts.
	LevelFail
)

func (Level) Glyph

func (l Level) Glyph() string

Glyph returns the single-rune status marker for the level.

func (Level) String

func (l Level) String() string

String returns the machine-readable level token. The GUI marshals events to JSON for its frontend, so this is part of the wire shape.

type Options

type Options struct {
	// Workdir is the directory step 8 (init --all) targets. When it
	// is not inside a git repo, step 8 is skipped with a warning.
	Workdir string
	// SkipInit suppresses step 8 entirely.
	SkipInit bool
}

Options tune a run.

type PeerRegisterFn

type PeerRegisterFn func(backend string) error

PeerRegisterFn registers the current shell as a peer under the given backend label. Optional override for step 7 (see Actions).

type Summary

type Summary struct {
	Port             int
	AgentsClaimed    int
	RecipesApplied   int
	BridgesInstalled int
	PeersRegistered  int
	StepsOK          int
	StepsWarn        int
	StepsFailed      int
}

Summary is the running tally Run maintains across the steps so a caller can render a closing one-liner.

func Run

func Run(ctx context.Context, act Actions, opts Options, emit Emit) (Summary, error)

Run executes steps 1–9 of the bootstrap, emitting one Event per status line via emit, and returns the Summary. A non-nil error is returned only when a HARD-REQUIRED step fails: step 1 (daemon health) or step 9 (verify). Steps 2–8 are best-effort — their failures land as LevelWarn events and increment Summary.StepsWarn but never abort the run. The sequence is idempotent: each verb short-circuits when its target state already exists.

Jump to

Keyboard shortcuts

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