claudecore

package
v0.28.2 Latest Latest
Warning

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

Go to latest
Published: Sep 17, 2026 License: MIT Imports: 18 Imported by: 0

Documentation

Index

Constants

View Source
const (
	PromptInjectCheckInterval = 500 * time.Millisecond
	PromptInjectTimeout       = 30 * time.Second
)
View Source
const (
	// StopReasonAgentNotFound means Claude Code rejected the --agent name.
	StopReasonAgentNotFound = "agent_not_found"
	// StopReasonLaunchFailed means claude exited before avenor submitted a
	// prompt, for a reason avenor could not name.
	StopReasonLaunchFailed = "launch_failed"
)

Stop reasons for a Claude process that exited without ever running a turn. Both report status=failed: the old behaviour reported status=done with an empty output, which is byte-for-byte what a real end_turn that said nothing looks like, so callers could not tell a typo from a completed run.

Variables

This section is empty.

Functions

func CreateStderrLog added in v0.26.0

func CreateStderrLog() (string, error)

CreateStderrLog creates the file LaunchCommand redirects claude's stderr into. The caller owns it and should remove it on teardown via Session.

func DefaultLauncher

func DefaultLauncher() terminal.Launcher

func LaunchCommand added in v0.26.0

func LaunchCommand(args []string, stderrLog string) string

LaunchCommand renders the shell command that starts claude inside a terminal.

`exec` replaces the shell with claude so that tmux's #{pane_pid} reports claude's own PID and the terminal exits when claude does.

stderr goes to stderrLog because a fatal launch banner is otherwise unreachable. Claude Code writes it to stderr and exits within ~300ms; tmux then destroys the session together with its pane, and `capture-pane` shows a blank grid for the whole life of that pane anyway (confirmed at 25ms sampling, and with remain-on-exit holding the dead pane open). A file survives both. The redirect costs nothing on a healthy run: Claude Code draws its TUI on stdout and leaves stderr empty.

func MustJSON

func MustJSON(v any) json.RawMessage

func ShellQuote

func ShellQuote(s string) string

ShellQuote single-quotes a string for safe interpolation into a shell command.

func StripANSI added in v0.26.0

func StripANSI(s string) string

StripANSI removes terminal escape sequences from scraped output.

func TranscriptPath

func TranscriptPath(home, dir, sessionID string) string

func ValidTmuxKey

func ValidTmuxKey(key string) bool

ValidTmuxKey returns true if key is a safe single-character string for tmux send-keys.

func WaitForPaneReady

func WaitForPaneReady(ctx context.Context, term terminal.Session) bool

WaitForPaneReady blocks until Claude's input box is taking input. It auto-dismisses the trust-safety dialog if present. Returns false on context cancel, capture error, send error, or the PromptInjectTimeout deadline — callers must treat any false return as "do not paste, the pane is not in a known-ready state".

Types

type AgentNotFound added in v0.26.0

type AgentNotFound struct {
	// Agent is the rejected --agent value. Empty when the banner did not parse.
	Agent string
	// Available is the roster Claude Code listed, whitespace-collapsed. Empty
	// when the capture did not include it.
	Available string
}

AgentNotFound is the diagnosis for a launch Claude Code refused because it did not recognise the requested agent.

func DetectAgentNotFound added in v0.26.0

func DetectAgentNotFound(text string) (AgentNotFound, bool)

DetectAgentNotFound reports whether text holds the unrecognised-agent banner, along with whatever diagnostics it could recover from it.

func (AgentNotFound) Message added in v0.26.0

func (a AgentNotFound) Message() string

Message renders the diagnosis for the event stream. The roster is the single most useful thing for whoever typo'd the agent name, so it goes in the message and not only in a structured field.

type PaneState

type PaneState string
const (
	PaneStateUnknown    PaneState = "unknown"
	PaneStateActive     PaneState = "active"
	PaneStatePermission PaneState = "permission"
	PaneStateIdle       PaneState = "idle"
)

func ClassifyPane

func ClassifyPane(text string) PaneState

ClassifyPane returns the most-specific pane state. After a turn is submitted the pane shows both an echo line that starts with `❯` (the prior user prompt) AND a spinner line below it; the input box `❯` reappears at the bottom. An activity line therefore must beat any `❯` line, otherwise we'd report idle while a turn is still running.

func ScanTerminal

func ScanTerminal(ctx context.Context, term terminal.Session) (PaneState, error)

type PermissionOption

type PermissionOption struct {
	ID    string
	Label string
}

type Session

type Session struct {
	SessionID string
	RunID     string
	Dir       string
	TmuxName  string

	Term       terminal.Session
	Transcript *TranscriptReader

	// StderrLog is the file claude's stderr is redirected into by LaunchCommand.
	// It outlives the terminal, which is the only way to read a fatal launch
	// banner — see LaunchCommand for why the pane cannot be used.
	StderrLog string

	Events    chan events.Event
	Done      chan struct{}
	Ctx       context.Context
	CancelFn  context.CancelFunc
	StartedAt time.Time

	Mu                  sync.Mutex
	Prompted            bool
	Active              bool
	Finished            bool
	PendingTerminalPerm *TerminalPermission
}

func NewSession

func NewSession(ctx context.Context, opts SessionOptions) *Session

func (*Session) Emit

func (s *Session) Emit(ev events.Event)

func (*Session) EmitTerminalGone added in v0.26.0

func (s *Session) EmitTerminalGone(ctx context.Context)

EmitTerminalGone emits the terminal session.end for a Claude process that exited on its own. Both providers call it from their sessionGone branch, which cannot tell a finished turn from a refused launch by itself — the alive poll sees the same dead terminal either way — so classify the exit first.

MarkFinished is the existing guard against double-emitting: a run that already reported avenor_finish, a cancel, or a transcript end_turn keeps that verdict.

func (*Session) MarkActive

func (s *Session) MarkActive()

func (*Session) MarkFinished

func (s *Session) MarkFinished() bool

func (*Session) RemoveStderrLog added in v0.26.0

func (s *Session) RemoveStderrLog()

RemoveStderrLog deletes the stderr log. Safe to call on a session that has none.

func (*Session) ScanTerminalTick

func (s *Session) ScanTerminalTick()

func (*Session) ScanTranscriptTick

func (s *Session) ScanTranscriptTick()

func (*Session) SendCancelKeys

func (s *Session) SendCancelKeys(ctx context.Context) error

type SessionOptions

type SessionOptions struct {
	SessionID  string
	RunID      string
	Dir        string
	TmuxName   string
	Term       terminal.Session
	Transcript *TranscriptReader
	StderrLog  string
	EventsBuf  int
}

type TerminalPermission

type TerminalPermission struct {
	RequestID string
	Prompt    string
	Options   []PermissionOption
	CreatedAt time.Time
}

func ParseTerminalPermission

func ParseTerminalPermission(text string) *TerminalPermission

ParseTerminalPermission extracts a TerminalPermission from pane text, or nil if the text doesn't represent a Claude permission dialog.

type TranscriptReader

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

TranscriptReader incrementally reads new records from a JSONL transcript. Successive Tick calls return only records appended since the last call.

func NewTranscriptReader

func NewTranscriptReader(path string) *TranscriptReader

func (*TranscriptReader) Tick

Tick reads records appended since the previous call. It returns the records, the file's mtime (zero if missing), and any read error. A missing file is not an error — callers tick early and often, and the transcript only appears once Claude writes its first record.

Offset only advances past newline-terminated lines so a half-written final record is left for the next tick to consume in full.

type TranscriptRecord

type TranscriptRecord struct {
	Type          string         `json:"type"`
	AITitle       string         `json:"aiTitle,omitempty"`
	Timestamp     string         `json:"timestamp,omitempty"`
	StopReason    string         `json:"stop_reason,omitempty"`
	Text          string         `json:"text,omitempty"`
	ContentEvents []events.Event `json:"-"`
}

TranscriptRecord is the minimal subset of JSONL fields used for status and best-effort content extraction.

Directories

Path Synopsis
Package terminal provides an abstraction for interactive terminal sessions.
Package terminal provides an abstraction for interactive terminal sessions.

Jump to

Keyboard shortcuts

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