snapshot

package
v0.0.2 Latest Latest
Warning

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

Go to latest
Published: Jun 9, 2026 License: MIT Imports: 16 Imported by: 0

Documentation

Overview

Package snapshot owns ~/.lightcode/sessions/<id>/ — meta.json, snapshots/<turn>/, and turns/<turn>/ (message persistence). It backs both the conversation-anchored revert and the sessions foundation: session lifecycle (active / archived / deleted), message persistence, and session resume.

On-disk layout:

~/.lightcode/sessions/<session-id>/
├── meta.json
├── tokens.json              # monotonic, untouched by revert
├── snapshots/
│   └── <turn>/
│       └── <path-hash>/
│           ├── original     # pre-edit bytes, absent if file didn't exist
│           └── meta.json    # {original_path, tool_name, existed}
└── turns/
    └── <turn>/
        ├── messages.jsonl   # one serialized message per line
        └── complete         # empty marker written on turn_end

Turn numbers are integers starting at 1. A turn without a `complete` marker is considered interrupted by a crash and is discarded on session load.

Index

Constants

View Source
const (
	StateActive   = "active"
	StateArchived = "archived"
)

SessionState values stored in meta.json.

Variables

View Source
var ErrNoSession = errors.New("snapshot: no session open")

ErrNoSession is returned by any Store method that needs an active session when none is open.

Functions

func ArchiveSession

func ArchiveSession(sessionsRoot, id string) error

ArchiveSession flips a session's state to archived on disk, same effect as the sweep's active→archived branch. No-op if already archived.

func DeleteSession

func DeleteSession(sessionsRoot, id string) error

DeleteSession removes a session's dir entirely, same effect as the sweep's archived→deleted branch.

func LoadMostRecent

func LoadMostRecent(root, projectPath string) (string, error)

LoadMostRecent returns the most recently active session for projectPath, restricted to state == active. Returns ("", nil) if none.

func Sweep

func Sweep(root string, cfg LifecycleConfig, onDelete func(sessionID string)) (int, int, error)

Sweep walks every session dir and applies state transitions per cfg. Returns (archived, deleted) counts.

func SweepAllProjects

func SweepAllProjects(projectsRoot string, cfg LifecycleConfig, onDelete func(sessionID string)) (int, int, error)

SweepAllProjects runs Sweep over every project's sessions/ dir under projectsRoot. Returns combined counts across all projects.

Types

type CompactionRecord

type CompactionRecord struct {
	Summary            string `json:"summary"`
	BoundaryTurn       int    `json:"boundary_turn"`
	CompactedAt        string `json:"compacted_at"`
	SummarizerModel    string `json:"summarizer_model"`
	SummarizerProvider string `json:"summarizer_provider,omitempty"`
}

CompactionRecord is persisted to compaction.json when context lifecycle management summarizes the conversation.

type LifecycleConfig

type LifecycleConfig struct {
	Enabled                bool
	ArchiveAfterDays       int
	DeleteAfterArchiveDays int
}

LifecycleConfig controls Sweep's archive/delete thresholds. Days are counted in 24-hour units.

type SessionInfo

type SessionInfo struct {
	ID              string `json:"id"`
	CreatedAt       string `json:"createdAt"`
	LastActivity    int64  `json:"lastActivity"`
	State           string `json:"state"`
	ArchivedAt      int64  `json:"archivedAt"`
	ProjectPath     string `json:"projectPath"`
	ParentSessionID string `json:"parentSessionId,omitempty"`
}

SessionInfo is the summary returned by List for the session switcher.

func List

func List(root, projectPath, state string) ([]SessionInfo, error)

List returns sessions under root, filtered to projectPath (empty = no project filter) and state (empty = any state). Sorted by LastActivity descending.

type SessionMeta

type SessionMeta struct {
	ID               string `json:"id"`
	CreatedAt        string `json:"created_at"` // RFC3339
	ProjectPath      string `json:"project_path"`
	ProjectHash      string `json:"project_hash"`
	LightcodeVersion string `json:"lightcode_version"`
	State            string `json:"state"`         // "active" | "archived"
	ArchivedAt       int64  `json:"archived_at"`   // unix seconds, 0 if active
	LastActivity     int64  `json:"last_activity"` // unix seconds of last user message
	Provider         string `json:"provider,omitempty"`
	Model            string `json:"model,omitempty"`
	ParentSessionID  string `json:"parent_session_id,omitempty"`
}

SessionMeta is persisted to the session directory's meta.json. The project_hash lets the session list filter sessions by project without re-resolving paths. state / archived_at / last_activity drive the lifecycle sweep.

type SnapshotMeta

type SnapshotMeta struct {
	OriginalPath  string `json:"original_path"`
	CanonicalPath string `json:"canonical_path,omitempty"`
	Existed       bool   `json:"existed"`
}

SnapshotMeta is written alongside each snapshotted file. OriginalPath is the user-facing path shown in history and affected-file output. CanonicalPath is the hidden restore target for new snapshots. Old metadata without CanonicalPath falls back to OriginalPath. Existed is false when the snapshot represents a file that did not exist before the turn — on revert, that file is deleted.

type Store

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

Store owns one session directory at a time. Its session may be swapped (Close + BeginNewSession / LoadSession) while tool and loop references to the Store remain valid — they call methods on the same pointer, which now transparently refer to whichever session is active.

A Store with no active session rejects Snapshot / AppendMessage / MarkTurnComplete with ErrNoSession. BeginTurn and CurrentTurn return 0 in that state. This supports lazy session creation: a fresh launch opens a Store, and the first user prompt calls BeginNewSession.

func NewForSessionsRoot

func NewForSessionsRoot(sessionsRoot, projectsRoot, projectID string) (*Store, error)

NewForSessionsRoot returns a Store rooted at an explicit sessions directory (typically ~/.lightcode/projects/<pid>/sessions). The projectsRoot + projectID are recorded so TouchActivity can bump the project's last_activity.

func (*Store) Active

func (s *Store) Active() bool

Active reports whether a session is currently open.

func (*Store) AppendMessage

func (s *Store) AppendMessage(turn int, msg []byte) error

AppendMessage appends one serialized message (one JSON object + \n) to turns/<turn>/messages.jsonl. Creates the turn dir if needed.

func (*Store) AttachSessionsRoot

func (s *Store) AttachSessionsRoot(sessionsRoot, projectsRoot, projectID string) error

AttachSessionsRoot swaps the store's sessions root and project bookkeeping. Used for the lazy project-creation path: a Store built with NewEmpty gets its real root once the first session is created. Must not be called while a session is active.

func (*Store) BeginChildSession

func (s *Store) BeginChildSession(projectRoot, parentSessionID string) error

BeginChildSession creates a fresh session linked to a parent session.

func (*Store) BeginNewSession

func (s *Store) BeginNewSession(projectRoot string) error

BeginNewSession creates a fresh session directory, writes meta.json, and makes this Store refer to it. The Store must not already have an active session.

func (*Store) BeginTurn

func (s *Store) BeginTurn() int

BeginTurn scans turn dirs (both snapshots/ and turns/), picks the next integer, creates empty turn dirs on both sides, and stores it as currentTurn. Returns 0 if no session is active.

func (*Store) Close

func (s *Store) Close() (bool, error)

Close detaches the Store from its current session. If the session has no complete turns, the entire session dir is deleted (orphan cleanup for "opened a new session, switched away without using it"). Returns (wasDiscarded, err). A Store with no session is a no-op.

func (*Store) CurrentTurn

func (s *Store) CurrentTurn() int

CurrentTurn returns the last BeginTurn result, 0 if unset.

func (*Store) Dir

func (s *Store) Dir() string

Dir returns the session directory path, or "" if none is open.

func (*Store) DiscardSnapshotEntry

func (s *Store) DiscardSnapshotEntry(turn int, entryID string) error

DiscardSnapshotEntry releases a pre-mutation snapshot user. The entry is removed only if no concurrent user retained it or still depends on it.

func (*Store) ForkInto

func (s *Store) ForkInto(toTurn int) (string, string, error)

ForkInto copies turns 1..toTurn (both snapshots and messages) into a new session directory. The current session is untouched. Returns the path of the new session dir. Caller is responsible for switching to it.

func (*Store) ListTurns

func (s *Store) ListTurns() ([]TurnEntry, error)

ListTurns returns all recorded snapshot turns with their file meta.

func (*Store) LoadCompaction

func (s *Store) LoadCompaction() (*CompactionRecord, error)

LoadCompaction reads the compaction record, or returns nil if none exists.

func (*Store) LoadCompactionForSession

func (s *Store) LoadCompactionForSession(id string) (*CompactionRecord, error)

LoadCompactionForSession reads another session's compaction record without switching the active session.

func (*Store) LoadCompleteTurns

func (s *Store) LoadCompleteTurns() ([]TurnMessages, error)

LoadCompleteTurns returns every complete turn's messages in turn order. Incomplete turns are deleted from disk as a side effect.

func (*Store) LoadCompleteTurnsAfter

func (s *Store) LoadCompleteTurnsAfter(after int) ([]TurnMessages, error)

LoadCompleteTurnsAfter returns complete turns with turn number > after.

func (*Store) LoadCompleteTurnsAfterForSessionReadOnly

func (s *Store) LoadCompleteTurnsAfterForSessionReadOnly(id string, after int) ([]TurnMessages, error)

LoadCompleteTurnsAfterForSessionReadOnly returns another session's complete turns after the boundary without switching the active session or attempting crash recovery.

func (*Store) LoadCompleteTurnsAfterReadOnly

func (s *Store) LoadCompleteTurnsAfterReadOnly(after int) ([]TurnMessages, error)

LoadCompleteTurnsAfterReadOnly returns complete turns after the boundary without attempting crash recovery. It is safe for display reads while a turn is still in progress.

func (*Store) LoadCompleteTurnsForSessionReadOnly

func (s *Store) LoadCompleteTurnsForSessionReadOnly(id string) ([]TurnMessages, error)

LoadCompleteTurnsForSessionReadOnly returns another session's complete turns without switching the active session or attempting crash recovery.

func (*Store) LoadCompleteTurnsReadOnly

func (s *Store) LoadCompleteTurnsReadOnly() ([]TurnMessages, error)

LoadCompleteTurnsReadOnly returns complete turns without attempting crash recovery. It is safe for display reads while a turn is still in progress.

func (*Store) LoadSession

func (s *Store) LoadSession(id string) error

LoadSession attaches this Store to an existing on-disk session. Discards any incomplete turn dirs (crash recovery).

func (*Store) MarkTurnComplete

func (s *Store) MarkTurnComplete(turn int) error

MarkTurnComplete writes the empty `complete` marker in turns/<turn>/.

func (*Store) Meta

func (s *Store) Meta() (SessionMeta, error)

Meta reads the session's meta.json.

func (*Store) ProjectPath

func (s *Store) ProjectPath() string

ProjectPath returns the project path recorded in session meta, or "".

func (*Store) RetainSnapshotEntry

func (s *Store) RetainSnapshotEntry(turn int, entryID string)

RetainSnapshotEntry keeps a snapshot entry once any user starts mutating.

func (*Store) RevertCode

func (s *Store) RevertCode(toTurn int) ([]string, error)

RevertCode restores every file snapshotted in turns > toTurn to its pre-turn state and deletes those snapshot turn dirs. Message history and turn dirs are NOT touched — conversation stays intact.

func (*Store) RevertHistory

func (s *Store) RevertHistory(toTurn int) error

RevertHistory deletes message turn dirs strictly greater than toTurn and updates currentTurn. Files on disk are NOT touched.

func (*Store) Root

func (s *Store) Root() string

Root returns ~/.lightcode/sessions. Always valid.

func (*Store) SaveCompaction

func (s *Store) SaveCompaction(rec CompactionRecord) error

SaveCompaction writes a compaction record to the session directory.

func (*Store) SessionID

func (s *Store) SessionID() string

SessionID returns the session ID or "" if none is open.

func (*Store) SetModel

func (s *Store) SetModel(provider, model string) error

SetModel writes provider + model fields into meta.json.

func (*Store) SetState

func (s *Store) SetState(state string) error

SetState writes state + archived_at fields into meta.json.

func (*Store) Snapshot

func (s *Store) Snapshot(turn int, absPath string) error

Snapshot captures the pre-turn state of absPath. First-write-wins per (turn, path).

func (*Store) SnapshotResolved

func (s *Store) SnapshotResolved(turn int, originalPath, canonicalPath string) error

SnapshotResolved captures canonicalPath while preserving originalPath for UI/history display. First-write-wins per canonical path.

func (*Store) SnapshotResolvedEntry

func (s *Store) SnapshotResolvedEntry(turn int, originalPath, canonicalPath string) (string, bool, error)

SnapshotResolvedEntry is SnapshotResolved plus the concrete entry id and a created flag. Mutation callers must either retain the entry once mutation starts or discard their pre-mutation claim if validation fails first.

func (*Store) TouchActivity

func (s *Store) TouchActivity() error

TouchActivity updates LastActivity in meta.json to now. Called on every user message. Also bumps the owning project's meta.json when the store is project-aware.

type TurnEntry

type TurnEntry struct {
	Turn  int            `json:"turn"`
	Files []SnapshotMeta `json:"files"`
}

TurnEntry describes one snapshot turn for UI display.

type TurnMessages

type TurnMessages struct {
	Turn     int
	Messages [][]byte
}

TurnMessages is one turn's persisted messages, in append order.

Jump to

Keyboard shortcuts

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