repl

package
v0.0.0-...-e2e9674 Latest Latest
Warning

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

Go to latest
Published: Sep 30, 2026 License: Apache-2.0 Imports: 34 Imported by: 0

Documentation

Overview

Package repl is the interactive layer: readline input with slash commands, double-Ctrl-C chords, and live-rendered markdown streaming via internal/render.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func IsCommand

func IsCommand(name string) bool

IsCommand reports whether name (without the slash) is a REPL command. Script mode uses it to tell a command it cannot run from text that merely starts with a slash, such as a path.

func UserInterruptSignal

func UserInterruptSignal() syscall.Signal

UserInterruptSignal reports the signal the REPL and script mode treat as a stop-the-send interrupt, for a caller wiring its own signal.NotifyContext — main, which has no REPL to subscribe for it.

Types

type Options

type Options struct {
	Coder      *coder.Coder
	Config     *config.Config
	ModelAlias string // alias of the active model, for /model display

	// ResumeNote is a banner line naming what a previous session left pinned,
	// "" when nothing was restored. The banner lists the files either way; this
	// says where they came from, so restored context is never invisible.
	ResumeNote string

	// SaveResume records what a resume would restore, called after any command
	// that changes it. nil when the session leaves no trace (--no-history), so
	// the REPL needs no flag of its own.
	SaveResume func(alias string)

	// Git enables /undo and /diff; nil outside a repository (--no-git).
	Git *gitrepo.Repo

	// Sessions is what /session needs from the host: a project's
	// conversations and the operations that move between them. nil disables
	// the command, which is what a session leaving no trace wants — there is
	// nowhere for another conversation to be.
	Sessions *SessionOps

	// Notes returns the current session notes for /notes. nil disables the
	// command.
	Notes func() string

	// GenerateNotes regenerates notes from the transcript into memory.
	// Called by /notes generate. nil when notes are unavailable.
	GenerateNotes func(ctx context.Context) error

	// DropNotes discards the notes for this session.
	DropNotes func()

	// MakeClient builds a client when /model switches providers.
	MakeClient func(*config.Model) llm.ModelClient

	// RefreshCommitMessage rebuilds the git commit-message generator when the
	// active model changes. It is nil in sessions without git integration.
	RefreshCommitMessage func(*config.Model)

	// ConsultScope is how much of the session /consult shows the advisor. The
	// zero value is coder.ConsultNothing — the binary sets this from
	// --consult-scope, whose default is where the shipped behaviour lives,
	// because the ladder's order is what makes `scope >= ConsultFiles` read
	// correctly and "none" is the bottom of it.
	ConsultScope coder.ConsultScope

	// ReloadConfig re-reads config.star for /reload, using the same options as
	// the initial load. nil disables /reload.
	ReloadConfig func() (*config.Config, error)

	// ApplyEgress rebuilds the fetch and search ports from a reloaded config.
	// A closure because building them needs the proxy transport and the version
	// string, which are the binary's business rather than the REPL's — the same
	// reason MakeClient is one. Without it, /reload leaves both ports as they
	// were at startup, which is how a proxy fix could be applied, reloaded, and
	// silently ignored.
	ApplyEgress func(*coder.Coder, *config.Config)

	// Rediscover re-runs skill discovery for /reload, reopening the trust
	// store so a `strument trust` run in another window takes effect. A
	// closure for the same reason ApplyEgress is one: where the trust store
	// lives is the binary's business. nil leaves the session's skills alone.
	Rediscover func() []skill.Skill

	Color       bool
	HistoryFile string

	// Version fills the opening banner's "Strument v…" line.
	Version string
	// Theme is the color palette; the zero value defaults to DefaultTheme.
	Theme render.Theme
	// GetSize reports the terminal width for the horizontal rules (and is
	// shared with readline so its completion grid wraps at the same width).
	// nil falls back to 80 columns.
	GetSize func() (width, height int)

	Stdin  io.Reader // default os.Stdin
	Stdout io.Writer // default os.Stdout
	Stderr io.Writer // default os.Stderr

	// IsTerminal overrides terminal detection (readline renders line
	// editing only on real terminals).
	IsTerminal func() bool
	// StdinIsTerminal reports whether there is someone at the keyboard, and
	// gates the two places the harness asks a question mid-turn. nil means
	// yes, which is what the tests want and what the REPL assumed before this
	// existed.
	//
	// Separate from IsTerminal, which is about *rendering* and is true only
	// when both ends are a terminal. Redirecting output alone — `strument |
	// tee log` — leaves a human perfectly able to answer a prompt, and folding
	// the two questions together would refuse to ask them.
	StdinIsTerminal func() bool
	// MakeRaw/ExitRaw override raw-mode handling; readline's default
	// operates on the process's stdin, which tests replace with a pty.
	MakeRaw func() error
	ExitRaw func() error
	// Notify subscribes ch to SIGINT and the user-space interrupt
	// (interruptSignal) for the duration of a turn and returns the
	// unsubscribe. Default: os/signal.
	Notify func(ch chan<- os.Signal) (stop func())
	// Exit ends the process on the second in-turn Ctrl-C. Default: os.Exit.
	Exit func(code int)
	// Now is the chord clock. Default: time.Now.
	Now func() time.Time
	// RunEditor opens argv — an editor command with the file to edit last —
	// and waits for it, for /editor and Ctrl-X Ctrl-E. Default: editor.Run.
	RunEditor func(argv []string) error
}

Options configures a REPL. Zero values mean production defaults; the seams (Stdin/Stdout, IsTerminal, Notify, Exit, Now) exist for the pty tests.

type REPL

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

REPL is the interactive session driver.

func New

func New(opts Options) (*REPL, error)

New builds the REPL, wires the coder's Out to the live renderer, and prepares readline. Close releases the terminal.

func (*REPL) Asker

func (r *REPL) Asker() coder.Asker

Asker returns a coder.Asker that asks questions on this REPL's terminal. Unlike Confirmer there is no AutoConfirmer to wrap it in: --yes and --yes answers permission prompts, and a question is not one.

func (*REPL) Close

func (r *REPL) Close() error

Close releases the readline terminal state.

func (*REPL) Config

func (r *REPL) Config() *config.Config

Config is the configuration the session is running on now: the one it started with, or the last one /reload read. Code outside the REPL that was handed the startup config holds a copy /reload never touches.

func (*REPL) Confirmer

func (r *REPL) Confirmer() coder.Confirmer

Confirmer returns a coder.Confirmer that asks on this REPL's terminal; wrap it in an AutoConfirmer for --yes handling.

func (*REPL) Run

func (r *REPL) Run(ctx context.Context) error

Run is the main loop: getInput -> dispatch/runOne -> undo hint. It returns when the user exits (/exit, Ctrl-D, or a Ctrl-C chord at the prompt).

type SessionOps

type SessionOps struct {
	// Current is the conversation in use.
	Current func() string
	// List is every conversation the project holds, newest use first.
	List func() ([]history.Session, error)
	// Switch opens another conversation; create says whether it is expected
	// to be new. It returns the lines to show.
	//
	// alias is the model alias the user typed, which the REPL owns because
	// /model changes it. The host writes it into the new session's record
	// header and its resume file, and has no other way to know it.
	Switch func(name string, create bool, alias string) (string, error)
	// Fork starts a new conversation carrying this one's notes.
	Fork func(name, alias string) (string, error)
	// Rename renames one, following the process into it when it is the one in
	// use.
	Rename func(from, to string) error
	// Delete removes one that is not in use.
	Delete func(name string) error
}

SessionOps are the host's session operations, for /session.

The REPL knows a conversation by name and nothing else. Where one lives, what it restores and how its record is opened are the host's, for the same reason SaveResume and GenerateNotes are: neither the coder nor the REPL learns the layout of the state directory.

Jump to

Keyboard shortcuts

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