cli

package
v0.7.1 Latest Latest
Warning

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

Go to latest
Published: May 19, 2026 License: MIT Imports: 37 Imported by: 0

Documentation

Overview

Package cli wires subcommands to the underlying packages. It owns no business logic of its own - only argument parsing, dispatching, and printing. This keeps the rest of the codebase testable in isolation.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type App

type App struct {
	Version string
	In      io.Reader
	Out     io.Writer
	Err     io.Writer
	Paths   config.Paths

	// EditDraftFunc lets the apply command hand a draft off to a user's
	// editor. When nil, defaultEditDraft is used (shells out via os/exec).
	// Tests inject a deterministic fake so they never spawn a real editor.
	EditDraftFunc func(current string) (string, error)

	// NLClientFunc lets tests inject a fake LLM client for the natural-
	// language REPL dispatcher. When nil, the dispatcher reads config.json
	// via llm.New and falls back to Noop on misconfig.
	NLClientFunc func() llm.Client

	// CalendarClientFunc lets tests inject a fake calendar.Client so the
	// add-interview / add-deadline flows can be exercised without
	// hitting Google. When nil, the production path runs the real OAuth
	// + Calendar API.
	CalendarClientFunc func(ctx context.Context, a *App) (calendar.Client, error)

	// InboxClientFunc lets tests inject a fake inbox.Client (no real
	// IMAP, no real network) so the poll flow can be exercised
	// end-to-end. When nil, the production path constructs a real
	// IMAP client.
	InboxClientFunc func(ctx context.Context, a *App) (inbox.Client, error)
}

App holds the CLI's I/O and resolved data paths. Construction does not touch disk - that happens inside individual subcommands so `help` and `version` always work even on a broken install.

func New

func New(version string, in io.Reader, out, err io.Writer) *App

New builds an App with Paths from ResolveRoot (JOBFORGE_HOME, user config dir, or ~/.jobforge). The working directory does not matter.

func (*App) Run

func (a *App) Run(ctx context.Context, args []string) error

Run dispatches the chosen subcommand. Returning an error here causes main to exit non-zero and print the message. With no args, we drop into the REPL on a real TTY; pipes/CI/tests get plain help instead so they don't hang waiting for stdin.

func (*App) RunREPL

func (a *App) RunREPL(ctx context.Context) error

RunREPL drops into an interactive prompt that dispatches each line through App.Run. Exits on EOF, `exit`/`quit`/`:q`, or context cancellation (Ctrl+C in the parent process). Errors from individual commands are printed and the loop continues — only EOF/quit ends the session.

Two backends:

  • On a real TTY we use the Bubble Tea palette prompt (live `/` filter, arrow-key selection). See readLineWithPalette.
  • On pipes / tests / CI we fall back to a plain line-buffered scanner so the loop is testable with strings.NewReader.

Jump to

Keyboard shortcuts

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