Documentation
¶
Overview ¶
Package cli wires cobra commands, config loading, env/flag overrides, and top-level error-to-exit-code mapping. Thin transport layer: business logic lives in internal/config, internal/prompt, internal/client, and internal/render.
Index ¶
- Variables
- func APIBody(err error) string
- func FormatError(w io.Writer, err error, verbose int)
- func Hint(err error) string
- func NewAPIErr(format string, args ...any) error
- func NewConfigErr(format string, args ...any) error
- func NewFileErr(format string, args ...any) error
- func NewLogger(verbose int) *slog.Logger
- func NewLoggerTo(w io.Writer, verbose int) *slog.Logger
- func NewNetworkErr(format string, args ...any) error
- func NewTimeoutErr(format string, args ...any) error
- func NewUsageErr(format string, args ...any) error
- func ReadPrompt(args []string, stdin io.Reader, stdinIsTTY bool) (string, error)
- func StdinIsTTY() bool
- func WrapCategorized(cat Category, code ExitCode, err error) error
- type AtomicWriter
- type BodyCarrier
- type CategorizedError
- type Category
- type ExitCode
- type Globals
- type Hinter
- type PresetFlags
- type ResolvedPreset
Constants ¶
This section is empty.
Variables ¶
var ( ErrUsage = errors.New("usage error") ErrConfig = errors.New("config error") ErrFile = errors.New("file error") ErrNetwork = errors.New("network error") ErrAPI = errors.New("api error") ErrTimeout = errors.New("timeout error") )
Sentinel base errors for each category — wrapped so callers can use errors.Is.
Functions ¶
func FormatError ¶
FormatError renders an error for stderr in the canonical `askit: <category>: <detail> (exit <N>)` form (FR-060/061). When verbose > 0, an additional indented "hint:" line is emitted with any hint supplied via Hint(err). When verbose >= 2 and the error is in the API category, the truncated body from APIBody(err) is also emitted.
func NewConfigErr ¶
NewConfigErr wraps a configuration-level failure (malformed YAML, failed validation, unknown preset, unresolved required field) as exit-3.
func NewFileErr ¶
NewFileErr wraps a file-reference failure (missing, oversize, unreadable under the active unknown-strategy) as exit-4.
func NewLogger ¶
NewLogger builds a stderr slog.Logger whose level maps from the stacked `-v` count: 0 → Error, 1 → Info, 2+ → Debug (FR-090).
func NewLoggerTo ¶
NewLoggerTo is the same as NewLogger but writes to an arbitrary io.Writer (primarily for tests).
func NewNetworkErr ¶
NewNetworkErr wraps an HTTP transport failure (connection refused, DNS, TLS, connection reset) as exit-5.
func NewTimeoutErr ¶
NewTimeoutErr wraps a deadline or cancel event as exit-7.
func NewUsageErr ¶
NewUsageErr wraps a usage violation (unknown flag, missing prompt, bad -o target, TTY required, …) as exit-2.
func ReadPrompt ¶
ReadPrompt resolves the user prompt from the three documented sources per FR-002:
- A positional argument (possibly the explicit `-` stdin marker).
- stdin, when stdin is not a terminal.
- Both: stdin prepended to the positional argument, separated by a blank line.
Using `-` AND a separate positional prompt AND piped stdin at the same time is ambiguous and returns a usage error.
isTTY is injected so tests can exercise every branch without touching a real terminal.
func StdinIsTTY ¶
func StdinIsTTY() bool
StdinIsTTY reports whether os.Stdin is connected to a terminal. The real CLI uses this as the isTTY argument to ReadPrompt.
Types ¶
type AtomicWriter ¶
type AtomicWriter struct {
// contains filtered or unexported fields
}
AtomicWriter writes to a temporary sibling file and, on Commit, atomically renames it over the target (FR-006). Writer failures trigger automatic cleanup via Rollback.
func OpenOutput ¶
func OpenOutput(path string, force bool) (*AtomicWriter, error)
OpenOutput creates an AtomicWriter for path. If the target already exists as a regular file and force is false, returns a usage-level error (exit 2). Parent directories are created automatically.
func (*AtomicWriter) Close ¶
func (a *AtomicWriter) Close() error
Close is an io.Closer helper that defers to Rollback. Callers should pair OpenOutput with `defer w.Close()` and an explicit Commit.
func (*AtomicWriter) Commit ¶
func (a *AtomicWriter) Commit() error
Commit closes the temp file and atomically renames it over the target. After a successful Commit, subsequent calls are no-ops.
func (*AtomicWriter) Rollback ¶
func (a *AtomicWriter) Rollback() error
Rollback removes the temp file. Safe to call after Commit (it's a no-op then) or before any Write (removes an empty file).
type BodyCarrier ¶
type BodyCarrier interface {
APIResponseBody() string
}
BodyCarrier is implemented by API errors that carry an upstream response body for inclusion under -vv.
type CategorizedError ¶
CategorizedError is an error with an attached ExitCode and Category so the top-level mapper can render the correct stderr line and choose the correct exit code.
func (*CategorizedError) Error ¶
func (c *CategorizedError) Error() string
Error renders the wrapped error's message; category / exit code are applied by the outermost renderer in errout.go.
func (*CategorizedError) Unwrap ¶
func (c *CategorizedError) Unwrap() error
Unwrap exposes the wrapped error for errors.Is / errors.As.
type Category ¶
type Category string
Category is the short tag ("config", "file", "endpoint", "api", …) that appears after "askit:" in stderr output (FR-060).
const ( CatUsage Category = "usage" CatConfig Category = "config" CatFile Category = "file" CatEndpoint Category = "endpoint" CatAPI Category = "api" CatTimeout Category = "timeout" CatGeneric Category = "" )
Canonical categories.
func CategoryOf ¶
CategoryOf walks an error chain and returns the first embedded Category. Errors without a category map to CatGeneric.
type ExitCode ¶
type ExitCode int
ExitCode is the process exit code taxonomy defined by contracts/cli-surface.md.
const ( ExitOK ExitCode = 0 ExitGeneric ExitCode = 1 ExitUsage ExitCode = 2 ExitConfig ExitCode = 3 ExitFile ExitCode = 4 ExitNetwork ExitCode = 5 ExitAPI ExitCode = 6 ExitTimeout ExitCode = 7 )
Stable exit codes — part of the tool's public contract.
type Globals ¶
type Globals struct {
ConfigPath string // from -c or ASKIT_CONFIG
Endpoint string // from -e or ASKIT_ENDPOINT
Model string // from -m or ASKIT_MODEL
APIKey string // from --api-key or ASKIT_API_KEY
NoColor bool // from --no-color or NO_COLOR
Verbose int // from -v (stackable)
// contains filtered or unexported fields
}
Globals holds the values of the global (root-level) flags plus the env vars that parallel them. Populated by [harvestGlobals] at PersistentPreRun time so that downstream subcommands all see the same resolved view.
func (*Globals) EnvOverrides ¶
EnvOverrides returns the Overrides view of env-var values that should be layered after the explicit config file but before flag overrides.
func (*Globals) FlagOverrides ¶
FlagOverrides returns the Overrides view of flag-supplied values that should be layered last.
type Hinter ¶
type Hinter interface {
Hint() string
}
Hinter is implemented by errors that carry a verbose-only hint line.
type PresetFlags ¶
type PresetFlags struct {
System *string
Temperature *float64
TopP *float64
MaxTokens *int
Seed *int
Stream *bool
Output *config.OutputFormat
Model *string
}
PresetFlags is the subset of explicit CLI flags relevant to preset resolution. Pointer fields distinguish "flag was set" from "default zero value"; nil fields fall through to the preset or config.
type ResolvedPreset ¶
type ResolvedPreset struct {
Name string
System string
Temperature float64
TopP float64
MaxTokens int
Seed *int
Stream bool
Output config.OutputFormat
Model string
}
ResolvedPreset is the effective set of overrides after merging a named preset on top of config.Defaults and below explicit flags. All fields are concrete (no pointers) so the downstream request builder doesn't need to re-check layered nils.
func ResolvePreset ¶
func ResolvePreset(cfg *config.Config, name string, flags PresetFlags) (ResolvedPreset, error)
ResolvePreset composes the effective ResolvedPreset for a request by layering: config.Defaults → preset[name] → flags. Passing an empty name skips the preset layer entirely.
When name is non-empty but not found in cfg.Presets, returns a typed ConfigError enumerating the available preset names (FR-033).