Documentation
¶
Index ¶
- Constants
- func ActiveDir(workDir string) string
- func AppendProviderCall(workDir string, row ProviderCallRow) (int64, error)
- func AttemptToken(t *pm.Task) string
- func ClearTaskKill(workDir string, taskID int) error
- func DBPath(workDir string) string
- func LogEvent(workDir string, row EventRow)
- func LogEventDetails(workDir string, row EventRow, v any)
- func RequestTaskKill(workDir string, taskID int, targetStatus, requestedBy, attempt string) error
- func StateDBPath(workdir string) string
- func StatePath(workdir string) string
- type EventRow
- type EventType
- type KillRequest
- type ProjectState
- func (s *ProjectState) AddStep(result StepResult)
- func (s *ProjectState) LastNSteps(n int) []StepResult
- func (s *ProjectState) LiveDefaultMaxMinutes() int
- func (s *ProjectState) LiveEffort() string
- func (s *ProjectState) LiveMaxParallel() int
- func (s *ProjectState) RequireTask(id int) (*pm.Task, error)
- func (s *ProjectState) Save() error
- func (s *ProjectState) SaveDirect() error
- func (s *ProjectState) SyncFromDisk()
- type ProviderCallRow
- type StepResult
Constants ¶
const ( EventSessionStarted = statedb.EventSessionStarted EventSessionPaused = statedb.EventSessionPaused EventSessionFailed = statedb.EventSessionFailed EventPlanComplete = statedb.EventPlanComplete EventTaskStarted = statedb.EventTaskStarted EventTaskDone = statedb.EventTaskDone EventTaskFailed = statedb.EventTaskFailed EventTaskSkipped = statedb.EventTaskSkipped EventTaskHeal = statedb.EventTaskHeal EventTaskKilled = statedb.EventTaskKilled EventTaskAdded = statedb.EventTaskAdded EventTaskAddedExternal = statedb.EventTaskAddedExternal EventTaskDeleted = statedb.EventTaskDeleted EventTaskStatusChange = statedb.EventTaskStatusChange EventTaskBackground = statedb.EventTaskBackground EventTaskAborted = statedb.EventTaskAborted EventEvolveRoundStart = statedb.EventEvolveRoundStart EventEvolveDiscovered = statedb.EventEvolveDiscovered EventEvolveNoOp = statedb.EventEvolveNoOp )
Re-exported event-type constants. Keep this list in sync with pkg/statedb/events.go.
const NoStep = statedb.NoStep
NoStep is the EventRow.Step value for events not bound to any step. Steps are 0-based, so 0 is a real step number — callers must set Step to NoStep explicitly when an event has no associated step.
Variables ¶
This section is empty.
Functions ¶
func ActiveDir ¶
ActiveDir resolves the effective working directory for state operations. If a session is active (recorded in .cloop/active_session), it returns the session's isolated directory; otherwise it returns workDir unchanged.
func AppendProviderCall ¶
func AppendProviderCall(workDir string, row ProviderCallRow) (int64, error)
AppendProviderCall persists one provider-call audit row to the project's state.db. Returns the assigned id on success. Returns (0, nil) when no project exists at workDir (so observability code can fan out to every project without bothering to check first).
func AttemptToken ¶
AttemptToken renders a task's StartedAt as the attempt identifier used to scope kill requests. Returns "" for a task that has never been started, which the poller treats as naming no live execution.
Both sides of the comparison go through this function so the two never drift on formatting; the poller additionally compares parsed instants so a row written by a differently-formatting client still matches.
func ClearTaskKill ¶
ClearTaskKill removes the kill row for taskID. Idempotent.
func DBPath ¶
DBPath returns the path to the state.db for the given workdir, accounting for active session directories. Other packages (e.g. pkg/eventlog) call this so they don't need to duplicate the active-session resolution logic.
func LogEvent ¶
LogEvent appends one row to the project's event journal. Best-effort: any persistence error is reported to stderr and otherwise swallowed so that observability never blocks the orchestrator's work.
Pass workDir as the project root (or a session dir); it is resolved through the same effectiveDBPath the rest of the package uses. The Timestamp field of row will be set to time.Now() if zero. Events without an associated step must set row.Step to NoStep — steps are 0-based, so 0 is a real step number.
func LogEventDetails ¶
LogEventDetails serialises v as the row's Details JSON before recording. v may be nil (no details). Marshal failures fall back to recording without details rather than dropping the event entirely.
func RequestTaskKill ¶
RequestTaskKill records a manual-abort request for taskID. The orchestrator's fast-tick poller picks this up and fires the task's registered cancel; once the worker exits, target_status is re-applied so the operator's choice wins over the worker's "canceled → failed" handling.
attempt names the execution being aborted — the RFC3339Nano started_at the caller observed on the task, via AttemptToken. Requests are scoped to that attempt so one filed against an execution that has since ended cannot cancel a later attempt of the same task (Task 20203).
Returns nil on success or when the project DB does not exist (a kill request against a project with no orchestrator running is benign — there's nothing to cancel).
func StateDBPath ¶
StateDBPath returns the SQLite database path for the given workdir. It does NOT resolve the active session; use Load for that.
Types ¶
type EventRow ¶
EventRow is re-exported for callers that don't want to import statedb directly (the orchestrator uses pkg/state already).
type KillRequest ¶
type KillRequest = statedb.KillRequest
KillRequest is re-exported from statedb so callers don't have to import the lower layer just to read the requestor / target_status.
func LookupTaskKill ¶
func LookupTaskKill(workDir string, taskID int) (KillRequest, bool, error)
LookupTaskKill returns the pending kill row for taskID. Used by the orchestrator after a worker exits to recover the operator's chosen target_status.
func PendingKills ¶
func PendingKills(workDir string) ([]KillRequest, error)
PendingKills returns all currently-pending abort requests for the project. Returns (nil, nil) when the project has no DB yet.
type ProjectState ¶
type ProjectState struct {
Goal string `json:"goal"`
WorkDir string `json:"workdir"`
MaxSteps int `json:"max_steps"`
CurrentStep int `json:"current_step"`
Status string `json:"status"` // running, complete, failed, paused, evolving
Steps []StepResult `json:"steps"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
Model string `json:"model,omitempty"`
Instructions string `json:"instructions,omitempty"`
AutoEvolve bool `json:"auto_evolve"`
EvolveStep int `json:"evolve_step"`
// Provider settings
Provider string `json:"provider,omitempty"`
// Effort is the persisted model reasoning-effort level (low, medium,
// high, xhigh, max; empty = provider default). Set at init time or from
// the Web UI's Provider & Model picker; honored by providers that
// support it (currently claudecode via the claude CLI --effort flag).
Effort string `json:"effort,omitempty"`
// Product manager mode
PMMode bool `json:"pm_mode,omitempty"`
Plan *pm.Plan `json:"plan,omitempty"`
Milestones []*milestone.Milestone `json:"milestones,omitempty"`
// Cumulative token usage across all steps
TotalInputTokens int `json:"total_input_tokens,omitempty"`
TotalOutputTokens int `json:"total_output_tokens,omitempty"`
// DefaultMaxMinutes is the project-level per-task execution time budget.
DefaultMaxMinutes int `json:"default_max_minutes,omitempty"`
// SkipClarify persists the --skip-clarify flag.
SkipClarify bool `json:"skip_clarify,omitempty"`
// InnovateMode persists the --innovate flag from the most recent run.
InnovateMode bool `json:"innovate_mode,omitempty"`
// Parallel persists the --parallel flag (PM mode runs dependency-ready
// tasks concurrently in each round). Read by cmd/run as a default.
Parallel bool `json:"parallel,omitempty"`
// MaxParallel caps the worker pool when Parallel is true. 0 = unlimited.
MaxParallel int `json:"max_parallel,omitempty"`
// WorktreeParallel persists the --worktree-parallel flag. When true and the
// project is a git repo, parallel-mode tasks run inside dedicated git
// worktrees at .cloop/worktrees/task-<id>/ and their branches are drained
// back into the base branch through a serialized merge queue.
WorktreeParallel bool `json:"worktree_parallel,omitempty"`
// PlanOnly persists the --plan-only flag (PM mode: decompose goal into
// tasks but do not execute them).
PlanOnly bool `json:"plan_only,omitempty"`
// RetryFailed persists the --retry-failed flag (reset failed tasks to
// pending before running).
RetryFailed bool `json:"retry_failed,omitempty"`
// DryRun persists the --dry-run flag (show prompts without invoking the
// provider).
DryRun bool `json:"dry_run,omitempty"`
// StepCount is the total number of step rows in the database. Always
// populated: Load mirrors len(Steps); LoadLite fills it from a cheap
// SELECT COUNT(*) while Steps is nil. Read it instead of len(Steps)
// when working with lite-loaded state (Task 20125).
StepCount int `json:"-"`
// LastStepTime is the timestamp of the most recent step row. Same
// semantics as StepCount: set by both Load (last element) and LoadLite
// (cheap lookup of the newest step row); used by health probes to detect stalled
// runs without scanning the Steps slice.
LastStepTime time.Time `json:"-"`
}
func Init ¶
func Init(workdir, goal string, maxSteps int) (*ProjectState, error)
Init creates a new project state and persists it.
func Load ¶
func Load(workdir string) (*ProjectState, error)
Load reads project state, resolving the active session first. Auto-migrates from state.json on first run.
func LoadFromDir ¶
func LoadFromDir(dir string) (*ProjectState, error)
LoadFromDir loads state directly from a specific directory (e.g. a session directory) without going through the active-session resolution in Load. dir may be a session dir (state.db lives flat inside) or a regular workDir (.cloop/state.db). Returns nil, nil if no state exists.
func LoadLite ¶
func LoadLite(workdir string) (*ProjectState, error)
LoadLite is like Load but skips reading the per-step rows. The returned ProjectState has Steps == nil while StepCount and LastStepTime are populated from cheap SQL aggregates (Task 20125). Use it from handlers that render counts or check last-activity but never touch step Output — for a 5k-step project this saves ~1.5 MiB of allocation per call.
func (*ProjectState) AddStep ¶
func (s *ProjectState) AddStep(result StepResult)
func (*ProjectState) LastNSteps ¶
func (s *ProjectState) LastNSteps(n int) []StepResult
func (*ProjectState) LiveDefaultMaxMinutes ¶
func (s *ProjectState) LiveDefaultMaxMinutes() int
LiveDefaultMaxMinutes returns DefaultMaxMinutes under the live-toggle lock.
func (*ProjectState) LiveEffort ¶
func (s *ProjectState) LiveEffort() string
LiveEffort returns Effort under the live-toggle lock. Use from goroutines that can run concurrently with Save/SyncFromDisk (parallel workers, pollers).
func (*ProjectState) LiveMaxParallel ¶
func (s *ProjectState) LiveMaxParallel() int
LiveMaxParallel returns MaxParallel under the live-toggle lock.
func (*ProjectState) RequireTask ¶
func (s *ProjectState) RequireTask(id int) (*pm.Task, error)
RequireTask returns the task with the given ID, wrapping statedb.ErrTaskNotFound when the plan is missing or no task matches. HTTP handlers should use errors.Is(err, statedb.ErrTaskNotFound) and statedb.HTTPStatus(err) to map to the correct status code.
func (*ProjectState) Save ¶
func (s *ProjectState) Save() error
Save writes the project state to the SQLite store, first merging any tasks that were added externally while this state object was in memory. This is the standard save path used by the orchestrator. UI handlers that intentionally mutate (add/edit/delete) tasks should use SaveDirect to avoid the merge re-adding deleted tasks.
func (*ProjectState) SaveDirect ¶
func (s *ProjectState) SaveDirect() error
SaveDirect writes the project state to the SQLite store WITHOUT merging externally-added tasks. Use this for intentional UI mutations (add, edit, delete tasks) where the caller has already loaded the latest state and does not want deleted tasks re-added from disk.
func (*ProjectState) SyncFromDisk ¶
func (s *ProjectState) SyncFromDisk()
SyncFromDisk re-reads the on-disk state and merges externally-added tasks.
type ProviderCallRow ¶
type ProviderCallRow = statedb.ProviderCallRow
ProviderCallRow is re-exported so callers don't have to import statedb directly.
func ListProviderCalls ¶
func ListProviderCalls(workDir string, offset, limit, taskID int, providerFilter string) ([]ProviderCallRow, int, error)
ListProviderCalls returns up to limit rows from the audit log starting at offset, latest-first. Returns (nil, 0, nil) for projects that have no state.db yet.
func LoadProviderCall ¶
func LoadProviderCall(workDir string, id int64) (*ProviderCallRow, error)
LoadProviderCall returns the full row for a single audit-log id.