Help us shape the future of Go! Take the 2026 Go Developer Survey

store

package
v0.33.0 Latest Latest
Warning

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

Go to latest
Published: Sep 18, 2026 License: Apache-2.0 Imports: 15 Imported by: 0

Documentation

Overview

Package store persists clarity watch's session history (projects, worktrees, sessions, commits, snapshots) to a per-repo SQLite database, so it survives a process restart or crash. See the "ER: Persisted Session History" and "Session Lifecycle" design artifacts (Strata, Clarity project) for the schema and its rationale.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AppendSnapshot

func AppendSnapshot(db *sql.DB, sessionID int64, position int, source, format, kind string, createdAt time.Time) error

AppendSnapshot writes one snapshot into sessionID's snapshot stream, called as each snapshot is produced (not batched) so a crash or kill loses at most the single write in flight, never the whole session.

func CloseRun

func CloseRun(db *sql.DB, runID int64) error

CloseRun sets ended_at on runID, marking it as having shut down cleanly. A run whose ended_at is still NULL crashed or was killed rather than exiting through its own defer chain — the same "NULL means unclean exit" convention CloseSessionStale relies on for a session left open.

func CloseSessionCommitted

func CloseSessionCommitted(db *sql.DB, sessionID int64, commits []CommitRecord) error

CloseSessionCommitted closes sessionID as committed: sets closed_at and closed_reason='committed', and records commits. Requires at least one commit — a session closed by a real commit always has one, per the design; a session with none belongs to CloseSessionDiscarded, CloseSessionWorktreeRemoved, or CloseSessionStale instead.

func CloseSessionDiscarded

func CloseSessionDiscarded(db *sql.DB, sessionID int64) error

CloseSessionDiscarded closes sessionID as discarded: the working tree returned to a clean state with no commit (stash, checkout -- ., reset with no reachable new commits) while clarity watch was actively watching. No commits are recorded.

func CloseSessionStale

func CloseSessionStale(db *sql.DB, sessionID int64) error

CloseSessionStale closes sessionID as stale: it was left open by a process that exited without closing it (a crash, a kill, a machine restart — clarity watch doesn't know which), and at the next relaunch its last recorded snapshot no longer matched the freshly rebuilt graph, so it was closed rather than resumed. No commits are recorded. Called by OpenOrResumeSession — not normally called directly.

func CloseSessionWorktreeRemoved

func CloseSessionWorktreeRemoved(db *sql.DB, sessionID int64) error

CloseSessionWorktreeRemoved closes sessionID as worktree_removed: the underlying git worktree was physically removed while the session still had uncommitted snapshots. No commits are recorded.

func EnsureProject

func EnsureProject(db *sql.DB, repoOrigin string) (string, error)

EnsureProject returns the id of the projects row for repoOrigin, creating one (with a fresh UUID) if it doesn't exist yet. Idempotent: calling it again for the same repoOrigin always returns the same id, never inserts a duplicate row — including under a race, since repo_origin is UNIQUE and a conflicting insert falls back to re-reading the winning row.

func LockPathFor

func LockPathFor(worktreePath string) (string, error)

LockPathFor resolves the path to the repo-wide advisory lock file that gates a single clarity watch process per repository (see CLR-91). It sits beside the session-history database, sharing the same directory and the same one-per-clone guarantee.

func MarkWorktreeDisposed

func MarkWorktreeDisposed(db *sql.DB, id string) error

MarkWorktreeDisposed sets disposed_at on worktree id: its underlying git worktree was physically removed. The row is never deleted.

func MarkWorktreeHidden

func MarkWorktreeHidden(db *sql.DB, id string) error

MarkWorktreeHidden sets hidden_at on worktree id: the user closed its already-disposed tab. The row is never deleted.

func Migrate

func Migrate(db *sql.DB) error

Migrate applies every pending migration embedded in this package to db. Applying it twice is a safe no-op: migrate.ErrNoChange is swallowed, not treated as a failure. A migration that fails partway is left by golang-migrate's sqlite3 driver marked "dirty" rather than silently applied — Migrate reports that as an error rather than pretending the schema is usable.

func Open

func Open(path string) (*sql.DB, error)

Open opens the SQLite database at path with the pragmas this package relies on (foreign key enforcement, since the schema depends on it) and runs any pending migrations. Callers should PathFor(worktreePath) to get path.

The connection pool is limited to one connection: SQLite serializes writers anyway, and Migrate needs a guarantee that the connection it toggles PRAGMA foreign_keys on is the same one golang-migrate later runs its transaction on (see migrate.go).

func OpenOrResumeSession

func OpenOrResumeSession(db *sql.DB, worktreeID, currentSource string, runID int64) (sessionID int64, nextPosition int, matched bool, err error)

OpenOrResumeSession is the entry point for the first snapshot of a worktree's lifetime in this process — the restart-hydration decision. runID is this process's watch_runs row, used only if a fresh session ends up being opened (see OpenSession) — a resumed session keeps the run_id of the run that originally opened it, not runID.

If no session was left open for worktreeID, this is exactly OpenSession: a fresh session opens, matched is false, nextPosition is 0.

If a session WAS left open (a prior process run never got to close it — crash, kill, machine restart), it's a resume candidate. currentSource is the freshly rebuilt graph for this worktree, always available for free since attaching to a worktree already rebuilds it to seed the tab. If it matches that session's last recorded snapshot exactly, the gap was invisible to what we actually track, so the session is resumed: matched is true, telling the caller currentSource is already recorded and must not be written again, and nextPosition is where the next *new* snapshot should go. If it doesn't match, the orphaned session is closed via CloseSessionStale (never resumed, never silently left open) and a fresh session opens normally.

func OpenRun

func OpenRun(db *sql.DB, projectID string, pid int) (int64, error)

OpenRun creates a new watch_runs row for the clarity watch process identified by pid, watching the repo identified by projectID, and returns its id.

A run's boundary is deliberately the same one CLR-91's repo lock already enforces: one process holds the lock for its whole lifetime, watching the entire repo (main worktree plus every linked worktree) under that single hold. OpenRun should be called once per process, right after that lock is acquired and persistence is otherwise set up — every session opened afterward is stamped with this run's id (see OpenSession), so which `clarity watch` invocation produced a given session becomes recoverable without inferring it from timestamps.

func OpenSession

func OpenSession(db *sql.DB, worktreeID string, runID int64) (int64, error)

OpenSession creates a new open session (closed_at NULL) for worktreeID, numbered one past the highest number ever used for that worktree — closed or still open, so a stale open session left behind by an earlier process run is never renumbered or reused — and returns its id. runID is the calling process's watch_runs row (see OpenRun), stamped once and never touched again: a session's run_id always names the run that opened it, even if a later run resumes it (see OpenOrResumeSession) — resuming is a continuation, not a re-parenting.

Each call always creates a fresh session; it never looks for or resumes a previously-open one. Deciding what to do with a session left open by a prior process run (resume vs. CloseSessionStale) is restart-hydration's job, not this one's.

Numbering is computed as MAX(number)+1 inside a transaction and retried on a unique-constraint conflict against idx_sessions_worktree_id_number, so it stays correct under concurrent writers regardless of what CLR-91 concludes about process-level coordination.

func PathFor

func PathFor(worktreePath string) (string, error)

PathFor resolves the session-history database path for the repository containing worktreePath. It does not create the database itself, only the containing directory, so callers can open/migrate it immediately after.

func RegisterWorktree

func RegisterWorktree(db *sql.DB, id, projectID, path string, kind protocol.WorktreeKind, lastKnownLabel string) error

RegisterWorktree upserts a worktrees row for id. On first sight it's inserted with first_seen_at set to now. On a later re-registration (e.g. clarity watch relaunched against the same worktree, which is why id is deterministic) it refreshes last_known_label and clears disposed_at and hidden_at: the supervisor calling this at all means the worktree is verifiably live right now, which contradicts any disposed/hidden marker left over from a prior lifecycle at this same id. first_seen_at, path, and kind are left untouched on conflict — "first" stays first.

func ResolveRepoOrigin

func ResolveRepoOrigin(worktreePath string) (string, error)

ResolveRepoOrigin returns the stable identity this package uses for projects.repo_origin: the repo's "origin" remote URL, or — for a repo with no remote configured, the normal state for a fresh `git init` that hasn't been pushed anywhere — a synthetic identity derived from its common git dir, prefixed so it can never collide with a real remote URL.

Types

type CommitRecord

type CommitRecord struct {
	Position int
	Hash     string
	Subject  string
}

CommitRecord is one commit to record against a session being closed as committed.

type SessionDetail

type SessionDetail struct {
	SessionSummary
	Snapshots []SnapshotRecord
	Commits   []CommitRecord
}

SessionDetail is a session's full content: its summary plus every snapshot and commit recorded against it, ordered by position.

func GetSessionDetail

func GetSessionDetail(db *sql.DB, sessionID int64) (detail SessionDetail, found bool, err error)

GetSessionDetail returns sessionID's full content: its summary, every snapshot, and every commit, ordered by position. found is false if no session with that id exists.

type SessionSummary

type SessionSummary struct {
	ID            int64
	WorktreeID    string
	RunID         int64
	Number        int
	CreatedAt     time.Time
	ClosedAt      *time.Time
	ClosedReason  string
	SnapshotCount int
	CommitCount   int
}

SessionSummary is one session's metadata, with no snapshot/commit content — see ListSessions. Kept as this package's own type, independent of the wire format (mirrored by protocol.PersistedSessionSummary).

func ListSessions

func ListSessions(db *sql.DB, projectID string) ([]SessionSummary, error)

ListSessions returns every persisted session across the whole project identified by projectID — every worktree, every run — ordered by worktree then number. No snapshot/commit content, only counts: cheap enough to call unconditionally on attach.

Scoped to the project, not a single worktree: a watch_runs row (CLR-97) already spans every worktree the process watches, so a worktree-scoped listing would force the caller to fetch per-worktree and stitch runs back together itself.

type SnapshotRecord

type SnapshotRecord struct {
	Position  int
	Source    string
	Format    string
	Kind      string
	CreatedAt time.Time
}

SnapshotRecord is one recorded snapshot within a session's timeline, as returned by GetSessionDetail.

Jump to

Keyboard shortcuts

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