render

package
v1.2.1 Latest Latest
Warning

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

Go to latest
Published: May 29, 2026 License: GPL-3.0 Imports: 11 Imported by: 0

Documentation

Index

Constants

View Source
const SchemaVersion = 1

SchemaVersion is the integer in the "schema" field of every JSON document we emit. Consumers should refuse to parse if SchemaVersion is higher than what they expect.

Versioning policy (see docs/json-schema.md):

  • v1 (current): top-level shape locked at {schema, content, findings, summary, meta}. `findings` is populated from the parsed LLM response under ADR-0014. `summary` and `content` remain in the schema for backwards compatibility:
  • `content` is populated only on graceful degrade (LLM produced unparseable output); empty on the happy path.
  • `summary` is reserved for a future LLM-authored prose summary; v1 always emits it as `{}`.
  • Additive changes (new optional fields in `meta`, new keys in `summary`, new fields on a Finding) are NOT a version bump. Consumers MUST ignore unknown fields.
  • Renaming, removing, or changing the type of any documented field IS a breaking change and requires bumping SchemaVersion to 2.

Variables

This section is empty.

Functions

func BuildCopyPayload added in v0.9.0

func BuildCopyPayload(findings []Finding) string

BuildCopyPayload joins per-finding CopyText blocks with a markdown horizontal-rule separator (`\n---\n\n`). Order is preserved from the input slice — callers that want severity-ordered output should sort beforehand (GroupBySeverity / severityOrder).

Returns "" for an empty slice; callers should branch on the empty case and skip the clipboard call entirely so the user doesn't get a hint line about copying zero findings.

func Cards added in v0.6.0

func Cards(w io.Writer, p Payload) error

Cards is the rich terminal renderer that frames the review with a styled header, a pre-body status line, one bordered panel per finding (severity- colored), and a one-line summary footer. It is the default Format when stdout is a TTY and neither --markdown nor --json is set.

Under ADR-0014 the LLM emits a JSON document parsed into Payload.Findings before render. If Findings is nil (graceful degrade — parse failed) the renderer falls back to a Stage A glamour-rendered body of Payload.Content so the user still sees something rather than a stack trace. Color resolution is delegated to lipgloss; NO_COLOR=1 and non-TTY stdout both downgrade automatically.

func CopyText added in v0.9.0

func CopyText(f Finding) string

CopyText returns a plain-text representation of f suitable for pasting into chat, an issue tracker, or a code editor. Format:

[💥 CRITICAL] internal/auth/session.go:142
SQL fragment built from request input

String concatenation feeds db.Query directly — bypasses the
prepared statement path used elsewhere in this package.

→ Switch to a prepared statement with bound parameters here so
user input never reaches the SQL string concatenation path.

The diff snippet is deliberately omitted — chat clients tend to mangle multi-line code blocks, and the path:line already gives the recipient enough to jump straight to the source. The description and suggestion are each flattened to a single paragraph (collapse internal whitespace) so they survive Slack/Discord rendering.

func CountFiles added in v0.6.0

func CountFiles(findings []Finding) int

CountFiles returns the number of distinct files referenced across the given findings.

func FooterLine added in v1.2.1

func FooterLine(m Meta, findings []Finding) string

FooterLine returns the "✓ Done in … · … tokens · $cost" line.

func HeaderLine added in v1.2.1

func HeaderLine(m Meta) string

HeaderLine, StatusLine, and FooterLine expose the three context lines the Cards renderer wraps around its body, so non-card review surfaces (e.g. `remote pr`, whose findings go to GitHub) can print the exact same informational lines to the terminal. Keeping one implementation guarantees they stay identical across every review command type.

func JSON

func JSON(w io.Writer, p Payload) error

func Markdown

func Markdown(w io.Writer, p Payload) error

Markdown writes a plain-markdown rendering of the review. Under ADR-0014 the renderer runs the user's OUTPUT.md as a Go text/template against the parsed Findings; it never sees the system prompt or any LLM-side formatting. Graceful degrade paths:

  • p.Findings == nil → emit p.Content verbatim (parse failed upstream).
  • p.OutputTemplate == "" → emit p.Content verbatim (no template loaded).
  • template execute fails → return the error; pre-send validation (ADR-0014 §5) should have caught this, so if we land here a regression occurred and the caller deserves to see it rather than silently render half-formed output.

func StatusLine added in v1.2.1

func StatusLine(m Meta) string

StatusLine returns the "analyzing N files · …" line, or "" when no diff stats are populated.

func TemplateFuncs added in v0.6.0

func TemplateFuncs() template.FuncMap

TemplateFuncs is the function map registered on every OUTPUT.md template the renderer parses. The set is the public template contract (ADR-0014 §2); additions are allowed in v1.x but removals require a schema bump.

func Terminal

func Terminal(w io.Writer, p Payload) error

func ValidateOutputTemplate added in v0.6.0

func ValidateOutputTemplate(content string) error

ValidateOutputTemplate is the pre-send guard from ADR-0014 §5. It runs three checks against a template body so a malformed user OUTPUT.md fails before any provider round-trip:

  1. Parse — text/template syntax check.
  2. Empty-findings execute — does the template crash on the empty case?
  3. Sample-findings execute — does the template crash with two findings (critical + info) populated, covering both branches of any severity-based conditional logic.

Returns the first failure verbatim, wrapped with a stable prefix the CLI uses to format an i18n'd error message. Returns nil on success.

func VerboseFooter

func VerboseFooter(m Meta) string

VerboseFooter returns the multi-line footer appended after a review when --verbose is in effect. Format is stable: tokens, cost, latency, provider, model — each on its own line, aligned. Cached results get a `(cached)` marker on the tokens line so users see why a fast result was free.

Types

type Finding added in v0.6.0

type Finding struct {
	Severity    Severity `json:"severity"`
	File        string   `json:"file"`
	Line        int      `json:"line"`
	LineEnd     int      `json:"line_end,omitempty"`
	Title       string   `json:"title"`
	Description string   `json:"description"`
	Suggestion  string   `json:"suggestion"`
	Language    string   `json:"language,omitempty"`
	Snippet     string   `json:"snippet,omitempty"`
}

Finding is one review item the LLM returned. See ADR-0014 §1 for the full contract, including which fields are required.

func ParseFindings added in v0.6.0

func ParseFindings(content string) ([]Finding, error)

ParseFindings decodes the LLM-emitted JSON payload into a slice. The returned slice may be empty (a clean review) but is non-nil on success. Errors trigger graceful degrade at the caller (ADR-0014 §4) — the pipeline never crashes on a malformed response.

func (Finding) LineRef added in v0.9.0

func (f Finding) LineRef() string

LineRef formats the line reference as "142" when the finding is pinned to a single line, or "142-145" when LineEnd is set and greater than Line. Used by all renderers (cards, copytext, markdown via .LineRef template field) so the range display stays consistent. Returns "" when Line <= 0 so callers can branch on the missing case rather than emit "path:0".

LineEnd is treated as a closed range — both endpoints inclusive, matching how source-code "lines 142–145" reads in human writing. Out-of-order values (LineEnd < Line) and equal values (LineEnd == Line) collapse to a single-line ref; we never emit "142-142" or "145-142", both of which would be confusing.

func (Finding) PathRef added in v0.9.0

func (f Finding) PathRef() string

PathRef joins File and LineRef with ":" so callers don't repeat the conditional logic. Returns File alone when LineRef is empty.

type Format

type Format int
const (
	FormatTerminal Format = iota
	FormatMarkdown
	FormatJSON
)

func (Format) String

func (f Format) String() string

type Meta

type Meta struct {
	Provider  string
	Model     string
	Lang      string
	Usage     provider.Usage
	Cost      float64
	Latency   time.Duration
	Cached    bool
	Timestamp time.Time
	// Stats describing what went into this review. Used by the Cards
	// renderer for its pre-body status line; zero values cause the line
	// to be omitted. Markdown / JSON / verbose-footer renderers ignore
	// these fields, so adding more here is backwards-compatible.
	Files        int  // post-filter file count
	LinesAdded   int  // total `+` lines in the reviewed diff
	LinesRemoved int  // total `-` lines in the reviewed diff
	RulesLoaded  bool // a non-default COMMITBRIEF.md was loaded
}

type Payload

type Payload struct {
	// Content is the raw provider response — under ADR-0014 a JSON string
	// matching the findings schema; on graceful degrade it may be free-form
	// markdown left over from a malformed JSON response. Cached as-is.
	Content string

	// Findings is the parsed structured response from the LLM. A non-nil
	// empty slice means "no review-worthy issues"; a nil slice signals
	// graceful degrade — the JSON parse failed and renderers must fall
	// back to rendering Content directly (Stage A behavior).
	Findings []Finding

	// OutputTemplate is the loaded OUTPUT.md template body, consumed by the
	// Markdown renderer. Empty string falls back to emitting Content
	// unchanged (also the path used during degrade).
	OutputTemplate string

	// Compact requests one-line-per-finding rendering in the Cards layout,
	// useful when a review surfaces many findings and per-finding panels
	// would dominate the terminal. Header/status/footer stay; the body
	// becomes a severity-ordered list of "[icon] SEVERITY • file:line —
	// title" lines. Other renderers (Markdown/JSON) ignore this field.
	Compact bool

	Meta    Meta
	Verbose bool
}

type Severity added in v0.6.0

type Severity string

Severity ranks how urgently a finding should be addressed. The vocabulary is the wire contract with the LLM (ADR-0014 §1) and is intentionally English-only; UI strings around it are i18n-able at the renderer layer.

const (
	SeverityCritical Severity = "critical"
	SeverityHigh     Severity = "high"
	SeverityMedium   Severity = "medium"
	SeverityLow      Severity = "low"
	SeverityInfo     Severity = "info"
)

func (Severity) IsValid added in v0.6.0

func (s Severity) IsValid() bool

IsValid reports whether s is one of the five canonical levels.

type SeverityGroup added in v0.6.0

type SeverityGroup struct {
	Severity Severity
	Items    []Finding
}

SeverityGroup is the value type produced by GroupBySeverity for template consumption. Items preserve the order they appeared in the source slice.

func GroupBySeverity added in v0.6.0

func GroupBySeverity(findings []Finding) []SeverityGroup

GroupBySeverity returns findings grouped by severity, ordered critical → info. Empty buckets are omitted so templates can iterate without a presence check.

type Summary

type Summary struct {
}

type TemplateData added in v0.6.0

type TemplateData struct {
	Findings []Finding
}

TemplateData is the value passed to a parsed OUTPUT.md template at execution time. Keeping the struct named (rather than a bare slice) lets templates write `{{ range .Findings }}` and gives future fields a stable home.

Jump to

Keyboard shortcuts

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