Documentation
¶
Overview ¶
Package strategy provides an interface for different git strategies that can be used to save and manage Claude Code session changes.
Index ¶
- Constants
- Variables
- func CalculateAttributionWithAccumulated(baseTree *object.Tree, shadowTree *object.Tree, headTree *object.Tree, ...) *checkpoint.InitialAttribution
- func ClearSessionState(sessionID string) error
- func CountTodos(todosJSON []byte) int
- func DeleteOrphanedCheckpoints(checkpointIDs []string) (deleted []string, failed []string, err error)
- func DeleteOrphanedSessionStates(sessionIDs []string) (deleted []string, failed []string, err error)
- func DeleteShadowBranches(branches []string) (deleted []string, failed []string, err error)
- func EnsureEntireGitignore() error
- func EnsureMetadataBranch(repo *git.Repository) error
- func ExtractFirstPrompt(content string) string
- func ExtractInProgressTodo(todosJSON []byte) string
- func ExtractLastCompletedTodo(todosJSON []byte) string
- func ExtractSessionIDFromCommit(commit *object.Commit) string
- func ExtractToolUseIDFromTaskMetadataDir(metadataDir string) string
- func FormatIncrementalMessage(todoContent string, sequence int, toolUseID string) string
- func FormatIncrementalSubject(incrementalType string, subagentType string, taskDescription string, ...) string
- func FormatSubagentEndMessage(agentType, description, toolUseID string) string
- func GetCurrentBranchName(repo *git.Repository) string
- func GetDefaultBranchName(repo *git.Repository) string
- func GetGitAuthorFromRepo(repo *git.Repository) (name, email string)
- func GetGitCommonDir() (string, error)
- func GetGitDir() (string, error)
- func GetMainBranchHash(repo *git.Repository) plumbing.Hash
- func GetMainRepoRoot() (string, error)
- func GetMetadataBranchTree(repo *git.Repository) (*object.Tree, error)
- func GetRemoteMetadataBranchTree(repo *git.Repository) (*object.Tree, error)
- func GetWorktreePath() (string, error)
- func HardResetWithProtection(commitHash plumbing.Hash) (shortID string, err error)
- func InstallGitHook(silent bool) (int, error)
- func IsAncestorOf(repo *git.Repository, commit, target plumbing.Hash) bool
- func IsGitHookInstalled() bool
- func IsInsideWorktree() bool
- func IsOnDefaultBranch(repo *git.Repository) (bool, string)
- func IsShadowBranch(branchName string) bool
- func List() []string
- func ListShadowBranches() ([]string, error)
- func OpenRepository() (*git.Repository, error)
- func PromptOverwriteNewerLogs(sessions []SessionRestoreInfo) (bool, error)
- func ReadAllSessionPromptsFromTree(tree *object.Tree, checkpointPath string, sessionCount int, ...) []string
- func ReadSessionPromptFromShadow(repo *git.Repository, baseCommit, worktreeID, sessionID string) string
- func ReadSessionPromptFromTree(tree *object.Tree, checkpointPath string) string
- func Register(name string, factory Factory)
- func RemoveGitHook() (int, error)
- func SaveSessionState(state *SessionState) error
- func StageFiles(worktree *git.Worktree, modified, newFiles, deleted []string, ...)
- func StatusToText(status SessionRestoreStatus) string
- func TaskMetadataDir(sessionMetadataDir, toolUseID string) string
- func TruncateDescription(s string, maxLen int) string
- type AutoCommitStrategy
- func (s *AutoCommitStrategy) AllowsMainBranch() bool
- func (s *AutoCommitStrategy) CanRewind() (bool, string, error)
- func (s *AutoCommitStrategy) Description() string
- func (s *AutoCommitStrategy) EnsureSetup() error
- func (s *AutoCommitStrategy) GetCheckpointLog(cp Checkpoint) ([]byte, error)
- func (s *AutoCommitStrategy) GetMetadataRef(checkpoint Checkpoint) string
- func (s *AutoCommitStrategy) GetRewindPoints(limit int) ([]RewindPoint, error)
- func (s *AutoCommitStrategy) GetSessionContext(sessionID string) string
- func (s *AutoCommitStrategy) GetSessionInfo() (*SessionInfo, error)
- func (s *AutoCommitStrategy) GetSessionMetadataRef(sessionID string) string
- func (s *AutoCommitStrategy) GetTaskCheckpoint(point RewindPoint) (*TaskCheckpoint, error)
- func (s *AutoCommitStrategy) GetTaskCheckpointTranscript(point RewindPoint) ([]byte, error)
- func (s *AutoCommitStrategy) InitializeSession(sessionID string, agentType agent.AgentType, transcriptPath string) error
- func (s *AutoCommitStrategy) ListOrphanedItems() ([]CleanupItem, error)
- func (s *AutoCommitStrategy) Name() string
- func (s *AutoCommitStrategy) PrePush(remote string) error
- func (s *AutoCommitStrategy) PreviewRewind(_ RewindPoint) (*RewindPreview, error)
- func (s *AutoCommitStrategy) Rewind(point RewindPoint) error
- func (s *AutoCommitStrategy) SaveChanges(ctx SaveContext) error
- func (s *AutoCommitStrategy) SaveTaskCheckpoint(ctx TaskCheckpointContext) error
- func (s *AutoCommitStrategy) ValidateRepository() error
- type Checkpoint
- type CheckpointDetails
- type CheckpointInfo
- type CleanupItem
- type CleanupResult
- type CleanupType
- type CommitMsgHandler
- type ConcurrentSessionChecker
- type CondenseResult
- type ExtractedSessionData
- type Factory
- type LogsOnlyRestorer
- type ManualCommitStrategy
- func (s *ManualCommitStrategy) AllowsMainBranch() bool
- func (s *ManualCommitStrategy) CanRewind() (bool, string, error)
- func (s *ManualCommitStrategy) ClearSessionState(sessionID string) error
- func (s *ManualCommitStrategy) CommitMsg(commitMsgFile string) error
- func (s *ManualCommitStrategy) CondenseSession(repo *git.Repository, checkpointID id.CheckpointID, state *SessionState) (*CondenseResult, error)
- func (s *ManualCommitStrategy) Description() string
- func (s *ManualCommitStrategy) EnsureSetup() error
- func (s *ManualCommitStrategy) FindSessionsForCommit(baseCommitSHA string) ([]*SessionState, error)
- func (s *ManualCommitStrategy) GetAdditionalSessions() ([]*Session, error)
- func (s *ManualCommitStrategy) GetCheckpointLog(checkpoint Checkpoint) ([]byte, error)
- func (s *ManualCommitStrategy) GetLogsOnlyRewindPoints(limit int) ([]RewindPoint, error)
- func (s *ManualCommitStrategy) GetMetadataRef(checkpoint Checkpoint) string
- func (s *ManualCommitStrategy) GetRewindPoints(limit int) ([]RewindPoint, error)
- func (s *ManualCommitStrategy) GetSessionContext(sessionID string) string
- func (s *ManualCommitStrategy) GetSessionInfo() (*SessionInfo, error)
- func (s *ManualCommitStrategy) GetSessionMetadataRef(_ string) string
- func (s *ManualCommitStrategy) GetTaskCheckpoint(point RewindPoint) (*TaskCheckpoint, error)
- func (s *ManualCommitStrategy) GetTaskCheckpointTranscript(point RewindPoint) ([]byte, error)
- func (s *ManualCommitStrategy) HasOtherActiveSessionsWithCheckpoints(currentSessionID string) (*SessionState, error)
- func (s *ManualCommitStrategy) InitializeSession(sessionID string, agentType agent.AgentType, transcriptPath string) error
- func (s *ManualCommitStrategy) ListOrphanedItems() ([]CleanupItem, error)
- func (s *ManualCommitStrategy) Name() string
- func (s *ManualCommitStrategy) PostCommit() error
- func (s *ManualCommitStrategy) PrePush(remote string) error
- func (s *ManualCommitStrategy) PrepareCommitMsg(commitMsgFile string, source string) error
- func (s *ManualCommitStrategy) PreviewRewind(point RewindPoint) (*RewindPreview, error)
- func (s *ManualCommitStrategy) Reset() error
- func (s *ManualCommitStrategy) RestoreLogsOnly(point RewindPoint, force bool) error
- func (s *ManualCommitStrategy) Rewind(point RewindPoint) error
- func (s *ManualCommitStrategy) SaveChanges(ctx SaveContext) error
- func (s *ManualCommitStrategy) SaveTaskCheckpoint(ctx TaskCheckpointContext) error
- func (s *ManualCommitStrategy) ValidateRepository() error
- type OrphanedItemsLister
- type PostCommitHandler
- type PrePushHandler
- type PrepareCommitMsgHandler
- type PromptAttribution
- type PromptResponse
- type RewindPoint
- type RewindPreview
- type SaveContext
- type Session
- type SessionIDConflictError
- type SessionInfo
- type SessionInitializer
- type SessionResetter
- type SessionRestoreInfo
- type SessionRestoreStatus
- type SessionSource
- type SessionState
- type StageFilesContext
- type Strategy
- type SubagentCheckpoint
- type TaskCheckpoint
- type TaskCheckpointContext
Constants ¶
const ( StrategyNameManualCommit = "manual-commit" StrategyNameAutoCommit = "auto-commit" )
Strategy name constants
const ( // DefaultAgentType is the generic fallback agent type name DefaultAgentType = agent.AgentTypeUnknown )
const DefaultStrategyName = StrategyNameManualCommit
DefaultStrategyName is the name of the default strategy. Manual-commit is the recommended strategy for most workflows.
const MaxDescriptionLength = 60
MaxDescriptionLength is the maximum length for descriptions in commit messages before truncation occurs.
const NoDescription = "No description"
NoDescription is the default description for sessions without one.
Variables ¶
var ErrNoMetadata = errors.New("commit has no entire metadata")
ErrNoMetadata is returned when a commit does not have an Entire metadata trailer.
var ErrNoSession = errors.New("no session info available")
ErrNoSession is returned when no session info is available.
var ErrNotImplemented = errors.New("not implemented")
ErrNotImplemented is returned when a feature is not yet implemented.
var ErrNotTaskCheckpoint = errors.New("not a task checkpoint")
ErrNotTaskCheckpoint is returned when a rewind point is not a task checkpoint.
Functions ¶
func CalculateAttributionWithAccumulated ¶
func CalculateAttributionWithAccumulated( baseTree *object.Tree, shadowTree *object.Tree, headTree *object.Tree, filesTouched []string, promptAttributions []PromptAttribution, ) *checkpoint.InitialAttribution
CalculateAttributionWithAccumulated computes final attribution using accumulated prompt data. This provides more accurate attribution than tree-only comparison because it captures user edits that happened between checkpoints (which would otherwise be mixed into the checkpoint snapshots).
The calculation: 1. Sum user edits from PromptAttributions (captured at each prompt start) 2. Add user edits after the final checkpoint (shadow → head diff) 3. Calculate agent lines from base → shadow 4. Estimate user self-modifications vs agent modifications using per-file tracking 5. Compute percentages
Note: Binary files (detected by null bytes) are silently excluded from attribution calculations since line-based diffing only applies to text files.
See docs/architecture/attribution.md for details on the per-file tracking approach.
func ClearSessionState ¶
ClearSessionState removes the session state file for the given session ID.
func CountTodos ¶
CountTodos returns the number of todo items in the JSON array. Returns 0 if the JSON is invalid or empty.
func DeleteOrphanedCheckpoints ¶
func DeleteOrphanedCheckpoints(checkpointIDs []string) (deleted []string, failed []string, err error)
DeleteOrphanedCheckpoints removes checkpoint directories from the entire/sessions branch.
func DeleteOrphanedSessionStates ¶
func DeleteOrphanedSessionStates(sessionIDs []string) (deleted []string, failed []string, err error)
DeleteOrphanedSessionStates deletes the specified session state files.
func DeleteShadowBranches ¶
DeleteShadowBranches deletes the specified branches from the repository. Returns two slices: successfully deleted branches and branches that failed to delete. Individual branch deletion failures do not stop the operation - all branches are attempted. Returns an error only if the repository cannot be opened.
func EnsureEntireGitignore ¶
func EnsureEntireGitignore() error
EnsureEntireGitignore ensures all required entries are in .entire/.gitignore Works correctly from any subdirectory within the repository.
func EnsureMetadataBranch ¶
func EnsureMetadataBranch(repo *git.Repository) error
ensureMetadataBranch creates the orphan entire/sessions branch if it doesn't exist. This branch has no parent and starts with an empty tree.
func ExtractFirstPrompt ¶
ExtractFirstPrompt extracts and truncates the first meaningful prompt from prompt content. Prompts are separated by "\n\n---\n\n". Skips empty prompts and separator-only content. Returns empty string if no valid prompt is found.
func ExtractInProgressTodo ¶
ExtractInProgressTodo extracts the content of the in-progress todo item from tool_input. This is used for commit messages in incremental checkpoints.
Priority order:
- in_progress item (current work)
- first pending item (next work - fallback)
- last completed item (final work just finished)
- first item with unknown status (edge case)
- empty string (no items)
Returns empty string if no suitable item is found or JSON is invalid.
func ExtractLastCompletedTodo ¶
ExtractLastCompletedTodo extracts the content of the last completed todo item from tool_input. This represents the work that was just finished and is used for commit messages.
When TodoWrite is called in PostToolUse, the NEW list is provided which has the just-completed work marked as "completed". The last completed item is the most recently finished task.
Returns empty string if no completed items exist or JSON is invalid.
func ExtractSessionIDFromCommit ¶
ExtractSessionIDFromCommit extracts the session ID from a commit's trailers. It checks the Entire-Session trailer first, then falls back to extracting from the metadata directory path in the Entire-Metadata trailer. Returns empty string if no session ID is found.
func ExtractToolUseIDFromTaskMetadataDir ¶
ExtractToolUseIDFromTaskMetadataDir extracts the ToolUseID from a task metadata directory path. Task metadata dirs have format: .entire/metadata/<session>/tasks/<toolUseID> Returns empty string if not a task metadata directory.
func FormatIncrementalMessage ¶
FormatIncrementalMessage formats a commit message for an incremental checkpoint. Format: "<todo-content> (<tool-use-id>)"
If todoContent is empty, falls back to: "Checkpoint #<sequence>: <tool-use-id>"
func FormatIncrementalSubject ¶
func FormatIncrementalSubject( incrementalType string, subagentType string, taskDescription string, todoContent string, incrementalSequence int, shortToolUseID string, ) string
FormatIncrementalSubject formats the commit message subject for incremental checkpoints. Delegates to FormatIncrementalMessage.
Note: The incrementalType, subagentType, and taskDescription parameters are kept for API compatibility but are not currently used. They may be used in the future for different checkpoint types.
func FormatSubagentEndMessage ¶
FormatSubagentEndMessage formats a commit message for when a subagent completes. Format: "Completed '<agent-type>' agent: <description> (<tool-use-id>)"
Edge cases:
- Empty description: "Completed '<agent-type>' agent (<tool-use-id>)"
- Empty agentType: "Completed agent: <description> (<tool-use-id>)"
- Both empty: "Task: <tool-use-id>"
func GetCurrentBranchName ¶
func GetCurrentBranchName(repo *git.Repository) string
GetCurrentBranchName returns the short name of the current branch if HEAD points to a branch. Returns an empty string if in detached HEAD state or if there's an error reading HEAD. This is used to capture branch metadata for checkpoints.
func GetDefaultBranchName ¶
func GetDefaultBranchName(repo *git.Repository) string
GetDefaultBranchName returns the name of the default branch. First checks origin/HEAD, then falls back to checking if main/master exists. Returns empty string if unable to determine. NOTE: Duplicated from cli/git_operations.go - see ENT-129 for consolidation.
func GetGitAuthorFromRepo ¶
func GetGitAuthorFromRepo(repo *git.Repository) (name, email string)
GetGitAuthorFromRepo retrieves the git user.name and user.email from the repository config. It checks local config first, then falls back to global config. Returns ("Unknown", "unknown@local") if no user is configured - this allows operations to proceed even without git user config, which is especially useful for internal metadata commits on branches like entire/sessions.
func GetGitCommonDir ¶
GetGitCommonDir returns the path to the shared git directory. In a regular checkout, this is .git/ In a worktree, this is the main repo's .git/ (not .git/worktrees/<name>/) Uses git rev-parse --git-common-dir for reliable handling of worktrees.
func GetGitDir ¶
GetGitDir returns the actual git directory path by delegating to git itself. This handles both regular repositories and worktrees, and inherits git's security validation for gitdir references.
func GetMainBranchHash ¶
func GetMainBranchHash(repo *git.Repository) plumbing.Hash
getMainBranchHash returns the hash of the main branch (main or master). Returns ZeroHash if no main branch is found.
func GetMainRepoRoot ¶
GetMainRepoRoot returns the root directory of the main repository. In the main repo, this is the worktree path (repo root). In a worktree, this parses the .git file to find the main repo. This function works correctly from any subdirectory within the repository.
Per gitrepository-layout(5), a worktree's .git file is a "gitfile" containing "gitdir: <path>" pointing to $GIT_DIR/worktrees/<id> in the main repository. See: https://git-scm.com/docs/gitrepository-layout
func GetMetadataBranchTree ¶
func GetMetadataBranchTree(repo *git.Repository) (*object.Tree, error)
GetMetadataBranchTree returns the tree object for the entire/sessions branch.
func GetRemoteMetadataBranchTree ¶
func GetRemoteMetadataBranchTree(repo *git.Repository) (*object.Tree, error)
GetRemoteMetadataBranchTree returns the tree object for origin/entire/sessions.
func GetWorktreePath ¶
GetWorktreePath returns the absolute path to the current worktree root. This is the working directory path, not the git directory.
func HardResetWithProtection ¶
HardResetWithProtection performs a git reset --hard to the specified commit. Uses the git CLI instead of go-git because go-git's HardReset incorrectly deletes untracked directories (like .entire/) even when they're in .gitignore. Returns the short commit ID (7 chars) on success for display purposes.
func InstallGitHook ¶
InstallGitHook installs generic git hooks that delegate to `entire hook` commands. These hooks work with any strategy - the strategy is determined at runtime. If silent is true, no output is printed. Returns the number of hooks that were installed (0 if all already up to date).
func IsAncestorOf ¶
func IsAncestorOf(repo *git.Repository, commit, target plumbing.Hash) bool
IsAncestorOf checks if commit is an ancestor of (or equal to) target. Returns true if target can reach commit by following parent links. Limits search to 1000 commits to avoid excessive traversal.
func IsGitHookInstalled ¶
func IsGitHookInstalled() bool
IsGitHookInstalled checks if all generic Entire CLI hooks are installed.
func IsInsideWorktree ¶
func IsInsideWorktree() bool
IsInsideWorktree returns true if the current directory is inside a git worktree (as opposed to the main repository). Worktrees have .git as a file pointing to the main repo, while the main repo has .git as a directory. This function works correctly from any subdirectory within the repository.
func IsOnDefaultBranch ¶
func IsOnDefaultBranch(repo *git.Repository) (bool, string)
IsOnDefaultBranch checks if the repository HEAD is on the default branch. Returns (isOnDefault, currentBranchName). NOTE: Duplicated from cli/git_operations.go - see ENT-129 for consolidation.
func IsShadowBranch ¶
IsShadowBranch returns true if the branch name matches the shadow branch pattern. Shadow branches have the format "entire/<commit-hash>-<worktree-hash>" where the commit hash is at least 7 hex characters and worktree hash is 6 hex characters. The "entire/sessions/v1" branch is NOT a shadow branch.
func ListShadowBranches ¶
ListShadowBranches returns all shadow branches in the repository. Shadow branches match the pattern "entire/<commit-hash>" (7+ hex chars). The "entire/sessions/v1" branch is excluded as it stores permanent metadata. Returns an empty slice (not nil) if no shadow branches exist.
func OpenRepository ¶
func OpenRepository() (*git.Repository, error)
OpenRepository opens the git repository with linked worktree support enabled. It uses git.PlainOpenWithOptions with EnableDotGitCommonDir set to true, which is required for proper operation in git worktrees created via 'git worktree add'.
Without EnableDotGitCommonDir, go-git operations in worktrees can silently fail: - Commits appear to succeed but are not persisted - Refs are written to incorrect locations - The worktree's HEAD/index don't get updated properly
This happens because worktrees use .git as a file (pointing to the main repo) rather than a directory, and go-git needs to route paths correctly between shared (.git/) and per-worktree (.git/worktrees/<name>/) locations.
The function first uses 'git rev-parse --show-toplevel' to find the repository root, which works correctly even when called from a subdirectory within the repo.
func PromptOverwriteNewerLogs ¶
func PromptOverwriteNewerLogs(sessions []SessionRestoreInfo) (bool, error)
PromptOverwriteNewerLogs asks the user for confirmation to overwrite local session logs that have newer timestamps than the checkpoint versions.
func ReadAllSessionPromptsFromTree ¶
func ReadAllSessionPromptsFromTree(tree *object.Tree, checkpointPath string, sessionCount int, sessionIDs []string) []string
ReadAllSessionPromptsFromTree reads the first prompt for all sessions in a multi-session checkpoint. Returns a slice of prompts parallel to sessionIDs (oldest to newest). For single-session checkpoints, returns a slice with just the root prompt.
func ReadSessionPromptFromShadow ¶
func ReadSessionPromptFromShadow(repo *git.Repository, baseCommit, worktreeID, sessionID string) string
ReadSessionPromptFromShadow reads the first prompt for a session from the shadow branch. Returns an empty string if the prompt cannot be read.
func ReadSessionPromptFromTree ¶
ReadSessionPromptFromTree reads the first meaningful prompt from a checkpoint's prompt.txt file in a git tree. Returns an empty string if the prompt cannot be read.
func Register ¶
Register adds a strategy factory to the registry. This is typically called from init() functions in strategy implementations.
func RemoveGitHook ¶
RemoveGitHook removes all Entire CLI git hooks from the repository. Returns the number of hooks removed.
func SaveSessionState ¶
func SaveSessionState(state *SessionState) error
SaveSessionState saves the session state atomically.
func StageFiles ¶
func StageFiles(worktree *git.Worktree, modified, newFiles, deleted []string, stageCtx StageFilesContext)
StageFiles stages modified, new, and deleted files to the git worktree.
This function handles three categories of file changes:
- Modified files: existing files that have been changed
- New files: files that were created during the session
- Deleted files: files that were removed during the session
Error Handling Strategy:
- Individual file staging errors are logged to stderr but don't fail the operation
- This ensures that partial staging succeeds even if some files have issues
- If a modified file no longer exists, it's treated as a deletion
The stageCtx parameter is used for user-facing messages to indicate whether this is staging for a session checkpoint or a task checkpoint.
func StatusToText ¶
func StatusToText(status SessionRestoreStatus) string
StatusToText returns a human-readable status string.
func TaskMetadataDir ¶
TaskMetadataDir returns the path to a task's metadata directory within the session metadata directory.
func TruncateDescription ¶
TruncateDescription truncates a string to maxLen characters, adding "..." if truncated. If maxLen is less than 3, returns a string of dots up to maxLen.
Types ¶
type AutoCommitStrategy ¶
type AutoCommitStrategy struct {
// contains filtered or unexported fields
}
AutoCommitStrategy implements the auto-commit strategy: - Code changes are committed to the active branch (like commit strategy) - Session logs are committed to a shadow branch (like manual-commit strategy) - Code commits can reference the shadow branch via trailers
func (*AutoCommitStrategy) AllowsMainBranch ¶
func (s *AutoCommitStrategy) AllowsMainBranch() bool
AllowsMainBranch returns true to allow auto-commit strategy on main branch. The strategy creates clean commits with Entire-Checkpoint trailers, and detailed metadata is stored on the separate entire/sessions orphan branch.
func (*AutoCommitStrategy) CanRewind ¶
func (s *AutoCommitStrategy) CanRewind() (bool, string, error)
func (*AutoCommitStrategy) Description ¶
func (s *AutoCommitStrategy) Description() string
func (*AutoCommitStrategy) EnsureSetup ¶
func (s *AutoCommitStrategy) EnsureSetup() error
EnsureSetup ensures the strategy's required setup is in place. For auto-commit strategy: - Ensure .entire/.gitignore has all required entries - Create orphan entire/sessions branch if it doesn't exist
func (*AutoCommitStrategy) GetCheckpointLog ¶
func (s *AutoCommitStrategy) GetCheckpointLog(cp Checkpoint) ([]byte, error)
GetCheckpointLog returns the session transcript for a specific checkpoint. For auto-commit strategy, looks up checkpoint by ID on the entire/sessions branch using the checkpoint store.
func (*AutoCommitStrategy) GetMetadataRef ¶
func (s *AutoCommitStrategy) GetMetadataRef(checkpoint Checkpoint) string
GetMetadataRef returns a reference to the metadata for the given checkpoint. For auto-commit strategy, returns the checkpoint path on entire/sessions branch.
func (*AutoCommitStrategy) GetRewindPoints ¶
func (s *AutoCommitStrategy) GetRewindPoints(limit int) ([]RewindPoint, error)
func (*AutoCommitStrategy) GetSessionContext ¶
func (s *AutoCommitStrategy) GetSessionContext(sessionID string) string
GetSessionContext returns the context.md content for a session. For auto-commit strategy, reads from the entire/sessions branch using the checkpoint store.
func (*AutoCommitStrategy) GetSessionInfo ¶
func (s *AutoCommitStrategy) GetSessionInfo() (*SessionInfo, error)
GetSessionInfo returns session information for linking commits. For auto-commit strategy, we don't track active sessions - metadata is stored on entire/sessions branch when SaveChanges is called. Active branch commits are kept clean (no trailers), so this returns ErrNoSession. Use ListSessions() or GetSession() to retrieve session info from the metadata branch.
func (*AutoCommitStrategy) GetSessionMetadataRef ¶
func (s *AutoCommitStrategy) GetSessionMetadataRef(sessionID string) string
GetSessionMetadataRef returns a reference to the most recent metadata for a session.
func (*AutoCommitStrategy) GetTaskCheckpoint ¶
func (s *AutoCommitStrategy) GetTaskCheckpoint(point RewindPoint) (*TaskCheckpoint, error)
GetTaskCheckpoint returns the task checkpoint for a given rewind point. For auto-commit strategy, checkpoints are stored on the entire/sessions branch in checkpoint directories. Returns ErrNotTaskCheckpoint if the point is not a task checkpoint.
func (*AutoCommitStrategy) GetTaskCheckpointTranscript ¶
func (s *AutoCommitStrategy) GetTaskCheckpointTranscript(point RewindPoint) ([]byte, error)
GetTaskCheckpointTranscript returns the session transcript for a task checkpoint. For auto-commit strategy, transcripts are stored on the entire/sessions branch in checkpoint directories. Returns ErrNotTaskCheckpoint if the point is not a task checkpoint.
func (*AutoCommitStrategy) InitializeSession ¶
func (s *AutoCommitStrategy) InitializeSession(sessionID string, agentType agent.AgentType, transcriptPath string) error
InitializeSession creates session state for a new session. This is called during UserPromptSubmit hook to set up tracking for the session. For auto-commit strategy, this creates a SessionState file in .git/entire-sessions/ to track CondensedTranscriptLines (transcript offset) across checkpoints. agentType is the human-readable name of the agent (e.g., "Claude Code"). transcriptPath is the path to the live transcript file (for mid-session commit detection).
func (*AutoCommitStrategy) ListOrphanedItems ¶
func (s *AutoCommitStrategy) ListOrphanedItems() ([]CleanupItem, error)
ListOrphanedItems returns orphaned items created by the auto-commit strategy. For auto-commit, checkpoints are orphaned when no commit has an Entire-Checkpoint trailer referencing them (e.g., after rebasing or squashing).
func (*AutoCommitStrategy) Name ¶
func (s *AutoCommitStrategy) Name() string
func (*AutoCommitStrategy) PrePush ¶
func (s *AutoCommitStrategy) PrePush(remote string) error
PrePush is called by the git pre-push hook before pushing to a remote. It pushes the entire/sessions branch alongside the user's push. Configuration options (stored in .entire/settings.json under strategy_options.push_sessions):
- "auto": always push automatically
- "prompt" (default): ask user with option to enable auto
- "false"/"off"/"no": never push
func (*AutoCommitStrategy) PreviewRewind ¶
func (s *AutoCommitStrategy) PreviewRewind(_ RewindPoint) (*RewindPreview, error)
PreviewRewind returns what will happen if rewinding to the given point. For auto-commit strategy, this returns nil since git reset doesn't delete untracked files.
func (*AutoCommitStrategy) Rewind ¶
func (s *AutoCommitStrategy) Rewind(point RewindPoint) error
func (*AutoCommitStrategy) SaveChanges ¶
func (s *AutoCommitStrategy) SaveChanges(ctx SaveContext) error
func (*AutoCommitStrategy) SaveTaskCheckpoint ¶
func (s *AutoCommitStrategy) SaveTaskCheckpoint(ctx TaskCheckpointContext) error
SaveTaskCheckpoint creates a checkpoint commit for a completed task. For auto-commit strategy: 1. Commit code changes to active branch (no trailers - clean history) 2. Commit task metadata to entire/sessions branch with checkpoint format
func (*AutoCommitStrategy) ValidateRepository ¶
func (s *AutoCommitStrategy) ValidateRepository() error
type Checkpoint ¶
type Checkpoint struct {
// CheckpointID is the stable 12-hex-char identifier for this checkpoint.
// Used to look up metadata at <id[:2]>/<id[2:]>/ on entire/sessions branch.
CheckpointID id.CheckpointID
// Message is the commit message or checkpoint description
Message string
// Timestamp is when this checkpoint was created
Timestamp time.Time
// IsTaskCheckpoint indicates if this is a task checkpoint (vs a session checkpoint)
IsTaskCheckpoint bool
// ToolUseID is the tool use ID for task checkpoints (empty for session checkpoints)
ToolUseID string
}
Checkpoint represents a save point within a session. Checkpoints can be either session-level (on Stop) or task-level (on subagent completion).
type CheckpointDetails ¶
type CheckpointDetails struct {
// Interactions contains all prompt/response pairs in this checkpoint.
// For strategies like auto-commit/commit, this typically has one entry.
// For strategies like shadow, this may have multiple entries.
Interactions []PromptResponse
// Files is the aggregate list of all files modified in this checkpoint.
// This is a convenience field that combines files from all interactions.
Files []string
}
CheckpointDetails contains detailed information extracted from a checkpoint's transcript. This is used by the explain command to display checkpoint content.
type CheckpointInfo ¶
type CheckpointInfo struct {
CheckpointID id.CheckpointID `json:"checkpoint_id"` // 12-hex-char from Entire-Checkpoint trailer, used as directory path
SessionID string `json:"session_id"`
CreatedAt time.Time `json:"created_at"`
CheckpointsCount int `json:"checkpoints_count"`
FilesTouched []string `json:"files_touched"`
Agent agent.AgentType `json:"agent,omitempty"` // Human-readable agent name (e.g., "Claude Code")
IsTask bool `json:"is_task,omitempty"`
ToolUseID string `json:"tool_use_id,omitempty"`
SessionCount int `json:"session_count,omitempty"` // Number of sessions (1 if omitted)
SessionIDs []string `json:"session_ids,omitempty"` // All session IDs in this checkpoint
}
CheckpointInfo represents checkpoint metadata stored on the sessions branch. Metadata is stored at sharded path: <checkpoint_id[:2]>/<checkpoint_id[2:]>/
func ListCheckpoints ¶
func ListCheckpoints() ([]CheckpointInfo, error)
ListCheckpoints returns all checkpoints from the entire/sessions branch. Scans sharded paths: <id[:2]>/<id[2:]>/ directories containing metadata.json. Used by both manual-commit and auto-commit strategies.
func ReadCheckpointMetadata ¶
func ReadCheckpointMetadata(tree *object.Tree, checkpointPath string) (*CheckpointInfo, error)
readCheckpointMetadata reads metadata.json from a checkpoint path on entire/sessions. With the new format, root metadata.json is a CheckpointSummary with Agents array. This function reads the summary and extracts relevant fields into CheckpointInfo, also reading session-level metadata for IsTask/ToolUseID fields.
type CleanupItem ¶
type CleanupItem struct {
Type CleanupType
ID string // Branch name, session ID, or checkpoint ID
Reason string // Why this item is considered orphaned
}
CleanupItem represents an orphaned item that can be cleaned up.
func ListAllCleanupItems ¶
func ListAllCleanupItems() ([]CleanupItem, error)
ListAllCleanupItems returns all orphaned items across all categories. It iterates over all registered strategies and calls ListOrphanedItems on those that implement OrphanedItemsLister. Returns an error if the repository cannot be opened.
func ListOrphanedSessionStates ¶
func ListOrphanedSessionStates() ([]CleanupItem, error)
ListOrphanedSessionStates returns session state files that are orphaned. A session state is orphaned if:
- No checkpoints on entire/sessions reference this session ID
- No shadow branch exists for the session's base commit
This is strategy-agnostic as session states are shared by all strategies.
type CleanupResult ¶
type CleanupResult struct {
ShadowBranches []string // Deleted shadow branches
SessionStates []string // Deleted session state files
Checkpoints []string // Deleted checkpoint metadata
FailedBranches []string // Shadow branches that failed to delete
FailedStates []string // Session states that failed to delete
FailedCheckpoints []string // Checkpoints that failed to delete
}
CleanupResult contains the results of a cleanup operation.
func DeleteAllCleanupItems ¶
func DeleteAllCleanupItems(items []CleanupItem) (*CleanupResult, error)
DeleteAllCleanupItems deletes all specified cleanup items. Logs each deletion for audit purposes.
type CleanupType ¶
type CleanupType string
CleanupType identifies the type of orphaned item.
const ( CleanupTypeShadowBranch CleanupType = "shadow-branch" CleanupTypeSessionState CleanupType = "session-state" CleanupTypeCheckpoint CleanupType = "checkpoint" )
type CommitMsgHandler ¶
type CommitMsgHandler interface {
// CommitMsg is called by the git commit-msg hook after the user edits the message.
// Used to validate or modify the final commit message before the commit is created.
// If this returns an error, the commit is aborted.
CommitMsg(commitMsgFile string) error
}
CommitMsgHandler is an optional interface for strategies that need to handle the git commit-msg hook.
type ConcurrentSessionChecker ¶
type ConcurrentSessionChecker interface {
// HasOtherActiveSessionsWithCheckpoints returns a session state if there's another
// active session with uncommitted checkpoints on the same base commit.
// Returns nil, nil if no such session exists.
HasOtherActiveSessionsWithCheckpoints(currentSessionID string) (*SessionState, error)
}
ConcurrentSessionChecker is an optional interface for strategies that support detecting and warning about concurrent sessions with uncommitted changes. This is used by the UserPromptSubmit hook to block the first prompt when another session has uncommitted checkpoints on the same base commit.
type CondenseResult ¶
type CondenseResult struct {
CheckpointID id.CheckpointID // 12-hex-char from Entire-Checkpoint trailer, used as directory path
SessionID string
CheckpointsCount int
FilesTouched []string
TotalTranscriptLines int // Total lines in transcript after this condensation
}
CondenseResult contains the result of a session condensation operation.
type ExtractedSessionData ¶
type ExtractedSessionData struct {
Transcript []byte // Full transcript content for the session
FullTranscriptLines int // Total line count in full transcript
Prompts []string // All user prompts from this portion
Context []byte // Generated context.md content
FilesTouched []string
TokenUsage *agent.TokenUsage // Token usage calculated from transcript (since TranscriptLinesAtStart)
}
ExtractedSessionData contains data extracted from a shadow branch.
type LogsOnlyRestorer ¶
type LogsOnlyRestorer interface {
// RestoreLogsOnly restores session logs from a logs-only rewind point.
// Does not modify the working directory - only restores the transcript
// to Claude's project directory.
// If force is false, prompts for confirmation when local logs have newer timestamps.
RestoreLogsOnly(point RewindPoint, force bool) error
}
LogsOnlyRestorer is an optional interface for strategies that support restoring session logs without file state restoration. This is used for "logs-only" rewind points where only the session transcript can be restored (file state requires git checkout).
type ManualCommitStrategy ¶
type ManualCommitStrategy struct {
// contains filtered or unexported fields
}
ManualCommitStrategy implements the manual-commit strategy for session management. It stores checkpoints on shadow branches and condenses session logs to a permanent sessions branch when the user commits.
func (*ManualCommitStrategy) AllowsMainBranch ¶
func (s *ManualCommitStrategy) AllowsMainBranch() bool
AllowsMainBranch returns true because manual-commit strategy only writes to shadow branches (entire/<hash>) and entire/sessions, never modifying the working branch's commit history.
func (*ManualCommitStrategy) CanRewind ¶
func (s *ManualCommitStrategy) CanRewind() (bool, string, error)
CanRewind checks if rewinding is possible. For manual-commit strategy, rewind restores files from a checkpoint - uncommitted changes are expected and will be replaced by the checkpoint contents. Returns true with a warning message showing what changes will be reverted.
func (*ManualCommitStrategy) ClearSessionState ¶
func (s *ManualCommitStrategy) ClearSessionState(sessionID string) error
ClearSessionState is the exported version of clearSessionState. Used by the rewind reset command to clean up session state files.
func (*ManualCommitStrategy) CommitMsg ¶
func (s *ManualCommitStrategy) CommitMsg(commitMsgFile string) error
CommitMsg is called by the git commit-msg hook after the user edits the message. If the message contains only our trailer (no actual user content), strip it so git will abort the commit due to empty message.
func (*ManualCommitStrategy) CondenseSession ¶
func (s *ManualCommitStrategy) CondenseSession(repo *git.Repository, checkpointID id.CheckpointID, state *SessionState) (*CondenseResult, error)
CondenseSession condenses a session's shadow branch to permanent storage. checkpointID is the 12-hex-char value from the Entire-Checkpoint trailer. Metadata is stored at sharded path: <checkpoint_id[:2]>/<checkpoint_id[2:]>/ Uses checkpoint.GitStore.WriteCommitted for the git operations.
func (*ManualCommitStrategy) Description ¶
func (s *ManualCommitStrategy) Description() string
Description returns the strategy description.
func (*ManualCommitStrategy) EnsureSetup ¶
func (s *ManualCommitStrategy) EnsureSetup() error
EnsureSetup ensures the strategy is properly set up.
func (*ManualCommitStrategy) FindSessionsForCommit ¶
func (s *ManualCommitStrategy) FindSessionsForCommit(baseCommitSHA string) ([]*SessionState, error)
FindSessionsForCommit is the exported version of findSessionsForCommit. Used by the rewind reset command to find sessions to clean up.
func (*ManualCommitStrategy) GetAdditionalSessions ¶
func (s *ManualCommitStrategy) GetAdditionalSessions() ([]*Session, error)
GetAdditionalSessions implements SessionSource interface. Returns active sessions from .git/entire-sessions/ that haven't yet been condensed.
func (*ManualCommitStrategy) GetCheckpointLog ¶
func (s *ManualCommitStrategy) GetCheckpointLog(checkpoint Checkpoint) ([]byte, error)
GetCheckpointLog returns the session transcript for a specific checkpoint. For manual-commit strategy, metadata is stored at sharded paths on entire/sessions branch.
func (*ManualCommitStrategy) GetLogsOnlyRewindPoints ¶
func (s *ManualCommitStrategy) GetLogsOnlyRewindPoints(limit int) ([]RewindPoint, error)
GetLogsOnlyRewindPoints finds commits in the current branch's history that have condensed session logs on the entire/sessions branch. These are commits that were created with session data but the shadow branch has been condensed.
The function works by: 1. Getting all checkpoints from the entire/sessions branch 2. Building a map of checkpoint ID -> checkpoint info 3. Scanning the current branch history for commits with Entire-Checkpoint trailers 4. Matching by checkpoint ID (stable across amend/rebase)
func (*ManualCommitStrategy) GetMetadataRef ¶
func (s *ManualCommitStrategy) GetMetadataRef(checkpoint Checkpoint) string
GetMetadataRef returns a reference to the metadata for the given checkpoint. For manual-commit strategy, returns the sharded path on entire/sessions branch.
func (*ManualCommitStrategy) GetRewindPoints ¶
func (s *ManualCommitStrategy) GetRewindPoints(limit int) ([]RewindPoint, error)
GetRewindPoints returns available rewind points. Uses checkpoint.GitStore.ListTemporaryCheckpoints for reading from shadow branches.
func (*ManualCommitStrategy) GetSessionContext ¶
func (s *ManualCommitStrategy) GetSessionContext(sessionID string) string
GetSessionContext returns the context.md content for a session. For manual-commit strategy, reads from the entire/sessions branch using the sessions map.
func (*ManualCommitStrategy) GetSessionInfo ¶
func (s *ManualCommitStrategy) GetSessionInfo() (*SessionInfo, error)
GetSessionInfo returns the current session info.
func (*ManualCommitStrategy) GetSessionMetadataRef ¶
func (s *ManualCommitStrategy) GetSessionMetadataRef(_ string) string
GetSessionMetadataRef returns a reference to the most recent metadata commit for a session. For manual-commit strategy, metadata lives on the entire/sessions branch.
func (*ManualCommitStrategy) GetTaskCheckpoint ¶
func (s *ManualCommitStrategy) GetTaskCheckpoint(point RewindPoint) (*TaskCheckpoint, error)
GetTaskCheckpoint retrieves a task checkpoint.
func (*ManualCommitStrategy) GetTaskCheckpointTranscript ¶
func (s *ManualCommitStrategy) GetTaskCheckpointTranscript(point RewindPoint) ([]byte, error)
GetTaskCheckpointTranscript retrieves the transcript for a task checkpoint.
func (*ManualCommitStrategy) HasOtherActiveSessionsWithCheckpoints ¶
func (s *ManualCommitStrategy) HasOtherActiveSessionsWithCheckpoints(currentSessionID string) (*SessionState, error)
HasOtherActiveSessionsWithCheckpoints checks if there are other active sessions from the SAME worktree (different from currentSessionID) that have created checkpoints on the SAME base commit (current HEAD). This is used to detect concurrent sessions in different terminals but same directory. Returns the first found session with CheckpointCount > 0, or nil if none found.
func (*ManualCommitStrategy) InitializeSession ¶
func (s *ManualCommitStrategy) InitializeSession(sessionID string, agentType agent.AgentType, transcriptPath string) error
InitializeSession creates session state for a new session or updates an existing one. This implements the optional SessionInitializer interface. Called during UserPromptSubmit to allow git hooks to detect active sessions.
If the session already exists and HEAD has moved (e.g., user committed), updates BaseCommit to the new HEAD so future checkpoints go to the correct shadow branch.
If there's an existing shadow branch with commits from a different session ID, returns a SessionIDConflictError to prevent orphaning existing session work.
agentType is the human-readable name of the agent (e.g., "Claude Code"). transcriptPath is the path to the live transcript file (for mid-session commit detection).
func (*ManualCommitStrategy) ListOrphanedItems ¶
func (s *ManualCommitStrategy) ListOrphanedItems() ([]CleanupItem, error)
ListOrphanedItems returns orphaned items created by the manual-commit strategy. This includes:
- Shadow branches that weren't auto-cleaned during commit condensation
- Session state files with no corresponding checkpoints or shadow branches
func (*ManualCommitStrategy) Name ¶
func (s *ManualCommitStrategy) Name() string
Name returns the strategy name.
func (*ManualCommitStrategy) PostCommit ¶
func (s *ManualCommitStrategy) PostCommit() error
PostCommit is called by the git post-commit hook after a commit is created. Checks if the commit has an Entire-Checkpoint trailer and if so, condenses session data from shadow branches to entire/sessions. If the user removed the trailer during commit message editing, this is treated as a "manual" commit and no condensation happens.
func (*ManualCommitStrategy) PrePush ¶
func (s *ManualCommitStrategy) PrePush(remote string) error
PrePush is called by the git pre-push hook before pushing to a remote. It pushes the entire/sessions branch alongside the user's push. Configuration options (stored in .entire/settings.json under strategy_options.push_sessions):
- "auto": always push automatically
- "prompt" (default): ask user with option to enable auto
- "false"/"off"/"no": never push
func (*ManualCommitStrategy) PrepareCommitMsg ¶
func (s *ManualCommitStrategy) PrepareCommitMsg(commitMsgFile string, source string) error
func (*ManualCommitStrategy) PreviewRewind ¶
func (s *ManualCommitStrategy) PreviewRewind(point RewindPoint) (*RewindPreview, error)
PreviewRewind returns what will happen if rewinding to the given point. This allows showing warnings about untracked files that will be deleted.
func (*ManualCommitStrategy) Reset ¶
func (s *ManualCommitStrategy) Reset() error
Reset deletes the shadow branch and session state for the current HEAD. This allows starting fresh without existing checkpoints.
func (*ManualCommitStrategy) RestoreLogsOnly ¶
func (s *ManualCommitStrategy) RestoreLogsOnly(point RewindPoint, force bool) error
RestoreLogsOnly restores session logs from a logs-only rewind point. This fetches the transcript from entire/sessions and writes it to Claude's project directory. Does not modify the working directory. When multiple sessions were condensed to the same checkpoint, ALL sessions are restored. If force is false, prompts for confirmation when local logs have newer timestamps.
func (*ManualCommitStrategy) Rewind ¶
func (s *ManualCommitStrategy) Rewind(point RewindPoint) error
Rewind restores the working directory to a checkpoint.
func (*ManualCommitStrategy) SaveChanges ¶
func (s *ManualCommitStrategy) SaveChanges(ctx SaveContext) error
SaveChanges saves a checkpoint to the shadow branch. Uses checkpoint.GitStore.WriteTemporary for git operations.
func (*ManualCommitStrategy) SaveTaskCheckpoint ¶
func (s *ManualCommitStrategy) SaveTaskCheckpoint(ctx TaskCheckpointContext) error
SaveTaskCheckpoint saves a task checkpoint to the shadow branch. Uses checkpoint.GitStore.WriteTemporaryTask for git operations.
func (*ManualCommitStrategy) ValidateRepository ¶
func (s *ManualCommitStrategy) ValidateRepository() error
ValidateRepository validates that the repository is suitable for this strategy.
type OrphanedItemsLister ¶
type OrphanedItemsLister interface {
// ListOrphanedItems returns items created by this strategy that are now orphaned.
// Each strategy defines what "orphaned" means for its own data structures.
ListOrphanedItems() ([]CleanupItem, error)
}
OrphanedItemsLister is an optional interface for strategies that can identify orphaned items (shadow branches, session states, checkpoints) that should be cleaned up. This is used by the "entire session cleanup" command.
ListAllCleanupItems() automatically discovers all registered strategies, checks if they implement OrphanedItemsLister, and combines their orphaned items.
type PostCommitHandler ¶
type PostCommitHandler interface {
// PostCommit is called by the git post-commit hook after a commit is created.
// Used to perform actions like condensing session data after commits.
// Should return nil on errors to not block subsequent operations (log warnings to stderr).
PostCommit() error
}
PostCommitHandler is an optional interface for strategies that need to handle the git post-commit hook.
type PrePushHandler ¶
type PrePushHandler interface {
// PrePush is called by the git pre-push hook before pushing to a remote.
// Used to push session branches (e.g., entire/sessions) alongside user pushes.
// The remote parameter is the name of the remote being pushed to.
// Should return nil on errors to not block pushes (log warnings to stderr).
PrePush(remote string) error
}
PrePushHandler is an optional interface for strategies that need to handle the git pre-push hook.
type PrepareCommitMsgHandler ¶
type PrepareCommitMsgHandler interface {
// PrepareCommitMsg is called by the git prepare-commit-msg hook.
// It can modify the commit message file to add trailers, etc.
// The source parameter indicates how the commit was initiated:
// - "" or "template": normal editor flow
// - "message": using -m or -F flag
// - "merge": merge commit
// - "squash": squash merge
// - "commit": amend with -c/-C
// Should return nil on errors to not block commits (log warnings to stderr).
PrepareCommitMsg(commitMsgFile string, source string) error
}
PrepareCommitMsgHandler is an optional interface for strategies that need to handle the git prepare-commit-msg hook.
type PromptAttribution ¶
type PromptAttribution struct {
CheckpointNumber int `json:"checkpoint_number"`
UserLinesAdded int `json:"user_lines_added"`
UserLinesRemoved int `json:"user_lines_removed"`
AgentLinesAdded int `json:"agent_lines_added"` // Always 0 for checkpoint 1 (no previous checkpoint)
AgentLinesRemoved int `json:"agent_lines_removed"` // Always 0 for checkpoint 1 (no previous checkpoint)
UserAddedPerFile map[string]int `json:"user_added_per_file,omitempty"` // Per-file user additions for modification tracking
}
PromptAttribution captures line-level attribution data at the start of each prompt, calculated BEFORE the agent runs. This allows us to separate user edits (made between prompts) from agent edits (made during prompt execution).
Fields:
- CheckpointNumber: Which checkpoint this attribution is for (1-indexed)
- UserLinesAdded/Removed: User edits since the last checkpoint (lastCheckpoint → worktree)
- AgentLinesAdded/Removed: Cumulative agent work so far (base → lastCheckpoint)
- UserAddedPerFile: Per-file breakdown of user additions (for accurate modification tracking)
Note: For checkpoint 1, AgentLinesAdded/Removed are always 0 because there is no previous checkpoint to compare against. This doesn't mean the agent hasn't done work yet - it means we can't measure cumulative agent work until after the first checkpoint is created. These fields become meaningful starting from checkpoint 2.
UserAddedPerFile enables accurate tracking of user self-modifications. When a user modifies their own previously-added lines (not agent lines), we shouldn't subtract from the agent's contribution. See docs/architecture/attribution.md for details.
func CalculatePromptAttribution ¶
func CalculatePromptAttribution( baseTree *object.Tree, lastCheckpointTree *object.Tree, worktreeFiles map[string]string, checkpointNumber int, ) PromptAttribution
CalculatePromptAttribution computes line-level attribution at the start of a prompt. This captures user edits since the last checkpoint BEFORE the agent makes changes.
Parameters:
- baseTree: the tree at session start (the base commit)
- lastCheckpointTree: the tree from the previous checkpoint (nil if first checkpoint)
- worktreeFiles: map of file path → current worktree content for files that changed
- checkpointNumber: which checkpoint we're about to create (1-indexed)
Returns the attribution data to store in session state. For checkpoint 1 (when lastCheckpointTree is nil), AgentLinesAdded/Removed will be 0 since there's no previous checkpoint to measure cumulative agent work against.
Note: Binary files (detected by null bytes) in reference trees are silently excluded from attribution calculations since line-based diffing only applies to text files.
type PromptResponse ¶
type PromptResponse struct {
// Prompt is the user's message
Prompt string
// Response is the assistant's response
Response string
// Files is the list of files modified during this prompt/response
Files []string
}
PromptResponse represents a single user prompt and assistant response pair.
type RewindPoint ¶
type RewindPoint struct {
// ID is the unique identifier for this rewind point
// (commit hash, branch name, stash ref, etc.)
ID string
// Message is the human-readable description/summary
Message string
// MetadataDir is the path to the metadata directory
MetadataDir string
// Date is when this rewind point was created
Date time.Time
// IsTaskCheckpoint indicates if this is a task checkpoint (vs a session checkpoint)
IsTaskCheckpoint bool
// ToolUseID is the tool use ID for task checkpoints (empty for session checkpoints)
ToolUseID string
// IsLogsOnly indicates this is a commit with session logs but no shadow branch state.
// The logs can be restored from entire/sessions, but file state requires git checkout.
IsLogsOnly bool
// CheckpointID is the stable 12-hex-char identifier for logs-only points.
// Used to retrieve logs from entire/sessions/<id[:2]>/<id[2:]>/full.jsonl
// Empty for shadow branch checkpoints (uncommitted).
CheckpointID id.CheckpointID
// Agent is the human-readable name of the agent that created this checkpoint
// (e.g., "Claude Code", "Cursor")
Agent agent.AgentType
// SessionID is the session identifier for this checkpoint.
// Used to distinguish checkpoints from different concurrent sessions.
SessionID string
// SessionPrompt is the initial prompt that started this session.
// Used to help users identify which session a checkpoint belongs to.
SessionPrompt string
// SessionCount is the number of sessions in this checkpoint (1 for single-session).
// Only populated for logs-only points with multi-session checkpoints.
SessionCount int
// SessionIDs contains all session IDs when this is a multi-session checkpoint.
// The last entry is the most recent session (same as SessionID).
// Only populated for logs-only points with multi-session checkpoints.
SessionIDs []string
// SessionPrompts contains the first prompt for each session (parallel to SessionIDs).
// Used to display context when showing resume commands for multi-session checkpoints.
SessionPrompts []string
}
RewindPoint represents a point to which the user can rewind. This abstraction allows different strategies to use different identifiers (commit hashes, branch names, stash refs, etc.)
type RewindPreview ¶
type RewindPreview struct {
// FilesToRestore are files from the checkpoint that will be written/restored.
FilesToRestore []string
// FilesToDelete are untracked files that will be removed.
// These are files created after the checkpoint that aren't in the checkpoint tree
// and weren't present at session start.
FilesToDelete []string
// TrackedChanges are tracked files with uncommitted changes that will be reverted.
// These come from the existing CanRewind() warning.
TrackedChanges []string
}
RewindPreview describes what will happen when rewinding to a checkpoint. Used to warn users about files that will be modified or deleted.
type SaveContext ¶
type SaveContext struct {
// SessionID is the Claude Code session identifier
SessionID string
// ModifiedFiles is the list of files modified during the session
// (extracted from the transcript, already filtered and relative)
ModifiedFiles []string
// NewFiles is the list of new files created during the session
// (pre-computed by CLI from pre-prompt state comparison)
NewFiles []string
// DeletedFiles is the list of files deleted during the session
// (tracked files that no longer exist)
DeletedFiles []string
// MetadataDir is the path to the session metadata directory
MetadataDir string
// MetadataDirAbs is the absolute path to the session metadata directory
MetadataDirAbs string
// CommitMessage is the generated commit message
CommitMessage string
// TranscriptPath is the path to the transcript file
TranscriptPath string
// AuthorName is the name to use for commits
AuthorName string
// AuthorEmail is the email to use for commits
AuthorEmail string
// AgentType is the human-readable agent name (e.g., "Claude Code", "Cursor")
AgentType agent.AgentType
// Transcript position at checkpoint start - tracks what was added during this checkpoint
TranscriptIdentifierAtStart string // Last identifier when checkpoint started (UUID for Claude, message ID for Gemini)
TranscriptLinesAtStart int // Line count when checkpoint started
// TokenUsage contains the token usage for this checkpoint
TokenUsage *agent.TokenUsage
}
SaveContext contains all information needed for saving changes. All file paths should be pre-filtered and normalized by the CLI layer.
type Session ¶
type Session struct {
// ID is the unique session identifier (e.g., "2025-12-01-8f76b0e8-b8f1-4a87-9186-848bdd83d62e")
ID string
// Description is a human-readable summary of the session
// (typically the first prompt or derived from commit messages)
Description string
// Strategy is the name of the strategy that created this session
Strategy string
// StartTime is when the session was started
StartTime time.Time
// Checkpoints is the list of save points within this session
Checkpoints []Checkpoint
}
Session represents a Claude Code session with its checkpoints. A session is created when a user runs `claude` and tracks all changes made during that interaction.
func GetSession ¶
GetSession finds a session by ID (supports prefix matching). Returns ErrNoSession if no matching session is found.
func ListSessions ¶
ListSessions returns all sessions from the entire/sessions branch, plus any additional sessions from strategies implementing SessionSource. It automatically discovers all registered strategies and merges their sessions.
type SessionIDConflictError ¶
type SessionIDConflictError struct {
ExistingSession string // Session ID found in the shadow branch
NewSession string // Session ID being initialized
ShadowBranch string // The shadow branch name (e.g., "entire/abc1234")
}
SessionIDConflictError is returned when trying to start a new session but the shadow branch already has commits from a different session ID. This prevents orphaning existing session work.
func (*SessionIDConflictError) Error ¶
func (e *SessionIDConflictError) Error() string
type SessionInfo ¶
type SessionInfo struct {
// SessionID is the session identifier extracted from the latest commit's metadata
SessionID string
// Reference is a strategy-specific reference string.
// For manual-commit strategy: "entire/abc1234" (the shadow branch name)
// Empty for commit strategy (metadata is in the same commit).
Reference string
// CommitHash is the full SHA of the commit containing the session metadata.
// Empty for commit strategy.
CommitHash string
}
SessionInfo contains information about the current session state. This is used to generate trailers for linking commits to their AI session.
type SessionInitializer ¶
type SessionInitializer interface {
// InitializeSession creates session state for a new session.
// Called during UserPromptSubmit hook before any checkpoints are created.
// agentType is the human-readable name of the agent (e.g., "Claude Code").
// transcriptPath is the path to the live transcript file (for mid-session commit detection).
InitializeSession(sessionID string, agentType agent.AgentType, transcriptPath string) error
}
SessionInitializer is an optional interface for strategies that need to initialize session state when a user prompt is submitted. Strategies like manual-commit use this to create session state files that the git prepare-commit-msg hook can detect.
type SessionResetter ¶
type SessionResetter interface {
// Reset deletes the shadow branch and session state for the current HEAD.
// Returns nil if there's nothing to reset (no shadow branch).
Reset() error
}
SessionResetter is an optional interface for strategies that support resetting session state and shadow branches. This is used by the "rewind reset" command to clean up shadow branches and session state when a user wants to start fresh.
type SessionRestoreInfo ¶
type SessionRestoreInfo struct {
SessionID string
Prompt string // First prompt preview for display
Status SessionRestoreStatus // Status of this session
LocalTime time.Time
CheckpointTime time.Time
}
SessionRestoreInfo contains information about a session being restored.
type SessionRestoreStatus ¶
type SessionRestoreStatus int
SessionRestoreStatus represents the status of a session being restored.
const ( StatusNew SessionRestoreStatus = iota // Local file doesn't exist StatusUnchanged // Local and checkpoint are the same StatusCheckpointNewer // Checkpoint has newer entries StatusLocalNewer // Local has newer entries (conflict) )
func ClassifyTimestamps ¶
func ClassifyTimestamps(localTime, checkpointTime time.Time) SessionRestoreStatus
ClassifyTimestamps determines the restore status based on local and checkpoint timestamps.
type SessionSource ¶
type SessionSource interface {
// GetAdditionalSessions returns sessions not yet on entire/sessions branch.
GetAdditionalSessions() ([]*Session, error)
}
SessionSource is an optional interface for strategies that provide additional sessions beyond those stored on the entire/sessions branch. For example, manual-commit strategy provides active sessions from .git/entire-sessions/ that haven't yet been condensed to entire/sessions.
ListSessions() automatically discovers all registered strategies, checks if they implement SessionSource, and merges their additional sessions by ID.
type SessionState ¶
type SessionState struct {
SessionID string `json:"session_id"`
BaseCommit string `json:"base_commit"`
WorktreePath string `json:"worktree_path,omitempty"` // Absolute path to the worktree root
WorktreeID string `json:"worktree_id,omitempty"` // Internal git worktree identifier (empty for main worktree)
StartedAt time.Time `json:"started_at"`
EndedAt *time.Time `json:"ended_at,omitempty"` // When the session was explicitly closed (nil = active or unclean exit)
CheckpointCount int `json:"checkpoint_count"`
CondensedTranscriptLines int `json:"condensed_transcript_lines,omitempty"` // Lines already included in previous condensation
UntrackedFilesAtStart []string `json:"untracked_files_at_start,omitempty"` // Files that existed at session start (to preserve during rewind)
FilesTouched []string `json:"files_touched,omitempty"` // Files modified/created/deleted during this session
LastCheckpointID id.CheckpointID `json:"last_checkpoint_id,omitempty"` // Checkpoint ID from last condensation, reused for subsequent commits without new content
AgentType agent.AgentType `json:"agent_type,omitempty"` // Agent type identifier (e.g., "Claude Code", "Cursor")
TranscriptPath string `json:"transcript_path,omitempty"` // Path to the live transcript file (for mid-session commit detection)
// Token usage tracking (accumulated across all checkpoints in this session)
TokenUsage *agent.TokenUsage `json:"token_usage,omitempty"`
// Transcript position when session started (for multi-session checkpoints on entire/sessions)
TranscriptLinesAtStart int `json:"transcript_lines_at_start,omitempty"`
TranscriptIdentifierAtStart string `json:"transcript_identifier_at_start,omitempty"`
// PromptAttributions tracks user and agent line changes at each prompt start.
PromptAttributions []PromptAttribution `json:"prompt_attributions,omitempty"`
// PendingPromptAttribution holds attribution calculated at prompt start (before agent runs).
// This is moved to PromptAttributions when SaveChanges is called.
PendingPromptAttribution *PromptAttribution `json:"pending_prompt_attribution,omitempty"`
}
SessionState represents the state of an active session.
func LoadSessionState ¶
func LoadSessionState(sessionID string) (*SessionState, error)
LoadSessionState loads the session state for the given session ID. Returns (nil, nil) when session file doesn't exist (not an error condition).
type StageFilesContext ¶
type StageFilesContext string
StageFilesContext describes what type of staging operation this is (for messages).
const ( // StageForSession is used when staging files for a session checkpoint. StageForSession StageFilesContext = "session" // StageForTask is used when staging files for a task checkpoint. StageForTask StageFilesContext = "task" )
type Strategy ¶
type Strategy interface {
// Name returns the strategy identifier (e.g., "commit", "branch", "stash")
Name() string
// Description returns a human-readable description for the setup wizard
Description() string
// AllowsMainBranch returns true if this strategy can safely operate on the
// default branch (main/master). Strategies that don't modify the working
// branch's commit history (like manual-commit strategies) can return true.
// Strategies that create commits on the working branch should return false
// to prevent polluting main branch history.
AllowsMainBranch() bool
// ValidateRepository checks if the repository is in a valid state
// for this strategy to operate. Returns an error if validation fails.
ValidateRepository() error
// SaveChanges is called on Stop to save all session changes
// using this strategy's approach (commit, branch, stash, etc.)
SaveChanges(ctx SaveContext) error
// SaveTaskCheckpoint is called by PostToolUse[Task] hook when a subagent completes.
// Creates a checkpoint commit with task metadata for later rewind.
// Different strategies may handle this differently:
// - Commit strategy: commits to active branch
// - Manual-commit strategy: commits to shadow branch
// - Auto-commit strategy: commits logs to shadow only (code deferred to Stop)
SaveTaskCheckpoint(ctx TaskCheckpointContext) error
// GetRewindPoints returns available points to rewind to.
// The limit parameter controls the maximum number of points to return.
GetRewindPoints(limit int) ([]RewindPoint, error)
// Rewind restores the repository to the given rewind point.
// The metadataDir in the point is used to restore the session transcript.
Rewind(point RewindPoint) error
// CanRewind checks if rewinding is currently possible.
// Returns (canRewind, reason if not, error)
CanRewind() (bool, string, error)
// PreviewRewind returns what will happen if rewinding to the given point.
// This allows showing warnings about files that will be deleted before the rewind.
// Returns nil if preview is not supported (e.g., auto-commit strategy).
PreviewRewind(point RewindPoint) (*RewindPreview, error)
// GetTaskCheckpoint returns the task checkpoint for a given rewind point.
// For strategies that store checkpoints in git (auto-commit), this reads from the branch.
// For strategies that store checkpoints on disk (commit, manual-commit), this reads from the filesystem.
// Returns nil, nil if not a task checkpoint or checkpoint not found.
GetTaskCheckpoint(point RewindPoint) (*TaskCheckpoint, error)
// GetTaskCheckpointTranscript returns the session transcript for a task checkpoint.
// For strategies that store transcripts in git (auto-commit), this reads from the branch.
// For strategies that store transcripts on disk (commit, manual-commit), this reads from the filesystem.
GetTaskCheckpointTranscript(point RewindPoint) ([]byte, error)
// GetSessionInfo returns session information for linking commits.
// This is used by the context command to generate trailers.
// Returns ErrNoSession if no session info is available.
GetSessionInfo() (*SessionInfo, error)
// EnsureSetup ensures the strategy's required setup is in place,
// installing any missing pieces (git hooks, gitignore entries, etc.).
// Returns nil if setup is complete or was successfully installed.
EnsureSetup() error
// GetMetadataRef returns a reference to the metadata commit for the given checkpoint.
// Format: "<branch>@<commit-sha>" (e.g., "entire/sessions@abc123").
// Returns empty string if not applicable (e.g., commit strategy with filesystem metadata).
GetMetadataRef(checkpoint Checkpoint) string
// GetSessionMetadataRef returns a reference to the most recent metadata commit for a session.
// Format: "<branch>@<commit-sha>" (e.g., "entire/sessions@abc123").
// Returns empty string if not applicable or session not found.
GetSessionMetadataRef(sessionID string) string
// GetSessionContext returns the context.md content for a session.
// Returns empty string if not available.
GetSessionContext(sessionID string) string
// GetCheckpointLog returns the session transcript for a specific checkpoint.
// For strategies that store transcripts in git branches (auto-commit, manual-commit),
// this reads from the checkpoint's commit tree.
// For strategies that store on disk (commit), reads from the filesystem.
// Returns ErrNoMetadata if transcript is not available.
GetCheckpointLog(checkpoint Checkpoint) ([]byte, error)
}
Strategy defines the interface for git operation strategies. Different implementations can use commits, branches, stashes, etc.
Note: State capture (tracking untracked files before a session) is handled by the CLI layer, not the strategy. The strategy receives pre-computed file lists in SaveContext.
func Default ¶
func Default() Strategy
Default returns the default strategy. Falls back to returning nil if no strategies are registered.
func NewAutoCommitStrategy ¶
func NewAutoCommitStrategy() Strategy
func NewManualCommitStrategy ¶
func NewManualCommitStrategy() Strategy
func NewShadowStrategy ¶
func NewShadowStrategy() Strategy
type SubagentCheckpoint ¶
type SubagentCheckpoint struct {
Type string `json:"type"` // Tool name: "TodoWrite", "Edit", "Write"
ToolUseID string `json:"tool_use_id"` // The tool use ID that created this checkpoint
Timestamp time.Time `json:"timestamp"` // When the checkpoint was created
Data json.RawMessage `json:"data"` // Type-specific payload (tool_input)
}
SubagentCheckpoint represents an intermediate checkpoint created during subagent execution. These are created by PostToolUse hooks for tools like TodoWrite, Edit, Write.
type TaskCheckpoint ¶
type TaskCheckpoint struct {
SessionID string `json:"session_id"`
ToolUseID string `json:"tool_use_id"`
CheckpointUUID string `json:"checkpoint_uuid"`
AgentID string `json:"agent_id,omitempty"`
}
TaskCheckpoint contains the checkpoint information written to checkpoint.json
func ReadTaskCheckpoint ¶
func ReadTaskCheckpoint(taskMetadataDir string) (*TaskCheckpoint, error)
ReadTaskCheckpoint reads the checkpoint.json file from a task metadata directory. This is used during rewind to get the checkpoint UUID for transcript truncation.
type TaskCheckpointContext ¶
type TaskCheckpointContext struct {
// SessionID is the Claude Code session identifier
SessionID string
// ToolUseID is the unique identifier for this Task tool invocation
ToolUseID string
// AgentID is the subagent identifier (from tool_response.agentId)
AgentID string
// ModifiedFiles is the list of files modified by the subagent
// (extracted from the subagent's transcript)
ModifiedFiles []string
// NewFiles is the list of new files created by the subagent
// (computed from pre-task state comparison)
NewFiles []string
// DeletedFiles is the list of files deleted by the subagent
DeletedFiles []string
// TranscriptPath is the path to the main session transcript
TranscriptPath string
// SubagentTranscriptPath is the path to the subagent's transcript (if available)
SubagentTranscriptPath string
// CheckpointUUID is the UUID for transcript truncation when rewinding
CheckpointUUID string
// AuthorName is the name to use for commits
AuthorName string
// AuthorEmail is the email to use for commits
AuthorEmail string
// IsIncremental indicates this is an incremental checkpoint during task execution,
// not a final task completion checkpoint. When true:
// - Writes to checkpoints/NNN-{tool-use-id}.json instead of checkpoint.json
// - Skips transcript handling
// - Uses incremental commit message
IsIncremental bool
// IncrementalSequence is the checkpoint sequence number (1, 2, 3, ...)
// Only used when IsIncremental is true
IncrementalSequence int
// IncrementalType is the tool that triggered this checkpoint ("TodoWrite", "Edit", etc.)
// Only used when IsIncremental is true
IncrementalType string
// IncrementalData is the tool_input payload for this checkpoint
// Only used when IsIncremental is true
IncrementalData json.RawMessage
// SubagentType is the type of subagent (e.g., "dev", "reviewer")
// Extracted from tool_input.subagent_type in Task tool
// Used for descriptive commit messages
SubagentType string
// TaskDescription is the task description provided to the subagent
// Extracted from tool_input.description in Task tool
// Used for descriptive commit messages
TaskDescription string
// TodoContent is the content of the in-progress todo item
// Extracted from tool_input.todos where status == "in_progress"
// Used for descriptive incremental checkpoint messages
TodoContent string
// AgentType is the human-readable agent name (e.g., "Claude Code", "Cursor")
AgentType agent.AgentType
}
TaskCheckpointContext contains all information needed for saving a task checkpoint. This is called by the PostToolUse[Task] hook when a subagent completes. The strategy is responsible for creating metadata structures and storing them according to its storage approach.
Source Files
¶
- auto_commit.go
- cleanup.go
- common.go
- hooks.go
- manual_commit.go
- manual_commit_attribution.go
- manual_commit_condensation.go
- manual_commit_git.go
- manual_commit_hooks.go
- manual_commit_logs.go
- manual_commit_push.go
- manual_commit_reset.go
- manual_commit_rewind.go
- manual_commit_session.go
- manual_commit_types.go
- messages.go
- push_common.go
- registry.go
- session.go
- session_state.go
- strategy.go