automate

package
v0.17.13 Latest Latest
Warning

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

Go to latest
Published: Jul 30, 2026 License: MIT Imports: 13 Imported by: 0

Documentation

Overview

Package automate provides shared workflow discovery and validation for the automate/ feature used by both the CLI (cmd/automate.go) and the agent tool layer (pkg/agent/tool_handlers_automate.go).

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Dir

func Dir() string

Dir returns the default automate directory path (cwd + "/automate").

CAUTION: in daemon mode (SPROUT_SERVICE=1), os.Getwd() returns the daemon root, not the active workspace. Tool handlers in the agent must use DirIn with the workspace root from the active Agent (a.GetWorkspaceRoot()) or context (pkg/filesystem.WorkspaceRootFromContext), not Dir(). See SP-119 for the workspace-aware flow.

func DirIn added in v0.17.2

func DirIn(workspaceDir string) string

DirIn returns the automate directory inside the given workspace directory. Returns the CWD-based Dir() when workspaceDir is empty (or whitespace-only), preserving CLI behavior where the user's shell CWD IS the workspace root.

This is the workspace-aware counterpart to Dir(). Use DirIn from any code that knows the active workspace (e.g., agent tools running inside a daemon where os.Getwd() returns the daemon root, not the user's workspace).

func ExtractDescription

func ExtractDescription(path string) (string, error)

ExtractDescription reads a workflow JSON file and returns its description field.

func GetAutomateSessionDir added in v0.16.4

func GetAutomateSessionDir(baseDir string) (string, error)

GetAutomateSessionDir returns the .sprout/automate/ directory path. It resolves the sprout directory relative to the given base (typically project root). Creates the directory if it doesn't exist.

func IsNotExists

func IsNotExists(err error) bool

IsNotExists returns true if the error indicates a missing file or directory.

func IsProcessAlive added in v0.16.4

func IsProcessAlive(pid int) bool

IsProcessAlive (Unix) — see pidalive_windows.go for the rationale and SP-112-3 for the deduplication.

func IsValidFilename

func IsValidFilename(name string) bool

IsValidFilename checks if a filename is safe for use as a workflow filename. Only allows alphanumeric characters, dots, underscores, and hyphens, followed by .json. Prevents shell injection via filenames.

func RemoveSessionFile added in v0.16.4

func RemoveSessionFile(sproutDir string, sessionID string) error

RemoveSessionFile removes the PID file for a session.

func ResolvePath

func ResolvePath(dir string, name string) (string, error)

ResolvePath finds a workflow file by name, with or without .json extension, and verifies the resolved path stays under the given directory to prevent path traversal attacks.

func StopProcess added in v0.16.4

func StopProcess(pid int) (bool, error)

StopProcess escalates signals to gracefully (then forcefully) stop a process. It sends SIGINT, waits 10s, then SIGTERM, waits 5s, then SIGKILL, waits 2s. Returns true if the process is confirmed dead after escalation.

func SweepStaleSessions added in v0.16.4

func SweepStaleSessions(sproutDir string) (int, error)

SweepStaleSessions removes session files whose tracked process is no longer alive. It returns the number of removed entries. Errors from listing or reading the session directory are returned; errors from individual file removals are silently ignored to avoid failing the sweep for one bad entry.

func VerifyProcessStartedBefore added in v0.16.18

func VerifyProcessStartedBefore(pid int, startedAt time.Time) bool

VerifyProcessStartedBefore returns true if the process at the given PID is confirmed to have started before the cutoff time, providing protection against PID reuse. The caller should record the session's start time and pass it here before signaling.

Returns false when the process at this PID started after the cutoff (indicating the original process died and the OS recycled the PID). Returns true when the process is not alive (nothing to signal) or on platforms where the check is unavailable (fail-open).

func WriteSessionFile added in v0.16.4

func WriteSessionFile(sproutDir string, sessionID string, info *AutomateSessionInfo) error

WriteSessionFile writes a session info JSON to .sprout/automate/<sessionID>.json. Creates the directory if needed.

Types

type AllowedPathSummary added in v0.17.7

type AllowedPathSummary struct {
	Path   string `json:"path"`
	Mode   string `json:"mode"`
	Reason string `json:"reason,omitempty"`
}

AllowedPathSummary is the display-only mirror of workflow.AllowedPath. It deliberately does NOT carry a Validate method — the parser runs workflow.AllowedPath.Validate() once during Summarize, so the summary only contains entries that already passed validation.

type AutomateSessionInfo added in v0.16.4

type AutomateSessionInfo struct {
	Workflow       string    `json:"workflow"`
	PID            int       `json:"pid"`
	StartedAt      time.Time `json:"started_at"`
	OutputFilePath string    `json:"output_file_path,omitempty"`
	BudgetUSD      *float64  `json:"budget_usd,omitempty"`
	Kind           string    `json:"kind"` // always "automate"
}

AutomateSessionInfo is the schema for .sprout/automate/<session_id>.json PID files.

func ListSessionFiles added in v0.16.4

func ListSessionFiles(sproutDir string) ([]AutomateSessionInfo, error)

ListSessionFiles reads all session files in .sprout/automate/ and returns them.

func ReadSessionFile added in v0.16.4

func ReadSessionFile(sproutDir string, sessionID string) (*AutomateSessionInfo, error)

ReadSessionFile reads and parses a single session file.

type BudgetSummary added in v0.16.4

type BudgetSummary struct {
	USD    float64   `json:"usd"`
	WarnAt []float64 `json:"warn_at,omitempty"`
}

BudgetSummary mirrors the cmd-level budget config in a package that has no cmd dependency, so the overview renderer can display it.

type Entry

type Entry struct {
	Filename    string `json:"name"`
	FilePath    string
	Description string `json:"description,omitempty"`
}

Entry represents a discovered workflow file with its metadata.

func Discover

func Discover(dir string) ([]Entry, error)

Discover scans the given directory for valid workflow JSON files.

type InitialSummary added in v0.16.4

type InitialSummary struct {
	Persona           string                    `json:"persona,omitempty"`
	Provider          string                    `json:"provider,omitempty"`
	Model             string                    `json:"model,omitempty"`
	MaxIterations     int                       `json:"max_iterations"`
	RiskProfile       string                    `json:"risk_profile,omitempty"`
	HasPrompt         bool                      `json:"has_prompt"`
	SubagentOverrides []SubagentOverrideSummary `json:"subagent_overrides,omitempty"`
	AllowedPaths      []AllowedPathSummary      `json:"allowed_paths,omitempty"`
}

InitialSummary describes the initial run.

type StepSummary added in v0.16.4

type StepSummary struct {
	Name           string               `json:"name,omitempty"`
	Kind           string               `json:"kind"`
	Persona        string               `json:"persona,omitempty"`
	Provider       string               `json:"provider,omitempty"`
	Model          string               `json:"model,omitempty"`
	When           string               `json:"when,omitempty"`
	CommandPreview string               `json:"command_preview,omitempty"`
	AllowedPaths   []AllowedPathSummary `json:"allowed_paths,omitempty"`
}

StepSummary describes a single workflow step.

Kind is one of "agent" (LLM inference) or "shell" (raw command). For shell steps, CommandPreview holds a single-line excerpt of the command for display.

type SubagentOverrideSummary added in v0.16.4

type SubagentOverrideSummary struct {
	Persona  string `json:"persona"`
	Provider string `json:"provider,omitempty"`
	Model    string `json:"model,omitempty"`
}

SubagentOverrideSummary describes one entry of subagent_overrides for display.

type Summary added in v0.16.4

type Summary struct {
	Description     string          `json:"description,omitempty"`
	ContinueOnError bool            `json:"continue_on_error,omitempty"`
	NoWebUI         bool            `json:"no_web_ui,omitempty"`
	Initial         *InitialSummary `json:"initial,omitempty"`
	Steps           []StepSummary   `json:"steps,omitempty"`
	Budget          *BudgetSummary  `json:"budget,omitempty"`
	// RequiresApproval reports whether the run_automate tool path should
	// prompt the user before launching this workflow. nil means the field
	// was unset in JSON (defaults to true). Explicit false marks the
	// workflow as agent-runnable without user confirmation. Serialized
	// as `null` when nil — the field is intentionally NOT omitempty so
	// the WebUI can distinguish "unset (defaults to required)" from
	// "absent (treated as not_required)".
	RequiresApproval *bool `json:"requires_approval"`
	// SubagentTimeoutSeconds overrides the per-run_subagent tool timeout
	// (default 1800 = 30 minutes). nil means use the default. Same nil-
	// semantics as RequiresApproval — serialized as `null` when unset.
	SubagentTimeoutSeconds *int `json:"subagent_timeout_seconds"`
	// AllowedPaths is the display-only view of the workflow's
	// declared allowed_paths entries. Populated by Summarize after
	// the same Validate() that the loader runs, so a malformed entry
	// surfaces as a parse error rather than silently dropping the
	// whole field. Entries are sorted by path for stable display.
	AllowedPaths []AllowedPathSummary `json:"allowed_paths,omitempty"`
	// Warnings collects advisory messages produced while building the
	// summary — currently the system-prefix warning when an
	// allowed_path falls under /etc, /usr, /var, etc. The CLI and
	// WebUI render these alongside the allowed_paths block so the
	// user sees the "this workflow touches platform infrastructure"
	// heads-up even when the path itself is well-formed.
	Warnings []string `json:"warnings,omitempty"`
}

Summary describes the structure of a workflow file at a glance. It is produced by Summarize and used by the CLI to render a human-readable overview before kicking off the workflow. JSON tags use snake_case to match the rest of the WebUI API surface; nil pointers are serialized as `null` (no omitempty) so `requires_approval` and `subagent_timeout_seconds` are always visible to the frontend — the original 3-state semantics (unset = default, true, false) must round-trip through the wire without collapsing to "absent."

func Summarize added in v0.16.4

func Summarize(path string) (*Summary, error)

Summarize parses a workflow file and returns its high-level structure. Fields the JSON does not specify are left at their zero value.

func (*Summary) IsApprovalRequired added in v0.16.4

func (s *Summary) IsApprovalRequired() bool

IsApprovalRequired returns true unless the workflow JSON explicitly declared requires_approval: false. Used by the agent tool path to decide whether to surface the intent-confirmation prompt.

Jump to

Keyboard shortcuts

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