data

package
v0.14.0 Latest Latest
Warning

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

Go to latest
Published: Jul 18, 2026 License: MIT Imports: 24 Imported by: 0

Documentation

Overview

Package data — attention.go scans Copilot CLI session-state directories to determine real-time attention status for each session. This avoids relying on session-store.db which is only updated during full reindex.

Package data provides Go data models that map to the Copilot CLI session store SQLite database, along with types for filtering, sorting, and pivoting session queries.

Package data — plans.go provides functions to detect and read Copilot CLI plan.md files from session-state directories.

Package data — workstatus.go provides functions to parse plan.md files and determine whether a session's planned work has been completed.

Index

Constants

This section is empty.

Variables

View Source
var ErrCopilotNotFound = errors.New("copilot CLI binary not found")

ErrCopilotNotFound is returned when the Copilot CLI binary cannot be located on the system.

View Source
var ErrIndexBusy = errors.New("session store is busy — Copilot CLI may be reindexing, try again shortly")

ErrIndexBusy is returned when the session store database is locked by another process (e.g. Copilot CLI reindexing).

View Source
var ErrReindexCancelled = errors.New("reindex cancelled")

ErrReindexCancelled is returned when the user cancels a running reindex.

Functions

func ChronicleReindex

func ChronicleReindex(ctx context.Context, onLine func(line string)) error

ChronicleReindex launches the Copilot CLI in a pseudo-terminal, sends the /chronicle reindex slash command, and streams cleaned output lines to the provided callback. This performs the full ETL: reading session JSONL files, workspace metadata, and checkpoints into the SQLite store.

If the Copilot CLI binary cannot be found, it returns ErrCopilotNotFound and the caller should fall back to Maintain().

The ctx parameter supports cancellation — when cancelled the PTY is closed immediately and ErrReindexCancelled is returned.

The onLine callback receives each non-empty line of stripped output. It is called from a goroutine and must be safe for concurrent use.

func ExportDir added in v0.13.0

func ExportDir() (string, error)

ExportDir returns the path to the export directory under the dispatch config directory (e.g. ~/.config/dispatch/exports).

func ExportSession added in v0.13.0

func ExportSession(detail *SessionDetail, dir string) (string, error)

ExportSession writes a session detail as Markdown to the given directory. The file is named <session-id>.md using a sanitized filename. Returns the full path of the written file.

func LastReindexTime

func LastReindexTime() time.Time

LastReindexTime returns the modification time of the session store database file, which is updated whenever a reindex writes to it. Returns the zero time if the file cannot be found.

func Maintain

func Maintain(ctx context.Context) error

Maintain opens a temporary read-write connection to the session store, checkpoints the WAL, rebuilds and optimises the FTS5 search index, then closes the connection. This does NOT modify session data — only index and journal maintenance. Safe to call while the read-only Store is open.

func NormalizeRepoSlug added in v0.14.0

func NormalizeRepoSlug(repository string) string

NormalizeRepoSlug reduces a repository identifier to its "owner/repo" form. It accepts a bare slug, an https URL, a scp-style ssh remote, or a github.com-prefixed path, and returns "" when it cannot extract owner/repo. It matches the form stored in the session repository column, so callers can use it to compare a live git remote against stored sessions.

func ParsePlanRemainingItems added in v0.8.0

func ParsePlanRemainingItems(content string) []string

ParsePlanRemainingItems extracts the text of unchecked/incomplete tasks from plan.md content. It recognises the same two formats as ParsePlanTasks:

  1. Checkbox-based: text from "- [ ] task" lines.
  2. Section-based: list items under TODO / IN PROGRESS headers.

Checkbox items take precedence when present, matching ParsePlanTasks behaviour. Returns nil when no incomplete items are found.

func ParsePlanTasks added in v0.8.0

func ParsePlanTasks(content string) (total int, done int)

ParsePlanTasks parses plan.md content and extracts task items.

It recognises two formats:

  1. Markdown checkboxes: "- [ ] task" (incomplete) / "- [x] task" (complete).
  2. Section-based headers: "## TODO:", "## DONE:", "## IN PROGRESS:" with list items underneath.

If both checkboxes and section headers are present the checkbox counts take precedence. Returns (0, 0) for empty or unparseable content.

func PlanFilePath added in v0.4.0

func PlanFilePath(sessionID string) (string, error)

PlanFilePath returns the absolute path to the plan.md file for the given session ID. Returns an error if the session ID is invalid or the session-state directory cannot be resolved.

func ReadPlanContent added in v0.4.0

func ReadPlanContent(sessionID string) (string, error)

ReadPlanContent reads the plan.md file for the given session ID. Returns the plan content as a string, capped at maxPlanFileSize bytes. Returns an empty string and an error if the file cannot be read or the session ID is invalid.

func RefURL added in v0.14.0

func RefURL(repository, refType, refValue string) (url string, ok bool)

RefURL builds a github.com URL for a session reference. The repository may be an "owner/repo" slug or a git remote URL (https or ssh form); anything else yields ok=false. Pull request and issue values are reduced to their digits so stored forms like "#42" or "PR42" still resolve. Commit values are kept as-is after a basic hex-character check. It returns ok=false when a valid URL cannot be built.

func RenderHTML added in v0.14.0

func RenderHTML(detail *SessionDetail) string

RenderHTML formats a SessionDetail as a single self-contained HTML document suitable for reading in a browser. The stylesheet is inlined so the file has no external references. All session and conversation text is escaped so content cannot inject markup.

func RenderMarkdown added in v0.13.0

func RenderMarkdown(detail *SessionDetail) string

RenderMarkdown formats a SessionDetail as a Markdown document suitable for export. The output includes metadata, conversation turns, checkpoints, touched files, and external references.

func SafeFilename added in v0.13.0

func SafeFilename(id string) string

SafeFilename returns a filesystem-safe string derived from id. Non-alphanumeric characters (excluding hyphens, underscores, dots) are replaced with underscores, and the result is truncated to 200 characters.

func ScanAllPlans added in v0.4.0

func ScanAllPlans() map[string]bool

ScanAllPlans reads the session-state directory and returns a map of session ID → true for every session that has a non-empty plan.md file. It discovers sessions from the filesystem directly, matching the pattern used by ScanAttention.

func ScanAttention added in v0.1.3

func ScanAttention(threshold time.Duration, workspaceRecovery bool) map[string]AttentionStatus

ScanAttention reads the Copilot CLI session-state directories and returns a map of session ID → AttentionStatus. The threshold parameter controls how long a running session can be quiet before it is classified as stale.

The scan is read-only and does not modify any files. It completes in under 50 ms for 100 sessions on typical hardware.

func ScanAttentionQuick added in v0.1.3

func ScanAttentionQuick(threshold time.Duration, workspaceRecovery bool) map[string]AttentionStatus

ScanAttentionQuick performs a fast first pass that only checks lock files for live sessions. Dead sessions are classified as AttentionIdle without reading events.jsonl. Use this for the initial scan to get dots visible immediately, then follow up with ScanAttention for full classification.

func ScanWorkStatus added in v0.8.0

func ScanWorkStatus(sessionIDs []string, progressFn func(completed, total int)) map[string]WorkStatusResult

ScanWorkStatus performs a full analysis of plan.md files for the given sessions. It reads each plan, parses its tasks, and returns a WorkStatusResult per session.

The optional progressFn callback is invoked after each session is analysed with (completed count, total count) for progress reporting.

func ScanWorkStatusQuick added in v0.8.0

func ScanWorkStatusQuick(planMap map[string]bool) map[string]WorkStatusResult

ScanWorkStatusQuick performs a fast classification pass over a plan map. Sessions with plans are marked WorkStatusUnknown (pending full analysis); sessions without plans are marked WorkStatusNoPlan. This is O(1) per session since it requires no file I/O.

func SessionStatePath added in v0.14.0

func SessionStatePath() string

SessionStatePath returns the resolved Copilot CLI session-state directory used for plan and attention scans. It returns an empty string when the directory cannot be resolved.

func WriteContinuationPlan added in v0.8.0

func WriteContinuationPlan(sessionID string, remaining []string, summary string) error

WriteContinuationPlan appends (or replaces) a "Remaining Work" section in the session's plan.md file. If the plan already contains a section with the sentinel header, that section is replaced in-place so that repeated scans do not duplicate content.

The function creates the plan.md file (and its parent directory) if neither exists, following the same path-safety rules as PlanFilePath.

Types

type AmbiguousIDPrefixError added in v0.14.0

type AmbiguousIDPrefixError struct {
	Prefix     string
	Candidates []string
}

AmbiguousIDPrefixError is returned by ResolveIDPrefix when a session ID prefix matches more than one stored session. Candidates lists the matching full IDs (capped) so the caller can tell the user how to disambiguate.

func (*AmbiguousIDPrefixError) Error added in v0.14.0

func (e *AmbiguousIDPrefixError) Error() string

type AttentionStatus added in v0.1.3

type AttentionStatus int

AttentionStatus indicates whether a session needs the user's attention. It is determined by scanning the Copilot CLI session-state directory for lock files and events.jsonl, not from the session-store.db.

const (
	// AttentionIdle means the session is not running (no lock file or PID dead).
	AttentionIdle AttentionStatus = iota
	// AttentionStale means the session is running but has no recent activity.
	AttentionStale
	// AttentionActive means the AI is currently working on a response.
	AttentionActive
	// AttentionWaiting means the AI has responded and is waiting for user input.
	AttentionWaiting
	// AttentionInterrupted means the session was interrupted by crash or reboot
	// (stale lock file with dead PID, last event not a turn-end).
	AttentionInterrupted
	// AttentionWorking means the AI is actively executing tools (finer than Active).
	AttentionWorking
	// AttentionThinking means the AI is generating a response (no tool calls yet).
	AttentionThinking
	// AttentionCompacting means the session is undergoing context compaction.
	AttentionCompacting
)

func (AttentionStatus) String added in v0.1.3

func (a AttentionStatus) String() string

String returns a human-readable label for the attention status.

type Checkpoint

type Checkpoint struct {
	SessionID        string `json:"session_id"`
	CheckpointNumber int    `json:"checkpoint_number"`
	Title            string `json:"title"`
	Overview         string `json:"overview"`
	History          string `json:"history"`
	WorkDone         string `json:"work_done"`
	TechnicalDetails string `json:"technical_details"`
	ImportantFiles   string `json:"important_files"`
	NextSteps        string `json:"next_steps"`
}

Checkpoint maps to the checkpoints table and captures a point-in-time snapshot of session progress.

type DBWatcher added in v0.9.0

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

DBWatcher monitors the session store database for changes. It uses SQLite's PRAGMA data_version as the primary signal (increments on each external commit) and falls back to WAL file modification time when the database connection is unavailable. It only polls when active (TUI focused) to minimize resource usage.

func NewDBWatcher added in v0.9.0

func NewDBWatcher(onChange func()) *DBWatcher

NewDBWatcher creates a watcher for the session store. The onChange callback is invoked (from a goroutine) whenever the DB appears to have been modified. The watcher starts inactive — call SetActive(true) to begin polling.

func (*DBWatcher) Poll added in v0.9.0

func (w *DBWatcher) Poll() bool

Poll checks the database for changes and returns true if it has been modified since the last check. This is also called internally by the loop but can be called manually for immediate checks.

func (*DBWatcher) ResetBaseline added in v0.9.0

func (w *DBWatcher) ResetBaseline()

ResetBaseline updates the last-known state so the next poll cycle won't fire a spurious change notification. Use this after a manual reload (e.g. rebuild index) to avoid duplicate refreshes.

func (*DBWatcher) SetActive added in v0.9.0

func (w *DBWatcher) SetActive(active bool)

SetActive enables or disables polling. When active is false, no file system operations are performed (near-zero CPU).

func (*DBWatcher) SetInterval added in v0.14.0

func (w *DBWatcher) SetInterval(d time.Duration)

SetInterval sets the polling interval. It must be called before the first SetActive(true); once the loop is running the interval is fixed. A non-positive interval is ignored so the built-in default is preserved.

func (*DBWatcher) Stop added in v0.9.0

func (w *DBWatcher) Stop()

Stop permanently stops the watcher. It is safe to call multiple times.

type FilterOptions

type FilterOptions struct {
	Query        string     `json:"query,omitempty"`
	Folder       string     `json:"folder,omitempty"`
	Repository   string     `json:"repository,omitempty"`
	Branch       string     `json:"branch,omitempty"`
	HostType     string     `json:"host_type,omitempty"`
	Since        *time.Time `json:"since,omitempty"`
	Until        *time.Time `json:"until,omitempty"`
	HasRefs      bool       `json:"has_refs,omitempty"`
	ExcludedDirs []string   `json:"excluded_dirs,omitempty"`

	// ExcludedWords is a list of words that hide sessions whose summary
	// or turn content contains any of these words (case-insensitive).
	ExcludedWords []string `json:"excluded_words,omitempty"`

	// DeepSearch controls the breadth of the text search. When false
	// (default / quick mode), only session-level fields are searched
	// (summary, branch, repository, cwd). When true (deep mode), related
	// tables are also searched: turns.user_message, checkpoints.title,
	// checkpoints.overview, session_files.file_path, session_refs.ref_value.
	DeepSearch bool `json:"deep_search,omitempty"`
}

FilterOptions describes the criteria used to narrow session queries.

type PivotField

type PivotField string

PivotField identifies the dimension used to group sessions.

const (
	// PivotByFolder groups sessions by their working directory.
	PivotByFolder PivotField = "cwd"
	// PivotByRepo groups sessions by repository name.
	PivotByRepo PivotField = "repository"
	// PivotByBranch groups sessions by git branch name.
	PivotByBranch PivotField = "branch"
	// PivotByDate groups sessions by date (YYYY-MM-DD).
	PivotByDate PivotField = "date"
	// PivotByHost groups sessions by host type (the provider that created
	// the session, e.g. "github" or "ado").
	PivotByHost PivotField = "host_type"
)

type SearchResult

type SearchResult struct {
	Content    string  `json:"content"`
	SessionID  string  `json:"session_id"`
	SourceType string  `json:"source_type"`
	SourceID   string  `json:"source_id"`
	Rank       float64 `json:"rank"`
}

SearchResult holds a single row returned from the FTS5 search_index virtual table, including the relevance rank.

type Session

type Session struct {
	ID         string `json:"id"`
	Cwd        string `json:"cwd"`
	Repository string `json:"repository"`
	Branch     string `json:"branch"`
	Summary    string `json:"summary"`
	CreatedAt  string `json:"created_at"`
	UpdatedAt  string `json:"updated_at"`

	// HostType is the authentication provider that created the session
	// (e.g. "github"). Added in schema version 3; empty for older sessions.
	HostType string `json:"host_type"`

	// LastActiveAt is computed at query time as the MAX of the latest
	// turn timestamp, updated_at, and created_at — whichever is most
	// recent.  Indexed turns may lag (stale reindex) while updated_at
	// may be noisy, so taking the maximum gives the best estimate.
	LastActiveAt string `json:"last_active_at"`

	// Computed fields – populated by JOIN aggregates, not stored in the table.
	TurnCount int `json:"turn_count"`
	FileCount int `json:"file_count"`
}

Session maps to the sessions table and carries computed aggregate counts populated at query time.

type SessionDetail

type SessionDetail struct {
	Session     Session       `json:"session"`
	Turns       []Turn        `json:"turns"`
	Checkpoints []Checkpoint  `json:"checkpoints"`
	Files       []SessionFile `json:"files"`
	Refs        []SessionRef  `json:"refs"`
}

SessionDetail is an aggregated view that combines a session with all of its related turns, checkpoints, files, and external references.

type SessionFile

type SessionFile struct {
	SessionID   string `json:"session_id"`
	FilePath    string `json:"file_path"`
	ToolName    string `json:"tool_name"`
	TurnIndex   int    `json:"turn_index"`
	FirstSeenAt string `json:"first_seen_at"`
}

SessionFile maps to the session_files table and records a file touched during a session.

type SessionGroup

type SessionGroup struct {
	Label    string    `json:"label"`
	Sessions []Session `json:"sessions"`
	Count    int       `json:"count"`
}

SessionGroup holds a set of sessions that share a common pivot label.

type SessionRef

type SessionRef struct {
	SessionID string `json:"session_id"`
	RefType   string `json:"ref_type"` // "commit", "pr", or "issue"
	RefValue  string `json:"ref_value"`
	TurnIndex int    `json:"turn_index"`
	CreatedAt string `json:"created_at"`
}

SessionRef maps to the session_refs table and links a session to an external reference such as a commit, pull request, or issue.

func BestRef added in v0.14.0

func BestRef(refs []SessionRef) (SessionRef, bool)

BestRef returns the most useful reference to open for a session, preferring a pull request over an issue over a commit. The second return value is false when the slice has no usable references.

type SortField

type SortField string

SortField identifies which column to sort sessions by.

const (
	// SortByUpdated sorts sessions by last update time.
	SortByUpdated SortField = "updated_at"
	// SortByCreated sorts sessions by creation time.
	SortByCreated SortField = "created_at"
	// SortByTurns sorts sessions by conversation turn count.
	SortByTurns SortField = "turn_count"
	// SortByName sorts sessions alphabetically by summary.
	SortByName SortField = "summary"
	// SortByFolder sorts sessions alphabetically by working directory.
	SortByFolder SortField = "cwd"
	// SortByAttention sorts sessions by attention status priority
	// (Waiting > Active > Stale > Idle). This is applied post-load
	// in the TUI layer since attention status is computed at runtime.
	SortByAttention SortField = "attention"
	// SortByFrecency ranks sessions by how often and how recently the user
	// has launched them. Like attention, it is applied post-load in the TUI
	// layer because launch statistics live in the user config, not the store.
	SortByFrecency SortField = "frecency"
)

type SortOptions

type SortOptions struct {
	Field SortField `json:"field"`
	Order SortOrder `json:"order"`
}

SortOptions combines a field and direction for ordering query results.

type SortOrder

type SortOrder string

SortOrder indicates ascending or descending sort direction.

const (
	// Ascending sorts results from lowest to highest value.
	Ascending SortOrder = "ASC"
	// Descending sorts results from highest to lowest value.
	Descending SortOrder = "DESC"
)

type Store

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

Store provides read-only access to the Copilot CLI session store.

func Open

func Open() (*Store, error)

Open opens the session store at the default platform path.

func OpenPath

func OpenPath(path string) (*Store, error)

OpenPath opens the session store at the given file path. The database is opened in read-only mode.

func (*Store) AllSessionIDs added in v0.14.0

func (s *Store) AllSessionIDs(ctx context.Context) ([]string, error)

AllSessionIDs returns the IDs of every session in the store, including "empty" sessions (no turns/files/checkpoints/refs) that ListSessions filters out. Callers that need to know whether a session still exists on disk — such as `dispatch prune`, which deletes config metadata for vanished sessions — must use this rather than ListSessions, otherwise metadata for real-but-empty sessions would be wrongly treated as stale.

func (*Store) Close

func (s *Store) Close() error

Close closes the underlying database connection.

func (*Store) CountSessions added in v0.14.0

func (s *Store) CountSessions(ctx context.Context) (int, error)

CountSessions returns the total number of sessions stored.

func (*Store) GetSession

func (s *Store) GetSession(ctx context.Context, id string) (*SessionDetail, error)

GetSession loads a single session and all of its related turns, checkpoints, files, and refs.

func (*Store) GroupSessions

func (s *Store) GroupSessions(ctx context.Context, pivot PivotField, filter FilterOptions, sort SortOptions, limit int) ([]SessionGroup, error)

GroupSessions groups sessions by the specified pivot field, applying the given filter and sort order within each group.

func (*Store) ListBranches

func (s *Store) ListBranches(ctx context.Context, repository string) ([]string, error)

ListBranches returns distinct branch values. If repository is non-empty, results are filtered to that repository.

func (*Store) ListFolders

func (s *Store) ListFolders(ctx context.Context) ([]string, error)

ListFolders returns the distinct cwd values across all sessions, sorted alphabetically.

func (*Store) ListRepositories

func (s *Store) ListRepositories(ctx context.Context) ([]string, error)

ListRepositories returns the distinct non-empty repository values across all sessions, sorted alphabetically.

func (*Store) ListSessions

func (s *Store) ListSessions(ctx context.Context, filter FilterOptions, sort SortOptions, limit int) ([]Session, error)

ListSessions returns sessions matching the filter, ordered and limited as specified. TurnCount and FileCount are computed via subqueries.

func (*Store) ListSessionsByIDs

func (s *Store) ListSessionsByIDs(ctx context.Context, ids []string) ([]Session, error)

ListSessionsByIDs returns sessions matching the given IDs, preserving the input order. IDs not found in the database are silently skipped.

func (*Store) ResolveIDPrefix added in v0.14.0

func (s *Store) ResolveIDPrefix(ctx context.Context, prefix string) (string, error)

ResolveIDPrefix expands a session ID or a unique ID prefix to a full session ID, mirroring git's short-SHA behavior. An exact ID match always wins, even when that value is also a prefix of longer IDs. With no exact match the value is treated as a prefix: a single match returns that ID, multiple matches return an *AmbiguousIDPrefixError listing the candidates, and no match returns sql.ErrNoRows. An empty prefix is rejected.

func (*Store) SearchSessions

func (s *Store) SearchSessions(ctx context.Context, query string, limit int) ([]SearchResult, error)

SearchSessions performs a fuzzy substring search across session metadata and turn content, returning matches ranked by source type. Sessions with zero turns are excluded. When FTS5 is available it is tried first for faster BM25-ranked results; on failure it falls back to LIKE.

func (*Store) SearchSessionsFTS added in v0.9.0

func (s *Store) SearchSessionsFTS(ctx context.Context, query string, limit int) ([]SearchResult, error)

SearchSessionsFTS performs a full-text search using the FTS5 search_index virtual table maintained by the Copilot CLI. Results are ranked by BM25 relevance. Returns nil, nil if the FTS5 table is not available.

type Turn

type Turn struct {
	SessionID         string `json:"session_id"`
	TurnIndex         int    `json:"turn_index"`
	UserMessage       string `json:"user_message"`
	AssistantResponse string `json:"assistant_response"`
	Timestamp         string `json:"timestamp"`
}

Turn maps to the turns table and represents a single conversational exchange within a session.

type WorkStatus added in v0.8.0

type WorkStatus int

WorkStatus indicates whether a session's planned work has been completed. It is determined by parsing the plan.md file and optionally cross-referencing against the session's git branch state.

const (
	// WorkStatusUnknown means the session has not been analyzed yet.
	WorkStatusUnknown WorkStatus = iota
	// WorkStatusComplete means all planned work appears to be done.
	WorkStatusComplete
	// WorkStatusIncomplete means there are outstanding tasks remaining.
	WorkStatusIncomplete
	// WorkStatusNoPlan means the session has no plan.md file.
	WorkStatusNoPlan
	// WorkStatusAnalyzing means analysis is currently in progress.
	WorkStatusAnalyzing
	// WorkStatusError means the analysis failed.
	WorkStatusError
)

func (WorkStatus) String added in v0.8.0

func (w WorkStatus) String() string

String returns a human-readable label for the work status.

type WorkStatusResult added in v0.8.0

type WorkStatusResult struct {
	Status         WorkStatus
	TotalTasks     int      // total tasks found in plan
	DoneTasks      int      // tasks marked as complete
	Detail         string   // human-readable summary (e.g., "3/7 tasks complete")
	RemainingItems []string // outstanding items from plan parsing or AI analysis (may be nil)
	Error          error    // non-nil when Status == WorkStatusError
}

WorkStatusResult holds the computed work status for a session along with detail about the tasks found in the plan.

Jump to

Keyboard shortcuts

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