0Z4C0
// navigation
// @ozaco/cli

Spinner

Live spinners, progress bars and nested task trees implementing the `Spinner` protocol.

import from@ozaco/cli/spinner

@ozaco/cli/spinner is the default implementation of the Spinner protocol. It draws animated progress that repaints in place on an interactive terminal and degrades to a single committed line when output is piped or redirected — the same calling code works in both.

The module exposes one plugin, DefaultSpinner, which provides three actions. start runs a single spinner you drive to a terminal state (succeed/fail/warn/info/stop). bar runs a progress bar with update/advance. group opens a live tree whose task and bar children can themselves nest, so multi-step work renders as an indented, animated outline.

Frames default to the active palette’s spinner glyphs and the color to its primary style, both overridable per call; the default frame interval is 80 ms. Every handle is scope-bound: the animation task is spawned into the current scope and halted, the cursor restored, on teardown — so an interrupt never leaves a spinner spinning. Requires Terminal and Palette to be installed.

// on this page
01

Implementation

const

DefaultSpinner

The spinner implementation providing the `start`, `bar` and `group` actions.

signature
const DefaultSpinner: SpinnerDef

Install it alongside Terminal and Palette, then call Spinner.actions.start/bar/group. The handles it returns are documented below.

example
import { install } from '@ozaco/std/plugin'
import { Spinner } from '@ozaco/cli/core'
import { DefaultSpinner } from '@ozaco/cli/spinner'

yield* install(DefaultSpinner)
const spin = yield* Spinner.actions.start('Building…')
yield* spin.succeed('Built')
02

Actions

Available on the `Spinner` protocol once `DefaultSpinner` is installed.

fn

start

Start a single spinner; returns a `Handle` you resolve to a final state.

signature
start(options?: string | SpinnerDef.StartOptions): Future<SpinnerDef.Handle>

A bare string is shorthand for { message }. The handle’s update(message) changes the label live; succeed/fail/warn/info stop and commit a line led by the matching palette symbol; stop(message?) commits message or, with no argument, clears the line.

example
const spin = yield* Spinner.actions.start({ message: 'Fetching', interval: 100 })
yield* spin.update('Parsing')
yield* spin.fail('Network error')
fn

bar

Start a progress bar; returns a `BarHandle` driven by `update`/`advance`.

signature
bar(options?: string | SpinnerDef.BarOptions): Future<SpinnerDef.BarHandle>

update(value) sets absolute progress (clamped to total); advance(delta?) adds delta (default 1). succeed fills the bar and commits; fail and stop commit at the current value. Options include total, width, frames and interval.

example
const progress = yield* Spinner.actions.bar({ message: 'Download', total: 100 })
for (const chunk of chunks) {
  yield* progress.advance(chunk.size)
}
yield* progress.succeed('Done')
fn

group

Open a live task tree; spawn nested `task`/`bar` children under it.

signature
group(options?: SpinnerDef.GroupOptions): Future<SpinnerDef.GroupHandle>

The GroupHandle exposes task(message) and bar(message, options?) returning child handles, and stop() to finish the whole tree. A TaskHandle can nest further task/bar children, rendering an indented, animated outline of a multi-step job.

example
const group = yield* Spinner.actions.group()
const install = yield* group.task('Install deps')
const build = yield* install.task('Compile')
yield* build.succeed()
yield* install.succeed()
yield* group.stop()