Documentation
¶
Overview ¶
Package discovery scans for active Claude Code sessions on the local machine. It reads session files, checks process liveness, parses transcripts, and determines each session's current state.
Index ¶
- func CheckSession(pid int, startedAt time.Time) bool
- func EncodeCWD(cwd string) string
- func FindSessionIndex(projectsDir, cwd string) string
- func FindTranscriptPath(projectsDir, cwd, sessionID string) string
- func IsProcessAlive(pid int) bool
- func ParseSessionIndex(path string) (map[string]IndexEntry, error)
- func ReadLastActivity(path string) (time.Time, error)
- type AttentionReason
- type IndexEntry
- type Project
- type Session
- type SessionState
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func CheckSession ¶
CheckSession checks whether the process for a session is still the same process that started the session. It verifies both that the PID is alive and that the process start time is close to the session's startedAt.
This detects PID reuse: if a process dies and a new process gets the same PID, the start times won't match.
func EncodeCWD ¶
EncodeCWD converts a filesystem path to the encoded directory name used by Claude Code under ~/.claude/projects/. Forward slashes are replaced with hyphens, and non-ASCII characters are also replaced with hyphens to match Claude Code's actual encoding behavior.
Example: "/Users/jason/project" -> "-Users-jason-project" Example: "/Users/jason/Documents/实习/理想实习/FusionSQL" -> "-Users-jason-Documents---------FusionSQL"
func FindSessionIndex ¶
FindSessionIndex locates the sessions-index.json file for a given project CWD under the projects directory.
Returns an empty string if the file does not exist.
func FindTranscriptPath ¶
FindTranscriptPath locates the transcript JSONL file for a given session. It tries two strategies:
- Direct path: projectsDir/<encodedCWD>/<sessionID>.jsonl
- Fallback scan: search all project dirs for the sessionID.jsonl file
Returns an empty string if the transcript file does not exist.
func IsProcessAlive ¶
IsProcessAlive checks whether a process with the given PID exists. On macOS, this uses kill(pid, 0) which returns an error if the process does not exist. EPERM (permission denied) still means the process exists.
func ParseSessionIndex ¶
func ParseSessionIndex(path string) (map[string]IndexEntry, error)
ParseSessionIndex reads a sessions-index.json file and returns a map of session ID to IndexEntry. This is hints-only data used to enrich sessions with summaries and message counts.
Defensive behavior:
- Returns empty map and no error if the file does not exist.
- Returns empty map and no error if the file is malformed JSON.
- Silently ignores unknown fields in the JSON.
- Never fails. If anything goes wrong, you just get less data.
func ReadLastActivity ¶
ReadLastActivity reads the tail of a JSONL transcript file and returns the timestamp of the most recent entry that has one.
If the file does not exist or is empty, it returns the zero time and no error. Malformed lines are silently skipped.
Types ¶
type AttentionReason ¶
type AttentionReason string
AttentionReason flags diagnostic issues that are separate from lifecycle state. Per Codex review: don't mix lifecycle states with data-integrity warnings.
const ( // AttentionOrphaned means a transcript exists but no session file was found. AttentionOrphaned AttentionReason = "orphaned" // AttentionStale means the PID was reused by a different process. AttentionStale AttentionReason = "stale" // AttentionNoTranscript means a session file exists but no transcript was found. AttentionNoTranscript AttentionReason = "no-transcript" )
type IndexEntry ¶
type IndexEntry struct {
SessionID string `json:"sessionId"`
Summary string `json:"summary"`
MessageCount int `json:"messageCount"`
}
IndexEntry holds the subset of fields we extract from a sessions-index.json entry. Unknown fields are silently ignored.
type Project ¶
type Project struct {
// Name is the project identifier. Normally the basename of the shared CWD
// (e.g. "QuantMind"). When multiple projects share the same basename,
// GroupByProject expands it to "parent/basename" (e.g. "work/api") to
// prevent identity collisions.
Name string
// Path is the full filesystem path to the project directory.
Path string
// Sessions contains all discovered sessions for this project.
Sessions []Session
}
Project groups sessions that share the same working directory.
func GroupByProject ¶
GroupByProject groups a flat list of sessions into Project values, keyed by CWD. When multiple distinct CWDs share the same basename, their display names are expanded to include up to 3 path components (e.g. "work/api" instead of "api") until all names are unique.
The returned slice is sorted alphabetically by project name.
type Session ¶
type Session struct {
// ID is the session UUID from the session file (sessionId field).
ID string
// PID is the process ID of the Claude Code process.
PID int
// CWD is the working directory the session was started in.
CWD string
// ProjectName is the basename of CWD (or the git root if available).
ProjectName string
// StartedAt is when the session was created (from the session file).
StartedAt time.Time
// State is the classified lifecycle state.
State SessionState
// LastActivity is the timestamp of the most recent transcript entry.
// Zero value means no activity information is available.
LastActivity time.Time
// Summary is the human-readable summary from sessions-index.json, if
// available. Empty string if not found.
Summary string
// MessageCount is the number of messages from sessions-index.json.
// Zero if not available.
MessageCount int
// Attention holds diagnostic flags (orphaned, stale, no-transcript).
// Empty slice means no issues.
Attention []AttentionReason
}
Session represents a single Claude Code session discovered on disk.
func ScanSessions ¶
ScanSessions reads all session files from the given directory and returns parsed Session values. It silently skips files that are not valid JSON, are not .json files, or are missing required fields.
If the directory does not exist, ScanSessions returns an empty slice and no error.
type SessionState ¶
type SessionState string
SessionState describes the lifecycle state of a Claude Code session.
const ( // StateBusy means the session's process is alive and had activity within // the last 30 seconds. StateBusy SessionState = "busy" // StateWaiting means the process is alive but activity was between 30 // seconds and 5 minutes ago (likely waiting for user input). StateWaiting SessionState = "waiting" // StateIdle means the process is alive but no activity for over 5 // minutes. StateIdle SessionState = "idle" // StateDead means the session's process is no longer running. StateDead SessionState = "dead" )
func ClassifyState ¶
func ClassifyState(processAlive bool, lastActivity time.Time) SessionState
ClassifyState determines the SessionState based on process liveness and last activity timestamp.
Decision logic:
- Process not alive -> StateDead
- Process alive, activity < 30s ago -> StateBusy
- Process alive, activity 30s-5min ago -> StateWaiting
- Process alive, activity > 5min ago -> StateIdle
- Process alive, no activity info -> StateIdle
StateOrphaned and StateStale are not assigned by this function; they require additional context from the scanner.
func (SessionState) IsAlive ¶
func (s SessionState) IsAlive() bool
IsAlive reports whether the state indicates an active, running session.