Documentation
¶
Overview ¶
Package shell provides cross-platform shell execution capabilities.
This package provides Shell instances for executing commands with their own working directory and environment. Each shell execution is independent.
WINDOWS COMPATIBILITY: This implementation provides POSIX shell emulation (mvdan.cc/sh/v3) even on Windows. Commands should use forward slashes (/) as path separators to work correctly on all platforms.
Index ¶
- Constants
- Variables
- func ExitCode(err error) int
- func ExpandValue(ctx context.Context, value string, env []string) (string, error)
- func IsInterrupt(err error) bool
- func Run(ctx context.Context, opts RunOptions) (err error)
- func SeshatEnvMarkers() []string
- type BackgroundShell
- type BackgroundShellInfo
- type BackgroundShellManager
- func (m *BackgroundShellManager) Cleanup() int
- func (m *BackgroundShellManager) Get(id string) (*BackgroundShell, bool)
- func (m *BackgroundShellManager) Kill(id string) error
- func (m *BackgroundShellManager) KillAll(ctx context.Context)
- func (m *BackgroundShellManager) List() []string
- func (m *BackgroundShellManager) Remove(id string) error
- func (m *BackgroundShellManager) Start(ctx context.Context, workingDir string, blockFuncs []BlockFunc, command string, ...) (*BackgroundShell, error)
- type BlockFunc
- type Logger
- type Options
- type RunOptions
- type Shell
- func (s *Shell) Exec(ctx context.Context, command string) (string, string, error)
- func (s *Shell) ExecStream(ctx context.Context, command string, stdout, stderr io.Writer) error
- func (s *Shell) GetEnv() []string
- func (s *Shell) GetWorkingDir() string
- func (s *Shell) SetBlockFuncs(blockFuncs []BlockFunc)
- func (s *Shell) SetEnv(key, value string)
- func (s *Shell) SetWorkingDir(dir string) error
- type ShellType
Constants ¶
const ( // MaxBackgroundJobs is the maximum number of concurrent background jobs allowed MaxBackgroundJobs = 50 // CompletedJobRetentionMinutes is how long to keep completed jobs before auto-cleanup (8 hours) CompletedJobRetentionMinutes = 8 * 60 )
Variables ¶
var NoUnset atomic.Bool
NoUnset controls whether ExpandValue treats unset variables as an error. Default false matches bash: $UNSET expands to "". Store true to re-enable strict mode globally. Not exposed in seshat.json; this is an internal escape hatch in case the lenient default turns out to be the wrong call.
Declared atomic because ExpandValue is invoked concurrently (multiple MCP / LSP / provider loads in flight at startup, hook execution, etc.) and an unsynchronised read/write pair is a data race under the Go memory model regardless of test-level happens-before reasoning. The atomic load on the hot path is negligible against the cost of parsing and running through mvdan.
Functions ¶
func ExpandValue ¶
ExpandValue expands shell-style substitutions in a single config value.
Supported constructs match the bash tool:
- $VAR and ${VAR}.
- ${VAR:-default} / ${VAR:+alt} / ${VAR:?msg}.
- $(command) with full quoting and nesting.
- escaped and quoted strings ("...", '...').
Contract:
- Returns exactly one string. No field splitting, no globbing, no pathname generation. Multi-word command output is preserved verbatim; it is never split into multiple values.
- Nounset is off by default, matching bash: unset variables expand to "". Opt in to strict behaviour per-reference with ${VAR:?msg}, which errors loudly when VAR is unset regardless of the global toggle. Flip the global default via shell.NoUnset.Store(true) as an internal escape hatch.
- Embedded whitespace and newlines in the input are preserved verbatim. Command substitution strips trailing newlines only (POSIX), never leading or internal whitespace.
- Errors wrap the failing inner command's exit code and a bounded prefix of its stderr. Callers that surface the error to users should additionally scrub it for the original template text.
func IsInterrupt ¶
IsInterrupt checks if an error is due to interruption
func Run ¶
func Run(ctx context.Context, opts RunOptions) (err error)
Run parses and executes a shell command using the same mvdan.cc/sh interpreter stack that the stateful Shell type uses (builtins, optional block list, optional Go coreutils). It is safe to call concurrently from multiple goroutines: each call builds its own interp.Runner and shares no state with other callers or with any Shell instance.
Errors returned from the command itself (non-zero exit, context cancellation, parse failures) follow the same conventions as Shell.Exec: inspect with IsInterrupt and ExitCode.
func SeshatEnvMarkers ¶
func SeshatEnvMarkers() []string
SeshatEnvMarkers returns a fresh slice of the environment variables that Seshat unconditionally sets on every shell it spawns — both the interactive bash tool's Shell and the hook runner's Run calls. Tools that want to detect "am I being invoked by an AI agent?" can check any of these. Keeping them in one place guarantees the two shell surfaces cannot drift. A fresh slice is returned on every call so callers may append freely.
Types ¶
type BackgroundShell ¶
type BackgroundShell struct {
ID string
Command string
Description string
Shell *Shell
WorkingDir string
// contains filtered or unexported fields
}
BackgroundShell represents a shell running in the background.
func (*BackgroundShell) GetOutput ¶
func (bs *BackgroundShell) GetOutput() (stdout string, stderr string, done bool, err error)
GetOutput returns the current output of a background shell.
func (*BackgroundShell) IsDone ¶
func (bs *BackgroundShell) IsDone() bool
IsDone checks if the background shell has finished execution.
func (*BackgroundShell) Wait ¶
func (bs *BackgroundShell) Wait()
Wait blocks until the background shell completes.
func (*BackgroundShell) WaitContext ¶
func (bs *BackgroundShell) WaitContext(ctx context.Context) bool
type BackgroundShellInfo ¶
BackgroundShellInfo contains information about a background shell.
type BackgroundShellManager ¶
type BackgroundShellManager struct {
// contains filtered or unexported fields
}
BackgroundShellManager manages background shell instances.
func GetBackgroundShellManager ¶
func GetBackgroundShellManager() *BackgroundShellManager
GetBackgroundShellManager returns the singleton background shell manager.
func (*BackgroundShellManager) Cleanup ¶
func (m *BackgroundShellManager) Cleanup() int
Cleanup removes completed jobs that have been finished for more than the retention period
func (*BackgroundShellManager) Get ¶
func (m *BackgroundShellManager) Get(id string) (*BackgroundShell, bool)
Get retrieves a background shell by ID.
func (*BackgroundShellManager) Kill ¶
func (m *BackgroundShellManager) Kill(id string) error
Kill terminates a background shell by ID.
func (*BackgroundShellManager) KillAll ¶
func (m *BackgroundShellManager) KillAll(ctx context.Context)
KillAll terminates all background shells. The provided context bounds how long the function waits for each shell to exit.
func (*BackgroundShellManager) List ¶
func (m *BackgroundShellManager) List() []string
List returns all background shell IDs.
func (*BackgroundShellManager) Remove ¶
func (m *BackgroundShellManager) Remove(id string) error
Remove removes a background shell from the manager without terminating it. This is useful when a shell has already completed and you just want to clean up tracking.
type BlockFunc ¶
BlockFunc is a function that determines if a command should be blocked
func ArgumentsBlocker ¶
ArgumentsBlocker creates a BlockFunc that blocks specific subcommand
func CommandsBlocker ¶
CommandsBlocker creates a BlockFunc that blocks exact command matches
type RunOptions ¶
type RunOptions struct {
// Command is the shell source to parse and execute.
Command string
// Cwd is the working directory for the execution. Required: callers
// must supply a non-empty value. Run does not silently fall back to
// the Seshat process cwd — hooks and the bash tool have different
// notions of "default" and each owns that decision.
Cwd string
// Env is the full environment visible to the command. The caller is
// responsible for inheriting from os.Environ() if that's desired.
Env []string
// Stdin is the command's standard input. nil is equivalent to an empty
// input stream.
Stdin io.Reader
// Stdout receives the command's standard output. nil discards output.
Stdout io.Writer
// Stderr receives the command's standard error. nil discards output.
Stderr io.Writer
// BlockFuncs is an optional list of deny-list matchers applied before
// each command reaches the exec layer. nil disables blocking entirely.
BlockFuncs []BlockFunc
}
RunOptions configures a single stateless shell execution via Run.
The zero value is not useful; at minimum Command must be set. Stdin, Stdout, and Stderr may be nil (nil readers/writers are treated as empty/discard). BlockFuncs may be nil to disable block-list enforcement — hooks use this to run user-authored commands with the same trust level as a shell alias.
type Shell ¶
type Shell struct {
// contains filtered or unexported fields
}
Shell provides cross-platform shell execution with optional state persistence
func (*Shell) ExecStream ¶
ExecStream executes a command in the shell with streaming output to provided writers
func (*Shell) GetWorkingDir ¶
GetWorkingDir returns the current working directory
func (*Shell) SetBlockFuncs ¶
SetBlockFuncs sets the command block functions for the shell
func (*Shell) SetWorkingDir ¶
SetWorkingDir sets the working directory