output

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Aug 14, 2026 License: MIT Imports: 18 Imported by: 0

Documentation

Overview

Package output formats lore's human and JSON output. All command handlers route through this package so styling, glyph fallbacks, and mode selection live in one place.

Three degradation rules govern human output:

  1. Color: emitted only when Out is a real terminal AND neither NO_COLOR nor --no-color is in effect. Redirecting stdout to a file therefore produces a clean ASCII transcript with no escape residue.
  2. Unicode glyphs: ✓ ⚠ ✗ → ← degrade to [ok] [!] [x] -> <- when Out is not a terminal. Decoupled from color so a user on a UTF-8 terminal with NO_COLOR set still gets nice glyphs; a user piping to `less` or a CI log still avoids mojibake.
  3. JSON mode (--json): human-mode printers (Success, Warn, Hint, PrintAddResult, PrintInitResult, PrintError) suppress all human output. Data-returning commands emit a documented JSON envelope instead.

Concurrency: mode, colorOverride, unicodeOverride, Out, and Err are package-level mutable globals. This is intentional for a single-process CLI where the cobra pre-run sets them once before any subcommand RunE fires. If a future command ever fans out goroutines that print (e.g. a parallel `lore status` across many projects), these need a mutex or a per-call context-carried renderer; today they don't.

Index

Constants

This section is empty.

Variables

Err is the writer for error output. Tests swap it; defaults to stderr.

Out is the writer for normal output. Tests swap it for a buffer; defaults to stdout. Reassigning it changes the TTY check that governs color and glyph degradation, since the check inspects whatever Out currently points at.

Functions

func Blank

func Blank()

Blank prints an empty line. Suppressed in JSON mode so the envelope stays single-line-parseable.

func ColorEnabled

func ColorEnabled() bool

ColorEnabled reports whether ANSI styling is currently emitted. False when --no-color is set, when NO_COLOR is in the environment (per the no-color.org de-facto standard), or when Out is not a terminal.

func Hint

func Hint(format string, args ...any)

Hint prints a dimmed informational line. Suppressed in JSON mode.

func PrintAddResult

func PrintAddResult(r AddResult)

PrintAddResult renders the per-dir add summary in three variants:

  • Every dir already tracked: terse "Project X is already tracked" line; idempotency is meant to be quiet.
  • At least one dir freshly added: header (project + path), per-dir blocks for each added/already-tracked dir, then the commit line and the "Next:" hint pointing at `git push` on central.
  • At least one dir skipped: per-dir safety messages rendered below the added blocks (or alone, when no dir landed). The cmd layer emits a non-zero exit via the error path; this function focuses on showing the user what was added vs refused.

Suppressed in JSON mode: slice 21 will wire a typed envelope; for now the human block is just skipped so script callers don't get noise.

func PrintDeferredFailure

func PrintDeferredFailure(data []byte) error

PrintDeferredFailure writes a deferred background failure to stderr.

func PrintDiff

func PrintDiff(result SyncResult)

PrintDiff renders project-copy changes against committed central HEAD.

func PrintDoctor

func PrintDoctor(result DoctorResult)

func PrintError

func PrintError(err error)

PrintError renders a lore error to Err with its hint, if any. Suppressed in JSON mode: the JSON envelope is the only thing the caller should be parsing on a failure (slice 21 polishes the failure envelope shape; slice 03 just ensures human noise doesn't leak).

func PrintInitResult

func PrintInitResult(r InitResult)

PrintInitResult prints the success summary plus the "no remote configured" hint when applicable. Paths are contracted back to `~/` for readability. Suppressed in JSON mode (slice 21 will wire a typed envelope).

func PrintList

func PrintList(result ListResult)

func PrintMoveResult

func PrintMoveResult(result MoveResult, ok bool)

func PrintPath

func PrintPath(p string)

PrintPath emits the path of a tracked agent dir (or the central repo).

Human mode: bare path line, no styling. `lore path` is a scripting helper meant to be consumed by `cd "$(lore path foo)"` and similar; ANSI codes would corrupt that.

JSON mode: a documented single-line envelope so agents can parse the result without string-matching. Slice 21 will extend this pattern to every data-returning command; slice 03 wires it for `lore path` as the only data command that exists today.

Schema (stable, additive-only): {"path": "<absolute path>"}.

func PrintPull

func PrintPull(result PullResult)

PrintPull renders pull outcomes in human or JSON form.

func PrintPullGitignoreWarnings

func PrintPullGitignoreWarnings(result PullResult)

PrintPullGitignoreWarnings prints warnings after the interactive picker.

func PrintPush

func PrintPush(result PushResult, auto bool)

PrintPush renders a push result. Auto suppresses only genuine no-ops.

func PrintRmConfirmation

func PrintRmConfirmation(view RmConfirmationView)

func PrintRmResult

func PrintRmResult(result RmResult, ok bool)

func PrintStatus

func PrintStatus(result SyncResult)

PrintStatus renders the complete sync-state report.

func PrintVersion

func PrintVersion(version string)

PrintVersion emits the resolved Lore build version.

Human mode: `lore version <version>`.

JSON mode: `{"version":"<version>"}`.

func SetColorForTest

func SetColorForTest(t *testing.T, enabled bool)

SetColorForTest forces color on/off for the duration of t. Used by golden tests that must produce deterministic output regardless of the developer's TTY.

func SetMode

func SetMode(m Mode)

SetMode sets the active output mode. Called by the root cobra pre-run hook after parsing --json. Tests should use SetModeForTest instead so the mode resets on cleanup.

func SetModeForTest

func SetModeForTest(t *testing.T, m Mode)

SetModeForTest forces mode for the duration of t. Restores the prior value on t.Cleanup so tests don't leak global state into each other.

func SetNoColor

func SetNoColor(disabled bool)

SetNoColor disables (or re-enables) color emission regardless of TTY detection. Called by the root pre-run hook after parsing --no-color. disabled=false clears the override so live env / TTY detection takes over again.

func SetUnicodeForTest

func SetUnicodeForTest(t *testing.T, enabled bool)

SetUnicodeForTest forces glyph mode for the duration of t. Same rationale as SetColorForTest.

func Success

func Success(format string, args ...any)

Success prints a ✓-prefixed line. No-op in JSON mode so a script- oriented `--json` run sees only the documented envelope on stdout.

func UnicodeEnabled

func UnicodeEnabled() bool

UnicodeEnabled reports whether unicode glyphs are emitted (versus the ASCII fallback set). Governed only by the TTY check on Out: a user piping to a logfile or a CI buffer gets ASCII even with NO_COLOR unset, because the logfile encoding is the actual concern.

func Warn

func Warn(format string, args ...any)

Warn prints a ⚠-prefixed line to Out. Warnings are part of normal output, not errors. Suppressed in JSON mode.

Types

type AddDirResult

type AddDirResult struct {
	Name        string
	Status      AddDirStatus
	CentralPath string
	// SafetyViolations carries one entry per safety-gate failure. Populated
	// only for StatusSkippedSafety. The slice (not a pre-joined string)
	// lets the JSON path emit structured violation kinds while the human
	// path still iterates Message lines.
	SafetyViolations []AddSafetyViolation
}

AddDirResult is the per-dir outcome inside an AddResult. Mirrors the shape of project.AgentDirResult.

type AddDirStatus

type AddDirStatus string

AddDirStatus mirrors project.DirStatus so this package doesn't have to import project (the dependency only ever points the other way: cmd/lore/add.go converts the orchestrator's result into this shape).

const (
	StatusAdded          AddDirStatus = "added"
	StatusAlreadyTracked AddDirStatus = "already-tracked"
	StatusSkippedSafety  AddDirStatus = "skipped-safety"
	StatusScaffolded     AddDirStatus = "scaffolded"
	StatusAdopted        AddDirStatus = "adopted"
)

type AddResult

type AddResult struct {
	ProjectName   string
	ProjectPath   string
	CentralRepo   string
	CommitMessage string
	CommitSHA     string
	SyncBase      string
	Dirs          []AddDirResult
	// ScaffoldRequested mirrors the orchestrator's flag: true when the
	// user passed --create, even when no scaffolding actually happened.
	ScaffoldRequested bool
}

AddResult is the data lore add hands to the output layer.

type AddSafetyViolation

type AddSafetyViolation struct {
	Kind    string
	Message string
}

AddSafetyViolation mirrors detect.Violation in shape (Kind + Message) so this package can carry the violation kind through to slice 21's typed JSON envelope without importing detect. The human renderer only uses Message today; Kind is preserved for the structured output path.

type DoctorResult

type DoctorResult struct {
	Healthy bool       `json:"healthy"`
	Fixed   []string   `json:"fixed"`
	Status  SyncResult `json:"status"`
}

type InitResult

type InitResult struct {
	CentralPath string // absolute path to the central repo
	ConfigPath  string // absolute path to the config file
	HasRemote   bool   // whether the central repo has a git remote configured
	Recreated   bool   // true if we re-created a missing dir (vs. fresh init)
}

InitResult is the data lore init hands to the output layer.

type ListResult

type ListResult struct {
	CentralRepo string    `json:"central_repo"`
	CentralHead string    `json:"central_head"`
	Rows        []ListRow `json:"rows"`
}

type ListRow

type ListRow struct {
	Project   string      `json:"project"`
	Checkout  string      `json:"checkout"`
	AgentDirs []string    `json:"agent_dirs"`
	SyncState string      `json:"sync_state"`
	Issues    []SyncIssue `json:"issues"`
}

type Mode

type Mode int

Mode names the output shape - human-readable lines, or a stable JSON envelope suitable for scripts and agents.

const (
	ModeHuman Mode = iota
	ModeJSON
)

func GetMode

func GetMode() Mode

GetMode returns the active mode. Commands consult this to choose between PrintXxx and emitJSON envelopes.

type MoveCheckoutResult

type MoveCheckoutResult struct {
	OldPath  string `json:"old_path"`
	Path     string `json:"path"`
	SyncBase string `json:"sync_base"`
}

type MoveResult

type MoveResult struct {
	OldName       string               `json:"old_name"`
	ProjectName   string               `json:"project"`
	CentralRepo   string               `json:"central_repo"`
	CommitMessage string               `json:"commit_message"`
	Commit        string               `json:"commit"`
	CentralOnly   bool                 `json:"central_only"`
	Checkouts     []MoveCheckoutResult `json:"checkouts"`
}

type PathEnvelope

type PathEnvelope struct {
	Path string `json:"path"`
}

PathEnvelope is the JSON shape `lore path --json` emits. Exported so downstream parsers (tests, agent harnesses) can decode into a typed struct rather than re-spelling the schema. Additive-only: new fields may be added but existing fields keep their name and type.

type PullCheckoutResult

type PullCheckoutResult struct {
	Path     string             `json:"path"`
	Status   PullCheckoutStatus `json:"status"`
	SyncBase string             `json:"sync_base"`
	Dirs     []PullDirResult    `json:"dirs"`
	Error    string             `json:"error"`
}

PullCheckoutResult is one public checkout outcome.

type PullCheckoutStatus

type PullCheckoutStatus string

PullCheckoutStatus mirrors project.PullCheckoutStatus. Values are identical to the project package's; the cmd layer converts.

const (
	// PullCheckoutMaterialized means the copy was created from central.
	PullCheckoutMaterialized PullCheckoutStatus = "materialized"
	// PullCheckoutUpdated means the copy received newer central content.
	PullCheckoutUpdated PullCheckoutStatus = "updated"
	// PullCheckoutAdopted means a matching copy was recorded at central HEAD.
	PullCheckoutAdopted PullCheckoutStatus = "adopted"
	// PullCheckoutUnchanged means the copy already matched at a live base.
	PullCheckoutUnchanged PullCheckoutStatus = "unchanged"
	// PullCheckoutProjectAhead means the copy holds changes central lacks.
	PullCheckoutProjectAhead PullCheckoutStatus = "project-ahead"
	// PullCheckoutRefused means a safety gate blocked the checkout.
	PullCheckoutRefused PullCheckoutStatus = "refused"
	// PullCheckoutFailed means the checkout was attempted and errored.
	PullCheckoutFailed PullCheckoutStatus = "failed"
	// PullCheckoutMerged means every divergence merged cleanly.
	PullCheckoutMerged PullCheckoutStatus = "merged"
	// PullCheckoutConflicted means unresolved artifacts were published.
	PullCheckoutConflicted PullCheckoutStatus = "conflicted"
	// PullCheckoutCentralForced means central was explicitly selected.
	PullCheckoutCentralForced PullCheckoutStatus = "central-forced"
	// PullCheckoutProjectForced means project was explicitly selected.
	PullCheckoutProjectForced PullCheckoutStatus = "project-forced"
)

type PullConflictResult

type PullConflictResult struct {
	Path        string `json:"path"`
	Kind        string `json:"kind"`
	SiblingPath string `json:"sibling_path"`
}

PullConflictResult is one public unresolved merge artifact.

type PullDirResult

type PullDirResult struct {
	Name      string               `json:"name"`
	Path      string               `json:"path"`
	Status    PullDirStatus        `json:"status"`
	Unignored bool                 `json:"unignored"`
	Conflicts []PullConflictResult `json:"conflicts"`
}

PullDirResult is one public agent-directory outcome.

type PullDirStatus

type PullDirStatus string

PullDirStatus mirrors project.PullDirStatus.

const (
	// PullDirMaterialized means the directory was created from central.
	PullDirMaterialized PullDirStatus = "materialized"
	// PullDirUpdated means the directory received newer central content.
	PullDirUpdated PullDirStatus = "updated"
	// PullDirUnchanged means the directory already matched central.
	PullDirUnchanged PullDirStatus = "unchanged"
	// PullDirProjectAhead means the directory holds changes central lacks.
	PullDirProjectAhead PullDirStatus = "project-ahead"
	// PullDirMerged means text differences merged without conflicts.
	PullDirMerged PullDirStatus = "merged"
	// PullDirConflicted means text conflict markers were written.
	PullDirConflicted PullDirStatus = "conflicted"
	// PullDirKeepBoth means a binary or non-text sibling was written.
	PullDirKeepBoth PullDirStatus = "keep-both"
	// PullDirCentralForced means explicit central selection replaced the directory.
	PullDirCentralForced PullDirStatus = "central-forced"
	// PullDirProjectForced means explicit project selection retained the directory.
	PullDirProjectForced PullDirStatus = "project-forced"
)

type PullProjectResult

type PullProjectResult struct {
	Name      string               `json:"name"`
	Status    PullProjectStatus    `json:"status"`
	Matches   []string             `json:"matches"`
	Checkouts []PullCheckoutResult `json:"checkouts"`
	Error     string               `json:"error"`
}

PullProjectResult is one public project outcome.

type PullProjectStatus

type PullProjectStatus string

PullProjectStatus mirrors project.PullProjectStatus.

const (
	// PullProjectPulled means at least one checkout received content.
	PullProjectPulled PullProjectStatus = "pulled"
	// PullProjectUnchanged means every checkout already matched.
	PullProjectUnchanged PullProjectStatus = "unchanged"
	// PullProjectMissing means no checkout was found in any configured root.
	PullProjectMissing PullProjectStatus = "missing"
	// PullProjectAmbiguous means several roots hold a candidate checkout.
	PullProjectAmbiguous PullProjectStatus = "ambiguous"
	// PullProjectRefused means a safety gate blocked the project.
	PullProjectRefused PullProjectStatus = "refused"
	// PullProjectFailed means the project was attempted and errored.
	PullProjectFailed PullProjectStatus = "failed"
	// PullProjectConflicted means at least one checkout needs resolution.
	PullProjectConflicted PullProjectStatus = "conflicted"
)

type PullResult

type PullResult struct {
	CentralRepo  string              `json:"central_repo"`
	CentralHead  string              `json:"central_head"`
	ScannedRoots []string            `json:"scanned_roots"`
	Projects     []PullProjectResult `json:"projects"`
}

PullResult is the public pull output model.

type PushCheckoutResult

type PushCheckoutResult struct {
	Path   string     `json:"path"`
	Status PushStatus `json:"status"`
}

PushCheckoutResult is one checkout considered by push.

type PushProjectResult

type PushProjectResult struct {
	Name      string               `json:"name"`
	Checkouts []PushCheckoutResult `json:"checkouts"`
}

PushProjectResult is one selected project.

type PushResult

type PushResult struct {
	CentralRepo   string              `json:"central_repo"`
	PreviousHead  string              `json:"previous_head"`
	CommitSHA     string              `json:"commit_sha"`
	CommitMessage string              `json:"commit_message"`
	Projects      []PushProjectResult `json:"projects"`
}

PushResult is the public push output model.

type PushStatus

type PushStatus string

PushStatus mirrors project.PushStatus so this package doesn't have to import project. Values are identical; the cmd layer converts.

const (
	// PushUnchanged means the checkout already matches central at a live base.
	PushUnchanged PushStatus = "unchanged"
	// PushPushed means the checkout's content was captured in central.
	PushPushed PushStatus = "pushed"
	// PushAdopted means content already matched and only the base advanced.
	PushAdopted PushStatus = "adopted"
)

type RmConfirmationView

type RmConfirmationView struct {
	ProjectName string
	CentralRepo string
	CommitMsg   string
	RecoveryCmd string
	Purge       bool
	Copies      []RmCopyResult
	RefusalNote string
}

type RmCopyResult

type RmCopyResult struct {
	Checkout string      `json:"checkout"`
	Dir      string      `json:"dir"`
	Path     string      `json:"path"`
	State    SyncState   `json:"state"`
	Issues   []SyncIssue `json:"issues"`
	Status   string      `json:"status"`
}

type RmResult

type RmResult struct {
	ProjectName   string         `json:"project"`
	CentralRepo   string         `json:"central_repo"`
	CommitMessage string         `json:"commit_message"`
	Commit        string         `json:"commit"`
	RecoveryCmd   string         `json:"recovery_command"`
	Purge         bool           `json:"purge"`
	Copies        []RmCopyResult `json:"copies"`
}

type SyncCheckoutResult

type SyncCheckoutResult struct {
	Path      string
	SyncBase  string
	State     SyncState
	BaseStale bool
	Dirs      []SyncDirResult
	Issues    []SyncIssue
}

SyncCheckoutResult is one independently tracked checkout.

type SyncCounts

type SyncCounts struct {
	InSync       int `json:"in_sync"`
	ProjectAhead int `json:"project_ahead"`
	CentralAhead int `json:"central_ahead"`
	Diverged     int `json:"diverged"`
}

SyncCounts contains stable file totals for every sync state.

type SyncDirResult

type SyncDirResult struct {
	Name      string
	State     SyncState
	BaseStale bool
	Files     []SyncFileResult
	Issues    []SyncIssue
}

SyncDirResult is one tracked agent directory.

type SyncEntry

type SyncEntry struct {
	Type       SyncEntryType
	Executable bool
	Data       []byte
}

SyncEntry is one side's file metadata and content.

type SyncEntryType

type SyncEntryType string

SyncEntryType mirrors reconcile.EntryKind.

const (
	SyncEntryFile    SyncEntryType = "file"
	SyncEntrySymlink SyncEntryType = "symlink"
)

type SyncFileResult

type SyncFileResult struct {
	Path          string
	State         SyncState
	ProjectChange string
	CentralChange string
	Project       *SyncEntry
	Central       *SyncEntry
	Base          *SyncEntry
}

SyncFileResult is one path's three-way classification.

type SyncIssue

type SyncIssue struct {
	Kind    SyncIssueKind `json:"kind"`
	Path    string        `json:"path"`
	Message string        `json:"message"`
}

SyncIssue is one health condition outside ordinary drift.

type SyncIssueKind

type SyncIssueKind string

SyncIssueKind mirrors reconcile.IssueKind.

const (
	SyncIssueCopyMissing       SyncIssueKind = "copy-missing"
	SyncIssueCopyInvalid       SyncIssueKind = "copy-invalid"
	SyncIssueUnsupportedObject SyncIssueKind = "unsupported-object"
	SyncIssueConflictMarkers   SyncIssueKind = "conflict-markers"
	SyncIssueConflictSibling   SyncIssueKind = "conflict-sibling"
	SyncIssueCentralDirty      SyncIssueKind = "central-dirty"
	SyncIssueBaseUnreachable   SyncIssueKind = "base-unreachable"
	SyncIssueCentralMissing    SyncIssueKind = "central-missing"
	SyncIssueInspectionFailed  SyncIssueKind = "inspection-failed"
)

type SyncProjectResult

type SyncProjectResult struct {
	Name      string
	Checkouts []SyncCheckoutResult
	Issues    []SyncIssue
}

SyncProjectResult groups a project's checkouts.

type SyncResult

type SyncResult struct {
	CentralRepo string
	CentralHead string
	Projects    []SyncProjectResult
}

SyncResult is the shared status and diff rendering model.

type SyncState

type SyncState string

SyncState mirrors reconcile.SyncState so this package doesn't import reconcile. cmd/lore/status.go translates the classifier's verdicts into it.

const (
	SyncInSync       SyncState = "in-sync"
	SyncProjectAhead SyncState = "project-ahead"
	SyncCentralAhead SyncState = "central-ahead"
	SyncDiverged     SyncState = "diverged"
)

type VersionEnvelope

type VersionEnvelope struct {
	Version string `json:"version"`
}

VersionEnvelope is the stable JSON shape emitted by `lore --version --json`.

Jump to

Keyboard shortcuts

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