utils

package
v1.10.20 Latest Latest
Warning

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

Go to latest
Published: Aug 7, 2026 License: MIT Imports: 27 Imported by: 0

Documentation

Index

Constants

View Source
const MaxShortenedNewlines = 5

Variables

View Source
var Live bool

Live controls whether macro mode switches to interactive stdin after consuming all macro inputs (true, default) or appends trailing "q\n" terminators for graceful auto-exit (false). Set by Setup() based on the --non-interactive flag.

View Source
var ReadonlyConfig bool

ReadonlyConfig makes config loads read-only: missing fields are filled in memory, but the file is never rewritten and no upgrade announcement is printed. Set for raw (machine-readable) runs so shell hooks and scripts never mutate the user's configs as a side effect (config migration design, Q5). This is what keeps a precmd hook running `clai -r chat dirv2` from silently migrating the configs before the user's own commands run.

Functions

func AttemptPrettyPrint

func AttemptPrettyPrint(w io.Writer, chatMessage pub_models.Message, username string, raw bool) error

AttemptPrettyPrint by first checking if the glow command is available, and if so, pretty print the chat message. If not found, simply print the message as is. If the message has ReasoningContent, it is rendered with reasoning color before the main content.

If w is nil, os.Stdout is used.

func ConfigDirPaths

func ConfigDirPaths() []string

func ConfigUpgradeMessage added in v1.10.20

func ConfigUpgradeMessage(configFileName string, added []string) string

ConfigUpgradeMessage returns the announcement text for fields added to a config file, e.g. "added new field(s) to textConfig.json: stoploss".

func CreateConfigDir

func CreateConfigDir(configPath string) error

func CreateFile

func CreateFile[T any](path string, toCreate *T) error

func DeleteRange

func DeleteRange[T any](s []T, start, end int) ([]T, error)

DeleteRange removes elements in [start, end] (inclusive) from the slice and returns the new slice. Panics if indices are invalid. Works for any slice type (Go 1.18+).

func EscapeEditorString added in v1.10.11

func EscapeEditorString(edited string) string

func GetClaiCacheDir

func GetClaiCacheDir() (string, error)

GetClaiCacheDir returns the path to the clai cache directory. The directory is located inside the user's cache directory as <UserCacheDir>/clai, unless overridden by CLAI_CACHE_DIR.

func GetClaiConfigDir

func GetClaiConfigDir() (string, error)

GetClaiConfigDir returns the path to the clai configuration directory. The directory is located inside the user's configuration directory as <UserConfigDir>/.clai, unless overridden by CLAI_CONFIG_DIR.

func GetFirstTokens

func GetFirstTokens(prompt []string, n int) []string

GetFirstTokens returns the first n tokens of the prompt, or the whole prompt if it has less than n tokens

func IsTerminalWriter added in v1.10.20

func IsTerminalWriter(w io.Writer) bool

IsTerminalWriter reports whether w resolves to a terminal writer.

func LoadConfigFromFile

func LoadConfigFromFile[T any](
	configDirPath,
	configFileName string,
	migrationCb func(string) error,
	dflt *T,
) (T, error)

func LoadConfigFromFileCollect added in v1.10.20

func LoadConfigFromFileCollect[T any](
	configDirPath,
	configFileName string,
	migrationCb func(string) error,
	dflt *T,
) (T, []string, error)

LoadConfigFromFileCollect is LoadConfigFromFile without the stdout announcement. It returns the JSON paths of every field it added to a pre-existing file, e.g. "stoploss" or "stoploss.max-tokens-handover-instructions"; an empty list means the file needed no upgrade (or was freshly created). Callers whose own output would overwrite the announcement (e.g. the interactive setup wizard, whose TUI erases pre-wizard stdout) use this to announce after their output is done.

func LoadTheme

func LoadTheme(configDirPath string) error

LoadTheme loads (and possibly creates) the theme.json file within the config dir. It is safe to call multiple times. After loading, stores the theme for consumer access.

func NewMacroReader added in v1.10.17

func NewMacroReader(inputs []string) io.Reader

NewMacroReader creates a reader that yields each input string as a line.

By default (Live=true), after all macro inputs are consumed the reader transparently switches to os.Stdin so the user continues interacting.

When Live is false (--non-interactive), 10 trailing "q\n" lines are appended for graceful termination through nested table loops.

Returns nil when inputs is empty or nil (caller should skip injection).

func NotificationBellEnabled

func NotificationBellEnabled() bool

func PrepareDisplayMessage added in v1.10.10

func PrepareDisplayMessage(msg pub_models.Message) pub_models.Message

func PrintToolActivity added in v1.10.20

func PrintToolActivity(w io.Writer, call pub_models.Call, content string, termWidth, maxRows int) error

PrintToolActivity prints one non-raw tool execution as a header and its result. The model transcript remains independent from this display-only representation.

func Prompt

func Prompt(stdinReplace string, args []string) (string, error)

Prompt returns the prompt by checking all the arguments and stdin. If there is no arguments, but data in stdin, stdin will become the prompt. If there are arguments and data in stdin, all stdinReplace tokens will be substituted with the data in stdin

func RandomPrefix

func RandomPrefix() string

func ReadAndUnmarshal

func ReadAndUnmarshal[T any](filePath string, config *T) error

ReadAndUnmarshal by first finding the file, then attempting to read + unmarshal to T

func ReplaceTildeWithHome

func ReplaceTildeWithHome(s string) (string, error)

func ResolveConfigDirPath

func ResolveConfigDirPath(configDir string, components []string) (string, error)

func ReturnNonDefault

func ReturnNonDefault[T comparable](a, b, defaultVal T) (T, error)

func RoleColor

func RoleColor(role string) string

RoleColor returns the theme color for a chat role.

func RollingOutputEnabled added in v1.10.20

func RollingOutputEnabled() bool

RollingOutputEnabled reports whether reasoning and tool activity share a rolling terminal viewport.

func RollingOutputWindowCellHeight added in v1.10.20

func RollingOutputWindowCellHeight() int

RollingOutputWindowCellHeight returns the maximum terminal cells (rows) for the shared rolling activity viewport.

func SaveBase64File added in v1.10.17

func SaveBase64File(prefix, dir, b64JSON, extension string) (string, error)

SaveBase64File decodes a base64 string and writes it to dir/prefix_random.extension. Falls back to /tmp on write failure.

func SessionDimensions added in v1.10.20

func SessionDimensions(w io.Writer) dimensions.Dimensions

SessionDimensions resolves the one terminal-size snapshot for w. The snapshot is bound to the writer's file descriptor, so the observed size matches the file the output is actually written to (R2-02): a terminal yields its live size, and a non-terminal writer, a failed read, or a reported zero size deterministically yields dimensions.Fallback (80x24). No error propagates, matching the legacy silent fallback. A nil writer resolves to os.Stdout.

This is the single width-discovery point of clai. Every width-aware render path either stores the result of this helper for its session (the querier's snapshot) or calls it once at the start of a standalone render operation.

func ShortenedOutput

func ShortenedOutput(out string, maxShortenedNewlines int) string

ShortenedOutput returns a shortened version of the output

func SummarizeAsyncToolResult added in v1.10.20

func SummarizeAsyncToolResult(name, content string) string

SummarizeAsyncToolResult returns the concise interactive representation of async tool output. Raw and redirected output bypass this helper.

func TableTheme added in v1.10.17

func TableTheme() table.Theme

TableTheme returns the table.Theme derived from the current global theme.

func ThemeConfigPath

func ThemeConfigPath(configDirPath string) string

ThemeConfigPath returns the fully qualified theme.json path.

func ToolOutputRows added in v1.10.20

func ToolOutputRows() int

ToolOutputRows returns the maximum terminal rows used for non-raw tool output.

func UnescapeEditorString added in v1.10.11

func UnescapeEditorString(toEdit string) string

func UpdateMessageTerminalMetadata

func UpdateMessageTerminalMetadata(msg string, line *string, lineCount *int, termWidth int)

UpdateMessageTerminalMetadata updates the terminal metadata. Meaning the lineCount, to eventually clear the terminal

func WriteFile

func WriteFile[T any](path string, toWrite *T) error

Types

type ActivityViewport added in v1.10.20

type ActivityViewport struct {
	// contains filtered or unexported fields
}

ActivityViewport keeps a bounded, display-only view of streamed reasoning, assistant prose, and tool activity. It never changes model or tool source data.

Storage is logical, not visual: each block keeps the full sanitized content (the source of truth) plus its display policy (kind, header and role colours, 2-space body indentation, and tool output-marker and ERROR: handling). Colours and indentation are re-derived at rewrap time, so a width change rewraps every retained block instead of reconstructing content from already wrapped rows. The active reasoning and text blocks coalesce streamed tokens into one open block; finished blocks keep their logical content until the retention policy evicts them (maxActivityBlocks blocks, each bounded by maxActivityBlockRunes). A terminal-height grow can therefore bring retained content back into view, bounded by retention, not by the last visible row count.

func NewActivityViewport added in v1.10.20

func NewActivityViewport(width, maxRows, terminalHeight int) *ActivityViewport

NewActivityViewport creates a viewport for all transient model activity. maxRows is the configured rolling-window cap; terminalHeight is the raw terminal height at creation. The effective height is min(maxRows, max(terminalHeight, 1)) from the start, so the viewport never renders taller than the terminal it writes to (R5-01). Resize takes raw terminal dimensions and keeps the same min(cap, terminal height) bound on later dimension changes.

func (*ActivityViewport) AppendReasoning added in v1.10.20

func (v *ActivityViewport) AppendReasoning(content string)

AppendReasoning adds a reasoning block. The warm colour applies only to its header; its indented body has the same neutral presentation as tool output. An open assistant-prose block is closed first so the reasoning starts a new block.

func (*ActivityViewport) AppendText added in v1.10.20

func (v *ActivityViewport) AppendText(content string)

AppendText adds an assistant-prose block to the same viewport. Streamed tokens coalesce into one block until FinishText or RemoveTextBlock closes it.

func (*ActivityViewport) AppendTool added in v1.10.20

func (v *ActivityViewport) AppendTool(call pub_models.Call, content string, maxRows int)

AppendTool adds a compacted tool block to the same viewport. An open assistant-prose or reasoning block is closed first so the tool starts a new block.

func (*ActivityViewport) Content added in v1.10.20

func (v *ActivityViewport) Content() string

Content returns the sanitized content of the open reasoning block, or "" when no reasoning block is open.

func (*ActivityViewport) DetachRenderedRegion added in v1.10.20

func (v *ActivityViewport) DetachRenderedRegion() int

DetachRenderedRegion transfers ownership of the rows already drawn to the caller. The retained activity history will render at the current cursor position on the next Render call.

func (*ActivityViewport) FinishReasoning added in v1.10.20

func (v *ActivityViewport) FinishReasoning()

FinishReasoning closes the current reasoning block. Its visible rows stay in the activity history, while the next reasoning event starts a new block.

func (*ActivityViewport) FinishText added in v1.10.20

func (v *ActivityViewport) FinishText()

FinishText closes the active assistant-prose block. Its visible rows stay in the activity history, while the next prose stream starts a new block.

func (*ActivityViewport) RemoveTextBlock added in v1.10.20

func (v *ActivityViewport) RemoveTextBlock() int

RemoveTextBlock removes the active assistant-prose block from the activity history and returns the number of rows removed. The final answer is removed this way so it prints below the window instead of remaining inside it. The active text block is the last retained block, so its rows are the cache tail.

func (*ActivityViewport) Render added in v1.10.20

func (v *ActivityViewport) Render(w io.Writer) error

Render redraws the viewport in its existing terminal region. A dirty viewport (after Resize or a partial write) emits one complete atomic frame: move up the previously drawn rows, clear down, and rewrite the full window. The diff path is used only for normal streaming appends: pure appends print below the previously drawn region without clearing, and a changed tail clears from the first changed row down. The whole update lands in one write, so the terminal never paints an intermediate blank frame. The cursor is left below the viewport so subsequent tool activity or answer text follows it. A partial or failed write leaves the viewport dirty; the next Render retries the full frame.

func (*ActivityViewport) Resize added in v1.10.20

func (v *ActivityViewport) Resize(width, terminalHeight int)

Resize applies new terminal dimensions to the viewport. It mutates state only: it stores the new width, computes the effective height as min(configured cap, terminal height), rewraps all retained blocks at the new width, invalidates the render bookkeeping, and marks the viewport dirty. It never writes to the writer and is a no-op when the supplied dimensions equal the current ones. Resize is invoked only from the serialized session loop, never from a signal callback; mutation and rendering stay on that loop, so no mutex is needed.

func (*ActivityViewport) Rows added in v1.10.20

func (v *ActivityViewport) Rows() []string

Rows returns the physical terminal rows currently visible in the viewport.

func (*ActivityViewport) TextBlockActive added in v1.10.20

func (v *ActivityViewport) TextBlockActive() bool

TextBlockActive reports whether an assistant-prose block is currently open.

type ContextKey

type ContextKey string
const (
	ContextCancelKey ContextKey = "contextCancel"
)

type RollingOutputConfig added in v1.10.20

type RollingOutputConfig struct {
	Enabled bool `json:"enabled"`

	WindowCellHeight int `json:"windowCellHeight"`
}

RollingOutputConfig configures the shared rolling activity viewport that contains streamed reasoning and tool blocks.

type Theme

type Theme struct {
	Primary   string `json:"primary"`
	Secondary string `json:"secondary"`
	Breadtext string `json:"breadtext"`

	RoleSystem    string `json:"roleSystem"`
	RoleUser      string `json:"roleUser"`
	RoleTool      string `json:"roleTool"`
	RoleReasoning string `json:"roleReasoning"`
	RoleOther     string `json:"roleOther"`

	NotificationBell bool `json:"notificationBell"`

	TableItems int `json:"tableItems"`

	ToolOutputRows int `json:"toolOutputRows"`

	RollingOutput RollingOutputConfig `json:"rollingOutput"`
}

Theme holds ANSI color configuration for terminal output. Values are raw ANSI escape sequences (e.g. "\u001b[38;2;120;140;160m").

This file is loaded from <clai-config-dir>/theme.json on startup. If NO_COLOR is set truthy, all colorization should be disabled.

Keep this config stable; new fields should be appended with defaults. Users can customize their own theme.json.

Jump to

Keyboard shortcuts

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