Documentation
¶
Index ¶
- Constants
- func CheckpointsEnabled() bool
- func DefaultRoot(env map[string]string) string
- func FormatExecPrompt(prompt string, prepared PreparedExec) string
- func IsResumableKind(kind SessionKind) bool
- func ValidSessionID(sessionID string) bool
- type AppendEventInput
- type CheckpointFile
- type CheckpointPayload
- type ChildInput
- type CompactionOptions
- type CompactionPayload
- type CompactionPlan
- type CreateInput
- type EnsureSpecImplementationInput
- type Event
- type EventRef
- type EventType
- type ExecError
- type ExecMode
- type ForkInput
- type Metadata
- type PrepareExecOptions
- type PreparedExec
- type RecordCompactionInput
- type RecordSpecInput
- type RestoreReport
- type RewindMarker
- type RewindOptions
- type RewindPlan
- type SessionKind
- type SpecStatus
- type Store
- func (store *Store) AppendEvent(sessionID string, input AppendEventInput) (Event, error)
- func (store *Store) AppendEventUnlessExists(sessionID string, input AppendEventInput, exists func([]Event) bool) (Event, bool, error)
- func (store *Store) AppendEvents(sessionID string, inputs []AppendEventInput) ([]Event, error)
- func (store *Store) ApplyRewind(sessionID, workspaceRoot string, targetSeq int) (RestoreReport, error)
- func (store *Store) CaptureToolCheckpoint(sessionID, workspaceRoot, tool string, paths []string) (Event, error)
- func (store *Store) Create(input CreateInput) (Metadata, error)
- func (store *Store) CreateChild(parentSessionID string, input ChildInput) (Metadata, error)
- func (store *Store) EnsureSpecImplementation(input EnsureSpecImplementationInput) (Metadata, []Event, error)
- func (store *Store) FindSpecImplementation(specID string, sourceSessionID string) (*Metadata, error)
- func (store *Store) Fork(parentSessionID string, input ForkInput) (Metadata, error)
- func (store *Store) Get(sessionID string) (*Metadata, error)
- func (store *Store) Latest() (*Metadata, error)
- func (store *Store) LatestResumable() (*Metadata, error)
- func (store *Store) Lineage(sessionID string) ([]Metadata, error)
- func (store *Store) List() ([]Metadata, error)
- func (store *Store) ListChildren(parentSessionID string) ([]Metadata, error)
- func (store *Store) ListResumable() ([]Metadata, error)
- func (store *Store) PlanCompaction(sessionID string, options CompactionOptions) (CompactionPlan, error)
- func (store *Store) PlanRewind(sessionID string, options RewindOptions) (RewindPlan, error)
- func (store *Store) ReadEvents(sessionID string) ([]Event, error)
- func (store *Store) ReadRehydratedEvents(sessionID string) ([]Event, error)
- func (store *Store) ReadReplayEvents(sessionID string) ([]Event, error)
- func (store *Store) RecordCompaction(sessionID string, input RecordCompactionInput) (Event, error)
- func (store *Store) RecordSpec(sessionID string, input RecordSpecInput) (Metadata, Event, error)
- func (store *Store) RestoreToSequence(sessionID, workspaceRoot string, targetSeq int) (RestoreReport, error)
- func (store *Store) SnapshotForCheckpoint(sessionID, workspaceRoot, tool string, paths []string) (CheckpointPayload, bool)
- func (store *Store) Tree(rootSessionID string) (TreeNode, error)
- func (store *Store) TruncateEvents(sessionID string, keepThroughSequence int) error
- func (store *Store) UpdateTitle(sessionID string, title string) (Metadata, error)
- type StoreOptions
- type TreeNode
Constants ¶
const ( MetadataFile = "metadata.json" EventsFile = "events.jsonl" )
const CheckpointsDir = "checkpoints"
CheckpointsDir is the per-session subdirectory holding content-addressed blobs.
Variables ¶
This section is empty.
Functions ¶
func CheckpointsEnabled ¶
func CheckpointsEnabled() bool
CheckpointsEnabled reports whether checkpoint capture is enabled (default on; disabled with ZERO_CHECKPOINTS=off).
func DefaultRoot ¶
func FormatExecPrompt ¶
func FormatExecPrompt(prompt string, prepared PreparedExec) string
func IsResumableKind ¶
func IsResumableKind(kind SessionKind) bool
IsResumableKind reports whether a session kind represents a standalone, user-resumable conversation rather than an agent sub-run. Regular ("") and user fork sessions are resumable; child (specialist/sub-agent) and spec draft/impl sessions are not — each agent task and /spec run creates one, so listing them in the resume picker floods it with non-conversation entries.
func ValidSessionID ¶
Types ¶
type AppendEventInput ¶
type CheckpointFile ¶
type CheckpointFile struct {
Path string `json:"path"`
Blob string `json:"blob,omitempty"` // sha256 of prior content, "" if absent/skipped
Absent bool `json:"absent,omitempty"` // file did not exist before (restore -> delete)
Skipped bool `json:"skipped,omitempty"` // exceeded size cap; not recoverable
Bytes int `json:"bytes,omitempty"`
Mode uint32 `json:"mode,omitempty"` // unix permission bits of the prior file; 0 if unknown (restore preserves existing mode)
}
CheckpointFile records the before-mutation state of one workspace file.
type CheckpointPayload ¶
type CheckpointPayload struct {
Tool string `json:"tool"`
Files []CheckpointFile `json:"files"`
}
CheckpointPayload is the payload of an EventSessionCheckpoint event. It indexes the before-state blobs captured for one mutating tool call.
type ChildInput ¶
type CompactionOptions ¶
type CompactionPayload ¶
type CompactionPayload struct {
Summary string `json:"summary"`
PreserveLast int `json:"preserveLast"`
CompactableCount int `json:"compactableCount"`
PreservedCount int `json:"preservedCount"`
CompactedThroughEventID string `json:"compactedThroughEventId,omitempty"`
CompactedThroughSequence int `json:"compactedThroughSequence,omitempty"`
CompactableEvents []EventRef `json:"compactableEvents,omitempty"`
PreservedEvents []EventRef `json:"preservedEvents,omitempty"`
PromptChars int `json:"promptChars,omitempty"`
Truncated bool `json:"truncated,omitempty"`
}
CompactionPayload is the payload of an EventCompaction event. It records the summary that should replace compacted-away events during replay.
func CompactionPayloadFromPlan ¶
func CompactionPayloadFromPlan(summary string, plan CompactionPlan) (CompactionPayload, error)
type CompactionPlan ¶
type CompactionPlan struct {
SessionID string `json:"sessionId"`
PreserveLast int `json:"preserveLast"`
CompactableCount int `json:"compactableCount"`
PreservedCount int `json:"preservedCount"`
CompactableEvents []EventRef `json:"compactableEvents"`
PreservedEvents []EventRef `json:"preservedEvents"`
SummaryPrompt string `json:"summaryPrompt"`
PromptChars int `json:"promptChars"`
Truncated bool `json:"truncated,omitempty"`
}
type CreateInput ¶
type CreateInput struct {
SessionID string
SessionKind SessionKind
Title string
Cwd string
ModelID string
Provider string
Tag string
Depth int
ParentSessionID string
RootSessionID string
AgentName string
TaskID string
ForkedFromEventID string
ForkedFromSequence int
SpawnedFromEventID string
SpawnedFromSequence int
SpecID string
SpecFilePath string
SpecStatus SpecStatus
SpecDraftModelID string
SpecDraftReasoning string
SpecUserComment string
SpecRejectReason string
SpecSourceSessionID string
SpecImplSessionID string
}
type Event ¶
type Event struct {
ID string `json:"id"`
SessionID string `json:"sessionId"`
Sequence int `json:"sequence"`
Type EventType `json:"type"`
CreatedAt string `json:"createdAt"`
Payload json.RawMessage `json:"payload,omitempty"`
}
func RehydrateEvents ¶
func ReplayEvents ¶
type EventType ¶
type EventType string
const ( EventMessage EventType = "message" EventToolCall EventType = "tool_call" EventPermission EventType = "permission" EventPermissionRequest EventType = "permission_request" EventPermissionDecision EventType = "permission_decision" EventToolResult EventType = "tool_result" EventProviderUsage EventType = "provider_usage" EventUsage EventType = EventProviderUsage EventError EventType = "error" EventSessionCheckpoint EventType = "session_checkpoint" EventSessionRewind EventType = "session_rewind" EventCompaction EventType = "session_compaction" EventSessionFork EventType = "session_fork" EventSessionChild EventType = "session_child" EventSpecialistStart EventType = "specialist_start" EventSpecialistStop EventType = "specialist_stop" EventSpecDraft EventType = "spec_draft" EventSpecApproved EventType = "spec_approved" EventSpecRejected EventType = "spec_rejected" )
type Metadata ¶
type Metadata struct {
SessionID string `json:"sessionId"`
SessionKind SessionKind `json:"sessionKind,omitempty"`
Title string `json:"title,omitempty"`
Cwd string `json:"cwd,omitempty"`
ModelID string `json:"modelId,omitempty"`
Provider string `json:"provider,omitempty"`
Tag string `json:"tag,omitempty"`
Depth int `json:"depth,omitempty"`
ParentSessionID string `json:"parentSessionId,omitempty"`
RootSessionID string `json:"rootSessionId,omitempty"`
AgentName string `json:"agentName,omitempty"`
TaskID string `json:"taskId,omitempty"`
ForkedFromEventID string `json:"forkedFromEventId,omitempty"`
ForkedFromSequence int `json:"forkedFromSequence,omitempty"`
SpawnedFromEventID string `json:"spawnedFromEventId,omitempty"`
SpawnedFromSequence int `json:"spawnedFromSequence,omitempty"`
SpecID string `json:"specId,omitempty"`
SpecFilePath string `json:"specFilePath,omitempty"`
SpecStatus SpecStatus `json:"specStatus,omitempty"`
SpecDraftModelID string `json:"specDraftModelId,omitempty"`
SpecDraftReasoning string `json:"specDraftReasoning,omitempty"`
SpecUserComment string `json:"specUserComment,omitempty"`
SpecRejectReason string `json:"specRejectReason,omitempty"`
SpecSourceSessionID string `json:"specSourceSessionId,omitempty"`
SpecImplSessionID string `json:"specImplSessionId,omitempty"`
CreatedAt string `json:"createdAt"`
UpdatedAt string `json:"updatedAt"`
EventCount int `json:"eventCount"`
LastEventType EventType `json:"lastEventType,omitempty"`
}
type PrepareExecOptions ¶
type PreparedExec ¶
func PrepareExec ¶
func PrepareExec(options PrepareExecOptions) (PreparedExec, error)
type RecordCompactionInput ¶
type RecordCompactionInput struct {
Plan CompactionPlan
Summary string
}
type RecordSpecInput ¶
type RestoreReport ¶
type RestoreReport struct {
TargetSequence int `json:"targetSequence"`
FilesRestored int `json:"filesRestored"`
FilesDeleted int `json:"filesDeleted"`
Skipped []string `json:"skipped,omitempty"` // paths whose before-state was not recoverable
}
RestoreReport summarizes a workspace restore.
type RewindMarker ¶
type RewindMarker struct {
TargetSequence int `json:"targetSequence"`
Report RestoreReport `json:"report"`
}
RewindMarker is the payload of the EventSessionRewind event appended after a rewind.
type RewindOptions ¶
type RewindPlan ¶
type RewindPlan struct {
SessionID string `json:"sessionId"`
TargetSequence int `json:"targetSequence"`
TargetEventID string `json:"targetEventId"`
KeepTarget bool `json:"keepTarget"`
KeptCount int `json:"keptCount"`
DroppedCount int `json:"droppedCount"`
LastKeptEventID string `json:"lastKeptEventId,omitempty"`
KeptEvents []EventRef `json:"keptEvents"`
DroppedEvents []EventRef `json:"droppedEvents"`
}
type SessionKind ¶
type SessionKind string
const ( SessionKindFork SessionKind = "fork" SessionKindChild SessionKind = "child" SessionKindSpecDraft SessionKind = "spec-draft" SessionKindSpecImpl SessionKind = "spec-impl" )
type SpecStatus ¶
type SpecStatus string
const ( SpecStatusDraft SpecStatus = "draft" SpecStatusApproved SpecStatus = "approved" SpecStatusRejected SpecStatus = "rejected" )
type Store ¶
type Store struct {
RootDir string
// contains filtered or unexported fields
}
func NewStore ¶
func NewStore(options StoreOptions) *Store
func (*Store) AppendEvent ¶
func (store *Store) AppendEvent(sessionID string, input AppendEventInput) (Event, error)
func (*Store) AppendEventUnlessExists ¶
func (store *Store) AppendEventUnlessExists(sessionID string, input AppendEventInput, exists func([]Event) bool) (Event, bool, error)
AppendEventUnlessExists appends input only when exists(currentEvents) is false, performing the existence check and the append atomically under the session lock (in-process mutex + cross-process file lock). It is the safe primitive for "record once" accounting: a plain ReadEvents-then-AppendEvent has a check-then-act race where two callers — even in separate processes — both see the event absent and each append a duplicate. Returns appended=false when the predicate already matched. A nil predicate always appends.
func (*Store) AppendEvents ¶ added in v0.2.0
func (store *Store) AppendEvents(sessionID string, inputs []AppendEventInput) ([]Event, error)
AppendEvents appends a batch of events atomically under one session lock and durability pass. The returned events have contiguous sequences in input order. An empty batch is a no-op and does not rewrite metadata.
func (*Store) ApplyRewind ¶
func (store *Store) ApplyRewind(sessionID, workspaceRoot string, targetSeq int) (RestoreReport, error)
ApplyRewind performs a full safe rewind: restore workspace files to targetSeq, truncate the event log, prune now-orphaned blobs, and append an EventSessionRewind marker. Returns the restore report.
func (*Store) CaptureToolCheckpoint ¶
func (store *Store) CaptureToolCheckpoint(sessionID, workspaceRoot, tool string, paths []string) (Event, error)
CaptureToolCheckpoint snapshots the current (before-mutation) content of each path and records an EventSessionCheckpoint indexing the blobs. Capture is best-effort: an unreadable file is recorded as skipped rather than failing the caller. Returns the appended event (or a zero Event if there was nothing to do).
func (*Store) CreateChild ¶
func (store *Store) CreateChild(parentSessionID string, input ChildInput) (Metadata, error)
func (*Store) EnsureSpecImplementation ¶
func (store *Store) EnsureSpecImplementation(input EnsureSpecImplementationInput) (Metadata, []Event, error)
func (*Store) FindSpecImplementation ¶
func (*Store) LatestResumable ¶
LatestResumable returns the most-recently-updated resumable session, or nil when none exist. Used by `/resume latest` so it lands on a real conversation instead of the newest child/spec sub-run.
func (*Store) ListChildren ¶
func (*Store) ListResumable ¶
ListResumable returns only the sessions a user can resume as standalone conversations (see IsResumableKind), newest-first like List.
func (*Store) PlanCompaction ¶
func (store *Store) PlanCompaction(sessionID string, options CompactionOptions) (CompactionPlan, error)
func (*Store) PlanRewind ¶
func (store *Store) PlanRewind(sessionID string, options RewindOptions) (RewindPlan, error)
func (*Store) ReadRehydratedEvents ¶
func (*Store) ReadReplayEvents ¶
func (*Store) RecordCompaction ¶
func (store *Store) RecordCompaction(sessionID string, input RecordCompactionInput) (Event, error)
func (*Store) RecordSpec ¶
func (*Store) RestoreToSequence ¶
func (store *Store) RestoreToSequence(sessionID, workspaceRoot string, targetSeq int) (RestoreReport, error)
RestoreToSequence reverts workspace files to their state at targetSeq by applying the before-snapshots of every checkpoint after the target, newest-first (so the snapshot closest to the target wins). It does not modify the event log.
func (*Store) SnapshotForCheckpoint ¶
func (store *Store) SnapshotForCheckpoint(sessionID, workspaceRoot, tool string, paths []string) (CheckpointPayload, bool)
SnapshotForCheckpoint reads and stores the before-mutation blobs for paths and returns the checkpoint payload WITHOUT appending an event.
CONTRACT: the returned payload references blobs that are ORPHAN-VULNERABLE — a concurrent pruneOrphanBlobs/ApplyRewind can delete them — until the caller appends an EventSessionCheckpoint carrying this payload. The caller therefore MUST record that event promptly, including on cancellation paths. Prefer CaptureToolCheckpoint, which writes the blobs AND appends the event atomically under one session lock; use SnapshotForCheckpoint only when the event must be batched IN ORDER with other session events (the TUI captures before each mutating tool, batches the checkpoint with the run's other events to preserve recorded ordering, and flushes them at end-of-run and on cancel).
Returns ok=false when there is nothing to record (disabled, no paths, or no capturable files).
func (*Store) TruncateEvents ¶
TruncateEvents atomically rewrites events.jsonl keeping only events with Sequence <= keepThroughSequence, and updates metadata EventCount.
func (*Store) UpdateTitle ¶
UpdateTitle replaces a session's Title and returns the updated metadata. It is serialized under the same per-session lock as AppendEvent and re-reads the latest metadata under that lock before rewriting, so a concurrent append can't clobber the new title (nor the title clobber a concurrent append's event count/timestamp). UpdatedAt is deliberately left untouched: a retitle is not activity, so it must not reorder the session in the resumable list. A blank title is rejected so a failed model generation can never erase a useful first-message title, and an unchanged title is a no-op (no rewrite/fsync).