Documentation
¶
Overview ¶
Package strategy provides the manual-commit strategy for managing Claude Code session changes via shadow branches and checkpoint condensation.
Index ¶
- Constants
- Variables
- func CalculateAttributionWithAccumulated(ctx context.Context, p AttributionParams) *checkpoint.InitialAttribution
- func CheckAndWarnHookManagers(ctx context.Context, w io.Writer, localDev, absolutePath bool)
- func ClaimSessionStartBanner(ctx context.Context, sessionID string) (claimed bool, err error)
- func ClearHooksDirCache()
- func ClearSessionState(ctx context.Context, sessionID string) error
- func CountTodos(todosJSON []byte) int
- func DeleteBranchCLI(ctx context.Context, branchName string) error
- func DeleteOrphanedCheckpoints(ctx context.Context, checkpointIDs []string) (deleted []string, failed []string, err error)
- func DeleteOrphanedSessionStates(ctx context.Context, sessionIDs []string) (deleted []string, failed []string, err error)
- func DeleteRefCLI(ctx context.Context, refName string, expectedOID string) error
- func DeleteShadowBranches(ctx context.Context, branches []string) (deleted []string, failed []string, err error)
- func DeleteV2Generations(ctx context.Context, generations []V2GenerationRef) (deleted []string, failed []string, err error)
- func EnsureEntireGitignore(ctx context.Context) error
- func EnsureMetadataBranch(repo *git.Repository) error
- func EnsureRedactionConfigured()
- func EnsureSetup(ctx context.Context) error
- func ExtractFirstPrompt(content string) string
- func ExtractInProgressTodo(todosJSON []byte) string
- func ExtractLastCompletedTodo(todosJSON []byte) string
- func ExtractSessionIDFromCommit(commit *object.Commit) string
- func FetchMetadataBranch(ctx context.Context, remoteURL string) error
- func FetchV2MainFromURL(ctx context.Context, remoteURL string) error
- func FindMostRecentSession(ctx context.Context) 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(ctx context.Context) (string, error)
- func GetGitDir(ctx context.Context) (string, error)
- func GetHooksDir(ctx context.Context) (string, error)
- func GetMainBranchHash(repo *git.Repository) plumbing.Hash
- func GetMainRepoRoot(ctx context.Context) (string, error)
- func GetMetadataBranchTree(repo *git.Repository) (*object.Tree, error)
- func GetRemoteMetadataBranchTree(repo *git.Repository) (*object.Tree, error)
- func GetV2MetadataBranchTree(repo *git.Repository) (*object.Tree, error)
- func HardResetWithProtection(ctx context.Context, commitHash plumbing.Hash) (shortID string, err error)
- func InstallGitHook(ctx context.Context, silent, localDev, absolutePath bool) (int, error)
- func IsAncestorOf(ctx context.Context, repo *git.Repository, commit, target plumbing.Hash) bool
- func IsEmptyRepository(repo *git.Repository) bool
- func IsGitHookInstalled(ctx context.Context) bool
- func IsGitHookInstalledInDir(ctx context.Context, repoDir string) bool
- func IsInsideWorktree(ctx context.Context) bool
- func IsMetadataDisconnected(ctx context.Context, repo *git.Repository, ...) (bool, error)
- func IsOnDefaultBranch(repo *git.Repository) (bool, string)
- func IsShadowBranch(branchName string) bool
- func IsV2MainDisconnected(ctx context.Context, repo *git.Repository, remote string) (bool, error)
- func ListShadowBranches(ctx context.Context) ([]string, error)
- func LoadAgentTypeHint(ctx context.Context, sessionID string) types.AgentType
- func LoadModelHint(ctx context.Context, sessionID string) string
- func ManagedGitHookNames() []string
- func OpenRepository(ctx context.Context) (*git.Repository, error)
- func PromoteTmpRefSafely(ctx context.Context, tmpRefName, destRefName plumbing.ReferenceName, ...) error
- func PromptOverwriteNewerLogs(errW io.Writer, sessions []SessionRestoreInfo) (bool, error)
- func ReadAgentTypeFromTree(tree *object.Tree, checkpointPath string) types.AgentType
- func ReadAllSessionPromptsFromTree(tree *object.Tree, checkpointPath string, sessionCount int, ...) []string
- func ReadLatestSessionPromptFromCommittedTree(tree *object.Tree, cpID id.CheckpointID, sessionCount int) string
- func ReadSessionPromptFromTree(tree *object.Tree, checkpointPath string) string
- func ReconcileDisconnectedMetadataBranch(ctx context.Context, repo *git.Repository, ...) error
- func ReconcileDisconnectedV2Ref(ctx context.Context, repo *git.Repository, remote string, w io.Writer) error
- func RemoveGitHook(ctx context.Context) (int, error)
- func ResolveAgentForRewind(agentType types.AgentType) (agent.Agent, error)
- func SafelyAdvanceLocalRef(ctx context.Context, repo *git.Repository, localRefName plumbing.ReferenceName, ...) error
- func SaveSessionState(ctx context.Context, state *SessionState) error
- func StatusToText(status SessionRestoreStatus) string
- func StoreAgentTypeHint(ctx context.Context, sessionID string, agentType types.AgentType) (created bool, err error)
- func StoreModelHint(ctx context.Context, sessionID, model string) error
- func TaskMetadataDir(sessionMetadataDir, toolUseID string) string
- func TransitionAndLog(goCtx context.Context, state *SessionState, event session.Event, ...) error
- func TruncateDescription(s string, maxLen int) string
- func WarnIfMetadataDisconnected()
- type AttributionParams
- type Checkpoint
- type CheckpointInfo
- func ListCheckpoints(ctx context.Context) ([]CheckpointInfo, error)
- func ReadCheckpointMetadata(tree checkpoint.FileReader, checkpointPath string) (*CheckpointInfo, error)
- func ReadCheckpointMetadataFromSubtree(tree checkpoint.FileReader, checkpointPath string) (*CheckpointInfo, error)
- func ResolveLatestCheckpointFromMap(cpIDs []id.CheckpointID, infoMap map[id.CheckpointID]CheckpointInfo) (CheckpointInfo, bool)
- type CleanupItem
- type CleanupResult
- type CleanupType
- type CondenseResult
- type ExtractedSessionData
- type ManualCommitStrategy
- func (s *ManualCommitStrategy) CanRewind(ctx context.Context) (bool, string, error)
- func (s *ManualCommitStrategy) ClearSessionState(ctx context.Context, sessionID string) error
- func (s *ManualCommitStrategy) CommitMsg(_ context.Context, commitMsgFile string) error
- func (s *ManualCommitStrategy) CondenseAndMarkFullyCondensed(ctx context.Context, sessionID string) error
- func (s *ManualCommitStrategy) CondenseSession(ctx context.Context, repo *git.Repository, checkpointID id.CheckpointID, ...) (*CondenseResult, error)
- func (s *ManualCommitStrategy) CondenseSessionByID(ctx context.Context, sessionID string) error
- func (s *ManualCommitStrategy) CountOtherActiveSessionsWithCheckpoints(ctx context.Context, currentSessionID string) (int, error)
- func (s *ManualCommitStrategy) FindSessionsForCommit(ctx context.Context, baseCommitSHA string) ([]*SessionState, error)
- func (s *ManualCommitStrategy) GetAdditionalSessions(ctx context.Context) ([]*Session, error)
- func (s *ManualCommitStrategy) GetCheckpointLog(ctx context.Context, checkpoint Checkpoint) ([]byte, error)
- func (s *ManualCommitStrategy) GetLogsOnlyRewindPoints(ctx context.Context, limit int) ([]RewindPoint, error)
- func (s *ManualCommitStrategy) GetMetadataRef(_ context.Context, checkpoint Checkpoint) string
- func (s *ManualCommitStrategy) GetRewindPoints(ctx context.Context, limit int) ([]RewindPoint, error)
- func (s *ManualCommitStrategy) GetSessionInfo(ctx context.Context) (*SessionInfo, error)
- func (s *ManualCommitStrategy) GetSessionMetadataRef(ctx context.Context, _ string) string
- func (s *ManualCommitStrategy) GetTaskCheckpoint(ctx context.Context, point RewindPoint) (*TaskCheckpoint, error)
- func (s *ManualCommitStrategy) GetTaskCheckpointTranscript(ctx context.Context, point RewindPoint) ([]byte, error)
- func (s *ManualCommitStrategy) HandleTurnEnd(ctx context.Context, state *SessionState) error
- func (s *ManualCommitStrategy) HasBlobFetcher() bool
- func (s *ManualCommitStrategy) InitializeSession(ctx context.Context, sessionID string, agentType types.AgentType, ...) error
- func (s *ManualCommitStrategy) ListOrphanedItems(ctx context.Context) ([]CleanupItem, error)
- func (s *ManualCommitStrategy) PostCommit(ctx context.Context) error
- func (s *ManualCommitStrategy) PostRewrite(ctx context.Context, rewriteType string, r io.Reader) error
- func (s *ManualCommitStrategy) PrePush(ctx context.Context, remote string) error
- func (s *ManualCommitStrategy) PrepareCommitMsg(ctx context.Context, commitMsgFile string, source string) error
- func (s *ManualCommitStrategy) PreviewRewind(ctx context.Context, point RewindPoint) (*RewindPreview, error)
- func (s *ManualCommitStrategy) Reset(ctx context.Context, w, errW io.Writer) error
- func (s *ManualCommitStrategy) ResetSession(ctx context.Context, w, errW io.Writer, sessionID string) error
- func (s *ManualCommitStrategy) RestoreLogsOnly(ctx context.Context, w, errW io.Writer, point RewindPoint, force bool) ([]RestoredSession, error)
- func (s *ManualCommitStrategy) Rewind(ctx context.Context, w, errW io.Writer, point RewindPoint) error
- func (s *ManualCommitStrategy) SaveStep(ctx context.Context, step StepContext) error
- func (s *ManualCommitStrategy) SaveTaskStep(ctx context.Context, step TaskStepContext) error
- func (s *ManualCommitStrategy) SetBlobFetcher(f checkpoint.BlobFetchFunc)
- func (s *ManualCommitStrategy) ValidateRepository() error
- type PromptAttribution
- type RepairV2GenerationMetadataResult
- type RestoredSession
- type RewindPoint
- type RewindPreview
- type Session
- type SessionInfo
- type SessionRestoreInfo
- type SessionRestoreStatus
- type SessionState
- type StepContext
- type SubagentCheckpoint
- type TaskCheckpoint
- type TaskStepContext
- type V2GenerationRef
Constants ¶
const FetchTmpRefPrefix = "refs/entire-fetch-tmp/"
FetchTmpRefPrefix is the namespace for temporary refs used by fetch helpers to land a fetched hash before safely promoting it to a final ref (via PromoteTmpRefSafely). Prefer using the named constants below when possible.
const MaxCommitTraversalDepth = 1000
MaxCommitTraversalDepth is the safety limit for walking git commit history. Prevents unbounded traversal in repositories with very long histories.
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.
const (
// Strategy name constants
StrategyNameManualCommit = "manual-commit"
)
Common branch name constants for default branch detection.
const V2MainFetchTmpRef = FetchTmpRefPrefix + "v2-main"
V2MainFetchTmpRef is the staging ref for fetches that target V2MainRefName. Shared between the cli package's origin-based fetches and the strategy package's checkpoint_remote URL-based fetch — those code paths never run concurrently (they are sequenced in explain and resume), so reusing one staging ref is safe and avoids divergent conventions.
Variables ¶
var ErrBranchNotFound = errors.New("branch not found")
ErrBranchNotFound is returned by DeleteBranchCLI when the branch does not exist.
var ErrEmptyRepository = errors.New("repository has no commits yet")
ErrEmptyRepository is returned when the repository has no commits yet.
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 ErrNotTaskCheckpoint = errors.New("not a task checkpoint")
ErrNotTaskCheckpoint is returned when a rewind point is not a task checkpoint.
var ErrRefChanged = errors.New("ref changed since inspection")
ErrRefChanged is returned by DeleteRefCLI when the ref no longer points to the expected OID.
var ErrRefNotFound = errors.New("ref not found")
ErrRefNotFound is returned by DeleteRefCLI when the ref does not exist.
Functions ¶
func CalculateAttributionWithAccumulated ¶
func CalculateAttributionWithAccumulated(ctx context.Context, p AttributionParams) *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
ParentCommitHash→HeadCommitHash is preferred for non-agent file detection so only files from THIS commit count. For initial commits (no parent), falls back to AttributionBaseCommit→HeadCommitHash. When hashes are empty, falls back to go-git tree walk.
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 CheckAndWarnHookManagers ¶ added in v0.4.5
CheckAndWarnHookManagers detects external hook managers and writes a warning to w if any are found. localDev controls whether the warning references "go run" or the "entire" binary. absolutePath embeds the full binary path for GUI git clients.
func ClaimSessionStartBanner ¶ added in v0.6.0
ClaimSessionStartBanner records that the SessionStart banner has been emitted for a session. First-writer-wins semantics, separate from StoreAgentTypeHint so a non-banner-capable agent winning the ownership race (e.g. Cursor, which doesn't implement HookResponseWriter) doesn't suppress the banner from a banner-capable agent that fires SessionStart for the same session.
Callers MUST only invoke this from within the HookResponseWriter branch — the claim represents "a banner was actually shown", not just "an agent considered showing one". Otherwise a non-writer claimant would re-introduce the bug.
Returns (claimed=true) when this call won the race and the caller should emit the banner; (claimed=false) when an earlier call already claimed it.
func ClearHooksDirCache ¶ added in v0.4.6
func ClearHooksDirCache()
ClearHooksDirCache clears the cached hooks directory. This is primarily useful for testing when changing directories.
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 DeleteBranchCLI ¶ added in v0.3.13
DeleteBranchCLI deletes a git branch using the git CLI. Uses `git branch -D` instead of go-git's RemoveReference because go-git v5 doesn't properly persist deletions when refs are packed (.git/packed-refs) or in a worktree context. This is the same class of go-git v5 bug that affects checkout and reset --hard (see HardResetWithProtection).
Returns ErrBranchNotFound if the branch does not exist, allowing callers to use errors.Is for idempotent deletion patterns.
func DeleteOrphanedCheckpoints ¶
func DeleteOrphanedCheckpoints(ctx context.Context, checkpointIDs []string) (deleted []string, failed []string, err error)
DeleteOrphanedCheckpoints removes checkpoint directories from the entire/checkpoints/v1 branch.
func DeleteOrphanedSessionStates ¶
func DeleteOrphanedSessionStates(ctx context.Context, sessionIDs []string) (deleted []string, failed []string, err error)
DeleteOrphanedSessionStates deletes the specified session state files.
func DeleteRefCLI ¶ added in v0.5.6
DeleteRefCLI deletes an arbitrary ref using the git CLI. Uses `git update-ref -d` instead of go-git's RemoveReference because go-git ref deletion is unreliable with packed refs and worktrees.
When expectedOID is non-empty, it is passed to `git update-ref -d <ref> <old-oid>` as a compare-and-swap guard: git will refuse the deletion if the ref no longer points to expectedOID, and ErrRefChanged is returned.
Returns ErrRefNotFound if the ref does not exist, allowing callers to use errors.Is for idempotent deletion patterns.
func DeleteShadowBranches ¶
func DeleteShadowBranches(ctx context.Context, branches []string) (deleted []string, failed []string, err error)
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.
func DeleteV2Generations ¶ added in v0.5.6
func DeleteV2Generations(ctx context.Context, generations []V2GenerationRef) (deleted []string, failed []string, err error)
DeleteV2Generations deletes archived checkpoints v2 /full/* generation refs. When RefOID is set, deletion uses compare-and-swap to avoid deleting a ref that was repointed after enumeration.
func EnsureEntireGitignore ¶
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 or updates the local entire/checkpoints/v1 branch. If the remote-tracking branch (origin/entire/checkpoints/v1) exists and the local branch is missing or empty, creates/updates the local branch from it. Otherwise creates an empty orphan.
func EnsureRedactionConfigured ¶ added in v0.5.1
func EnsureRedactionConfigured()
EnsureRedactionConfigured loads PII redaction settings and configures the redact package. No-op if PII is not enabled in settings. Must be called at each process entry point before checkpoint writes (e.g., hook PersistentPreRunE, doctor PreRun).
func EnsureSetup ¶ added in v0.4.8
EnsureSetup ensures the strategy is properly set up.
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 FetchMetadataBranch ¶ added in v0.5.3
FetchMetadataBranch fetches the metadata branch from the checkpoint remote URL and updates the local branch. Unlike fetchMetadataBranchIfMissing, this always fetches regardless of whether the branch exists locally (for resume scenarios where the local branch may be stale).
The fetch is unfiltered (NoFilter: true) because resume needs blob content (transcripts, metadata JSON) — not just tree objects.
func FetchV2MainFromURL ¶ added in v0.5.3
FetchV2MainFromURL fetches the v2 /main ref from a remote URL and advances the local ref only when doing so cannot rewind locally-ahead commits. Uses explicit refspec since v2 refs are under refs/entire/, not refs/heads/.
The fetch is unfiltered (NoFilter: true) because resume needs full metadata.
func FindMostRecentSession ¶ added in v0.3.13
FindMostRecentSession returns the session ID of the most recently interacted session (by LastInteractionTime) in the current worktree. Returns empty string if no sessions exist. Scoping to the current worktree prevents cross-worktree pollution in log routing. Falls back to unfiltered search if the worktree path can't be determined.
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, checking both the repository-local config and the global ~/.gitconfig. Delegates to checkpoint.GetGitAuthorFromRepo — this wrapper exists so callers within the strategy package don't need a qualified import.
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 GetHooksDir ¶ added in v0.4.5
GetHooksDir returns the active hooks directory path. This respects core.hooksPath and correctly resolves to the common hooks directory when called from a linked worktree. The result is cached per working directory.
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/checkpoints/v1 branch.
func GetRemoteMetadataBranchTree ¶
func GetRemoteMetadataBranchTree(repo *git.Repository) (*object.Tree, error)
GetRemoteMetadataBranchTree returns the tree object for origin/entire/checkpoints/v1.
func GetV2MetadataBranchTree ¶ added in v0.5.4
func GetV2MetadataBranchTree(repo *git.Repository) (*object.Tree, error)
GetV2MetadataBranchTree returns the tree object at the tip of the v2 /main ref. The v2 /main ref uses the same sharded checkpoint layout as v1, so ReadLatestSessionPromptFromCommittedTree works with either tree.
func HardResetWithProtection ¶
func HardResetWithProtection(ctx context.Context, commitHash plumbing.Hash) (shortID string, err error)
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 (except backup notifications, which always print). localDev controls whether hooks use "go run" (true) or the "entire" binary (false). absolutePath embeds the full binary path in hooks for GUI git clients. Returns the number of hooks that were installed (0 if all already up to date).
func IsAncestorOf ¶
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 MaxCommitTraversalDepth commits to avoid excessive traversal.
func IsEmptyRepository ¶ added in v0.4.3
func IsEmptyRepository(repo *git.Repository) bool
IsEmptyRepository returns true if the repository has no commits yet. After git-init, HEAD points to an unborn branch (e.g., refs/heads/main) whose target does not yet exist. repo.Head() returns ErrReferenceNotFound in this case.
func IsGitHookInstalled ¶
IsGitHookInstalled checks if all generic Entire CLI hooks are installed.
func IsGitHookInstalledInDir ¶ added in v0.4.4
IsGitHookInstalledInDir checks if all Entire CLI hooks are installed in the given repo directory. This is useful for tests that need to check hooks without changing the working directory.
func IsInsideWorktree ¶
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 IsMetadataDisconnected ¶ added in v0.5.0
func IsMetadataDisconnected(ctx context.Context, repo *git.Repository, remoteRefName plumbing.ReferenceName) (bool, error)
IsMetadataDisconnected checks whether the local metadata branch and the provided fetched or remote-tracking ref exist but share no common ancestor.
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/checkpoints/v1" branch is NOT a shadow branch.
func IsV2MainDisconnected ¶ added in v0.5.6
IsV2MainDisconnected checks whether the local v2 /main ref and the remote v2 /main ref exist but share no common ancestor. Uses git ls-remote to discover the remote ref (custom refs don't have remote-tracking refs).
remote is the git remote name, URL, or local path to check against. Returns (false, nil) if either ref doesn't exist or they share ancestry.
func ListShadowBranches ¶
ListShadowBranches returns all shadow branches in the repository. Shadow branches match the pattern "entire/<commit-hash>" (7+ hex chars). The "entire/checkpoints/v1" branch is excluded as it stores permanent metadata. Returns an empty slice (not nil) if no shadow branches exist.
func LoadAgentTypeHint ¶ added in v0.6.0
LoadAgentTypeHint reads the agent type hint written by SessionStart. Returns empty string if the hint file doesn't exist, can't be read, or the value isn't a registered agent type.
func LoadModelHint ¶ added in v0.5.0
LoadModelHint reads the LLM model name from the hint file for the given session. Returns empty string if the hint file doesn't exist or can't be read.
func ManagedGitHookNames ¶ added in v0.4.4
func ManagedGitHookNames() []string
ManagedGitHookNames returns the list of git hooks managed by Entire CLI. This is useful for tests that need to manipulate hooks.
func OpenRepository ¶
func OpenRepository(ctx context.Context) (*git.Repository, error)
OpenRepository opens the git repository from the repo root. It uses 'git rev-parse --show-toplevel' to find the repository root, which works correctly even when called from a subdirectory or a linked worktree.
func PromoteTmpRefSafely ¶ added in v0.5.6
func PromoteTmpRefSafely(ctx context.Context, tmpRefName, destRefName plumbing.ReferenceName, label string) error
PromoteTmpRefSafely reads tmpRefName (the ref a fetch just landed into), advances destRefName to its hash via SafelyAdvanceLocalRef, then removes the tmp ref. The cleanup is deferred so the tmp ref is reaped even when the advance fails.
label is a short human-readable name used in error messages (e.g. "v2 /main", "entire/checkpoints/v1"). Typical use:
// fetch with refspec "+<src>:<V2MainFetchTmpRef>" return PromoteTmpRefSafely(ctx, V2MainFetchTmpRef, paths.V2MainRefName, "v2 /main")
func PromptOverwriteNewerLogs ¶
func PromptOverwriteNewerLogs(errW io.Writer, sessions []SessionRestoreInfo) (bool, error)
PromptOverwriteNewerLogs asks the user for confirmation to overwrite local session logs that have newer timestamps than the checkpoint versions.
func ReadAgentTypeFromTree ¶ added in v0.4.4
ReadAgentTypeFromTree reads the agent type from a checkpoint's metadata.json file in a git tree. If metadata.json doesn't exist (shadow branches), it falls back to detecting the agent from the presence of agent-specific config files (.gemini/settings.json or .claude/). Returns agent.AgentTypeUnknown if the agent type cannot be determined.
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 ReadLatestSessionPromptFromCommittedTree ¶ added in v0.4.9
func ReadLatestSessionPromptFromCommittedTree(tree *object.Tree, cpID id.CheckpointID, sessionCount int) string
ReadLatestSessionPromptFromCommittedTree reads the first prompt from a committed checkpoint's latest session on the metadata branch tree. This navigates the sharded directory layout: <cpID.Path()>/<latestSessionIndex>/prompt.txt
Falls back through earlier sessions when the latest has no prompt. Avoids reading full transcripts — only reads prompt.txt files. sessionCount is the number of sessions in the checkpoint (from CommittedInfo.SessionCount).
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 ReconcileDisconnectedMetadataBranch ¶ added in v0.5.0
func ReconcileDisconnectedMetadataBranch( ctx context.Context, repo *git.Repository, remoteRefName plumbing.ReferenceName, w io.Writer, ) error
ReconcileDisconnectedMetadataBranch detects and repairs disconnected local/remote entire/checkpoints/v1 branches. Disconnected means no common ancestor, which only happens due to the empty-orphan bug. Diverged (shared ancestor) is normal and handled by the push path's tree merge.
Repair strategy: cherry-pick local commits onto remote tip, preserving all data. Checkpoint shards use unique paths (<id[:2]>/<id[2:]>/), so cherry-picks always apply cleanly.
Progress messages are written to w (typically os.Stderr for hooks or cmd.ErrOrStderr() for commands). The remote ref can be either a remote-tracking ref or a temporary fetched ref.
func ReconcileDisconnectedV2Ref ¶ added in v0.5.6
func ReconcileDisconnectedV2Ref( ctx context.Context, repo *git.Repository, remote string, w io.Writer, ) error
ReconcileDisconnectedV2Ref detects and repairs disconnected local/remote v2 /main refs. Same strategy as v1: cherry-pick local commits onto remote tip. The remote is discovered via git ls-remote and fetched to a temp ref.
remote is the git remote name, URL, or local path.
func RemoveGitHook ¶
RemoveGitHook removes all Entire CLI git hooks from the repository. If a .pre-entire backup exists, it is restored. Returns the number of hooks removed.
func ResolveAgentForRewind ¶ added in v0.4.3
ResolveAgentForRewind resolves the agent from checkpoint metadata.
func SafelyAdvanceLocalRef ¶ added in v0.5.6
func SafelyAdvanceLocalRef(ctx context.Context, repo *git.Repository, localRefName plumbing.ReferenceName, targetHash plumbing.Hash) error
SafelyAdvanceLocalRef updates localRefName to point at targetHash, except when the existing local ref is already at or ahead of targetHash. In that case it leaves the local ref unchanged to avoid rewinding locally-ahead work. Otherwise (local missing, behind, or diverged) it updates the ref to targetHash.
The ancestry check walks from the local ref (which has full history), so callers that fetched with --depth=1 do not break the check.
func SaveSessionState ¶
func SaveSessionState(ctx context.Context, state *SessionState) error
SaveSessionState saves the session state atomically.
func StatusToText ¶
func StatusToText(status SessionRestoreStatus) string
StatusToText returns a human-readable status string.
func StoreAgentTypeHint ¶ added in v0.6.0
func StoreAgentTypeHint(ctx context.Context, sessionID string, agentType types.AgentType) (created bool, err error)
StoreAgentTypeHint records the agent type that owns a session before SessionState exists. Used by the lifecycle dispatcher when SessionStart fires (state isn't created until TurnStart, so we need a place to remember which agent claimed the session first).
Semantics: first writer wins. When multiple agents fire hooks for the same session ID — e.g., Cursor IDE running cursor-agent while also forwarding to Claude Code's hook system — only the agent that fires SessionStart first gets recorded. Subsequent calls return nil without overwriting.
At TurnStart, InitializeSession reads this hint to override agentType when the hook firing isn't the same agent that owns the session. After the state file is written, the hint is unused but remains until ClearSessionState removes it alongside the state file.
Returns (created=true) when this call wrote the hint, (created=false) when the hint already existed (no-op) or agentType was empty/Unknown.
Banner display is gated separately via ClaimSessionStartBanner — winning the ownership claim does NOT mean this agent should also print the banner, because the winner may not implement HookResponseWriter (e.g., Cursor).
func StoreModelHint ¶ added in v0.5.0
StoreModelHint writes the LLM model name to a lightweight hint file (.git/entire-sessions/{session_id}.model) for cross-process persistence.
Why a separate file instead of SessionState?
SessionState requires BaseCommit (used for shadow branch naming, checkpoint writing, doctor classification, etc.) and is only created during TurnStart when the git repo is fully inspected. Some agents report the model on earlier hooks that fire as separate CLI processes before TurnStart:
- Claude Code sends "model" on SessionStart (before any TurnStart)
- Gemini CLI sends "llm_request.model" on BeforeModel (after TurnStart, so handleLifecycleModelUpdate writes to SessionState directly when it exists and only falls back to this hint file otherwise)
The hint is read by handleLifecycleTurnStart/TurnEnd when event.Model is empty, passed to InitializeSession, and persisted in state.ModelName. After that the hint file is redundant — it sits unused until ClearSessionState removes it alongside the session state file.
func TaskMetadataDir ¶
TaskMetadataDir returns the path to a task's metadata directory within the session metadata directory.
func TransitionAndLog ¶ added in v0.3.13
func TransitionAndLog(goCtx context.Context, state *SessionState, event session.Event, ctx session.TransitionContext, handler session.ActionHandler) error
TransitionAndLog runs a session phase transition, applies actions via the handler, and logs the transition. Returns the first handler error from ApplyTransition (if any) so callers can surface it. The error is also logged internally for diagnostics. This is the single entry point for all state machine transitions to ensure consistent logging of phase changes.
func TruncateDescription ¶
TruncateDescription truncates a string to maxLen runes, adding "..." if truncated. Uses rune-based slicing to avoid splitting multi-byte UTF-8 characters. If maxLen is less than 3, truncates without ellipsis.
func WarnIfMetadataDisconnected ¶ added in v0.5.0
func WarnIfMetadataDisconnected()
WarnIfMetadataDisconnected checks (once per process) whether the metadata branch is disconnected and prints a warning to stderr if so. It does NOT fix the problem — users are directed to 'entire doctor'.
Uses sync.Once, so a transient failure on the first call permanently suppresses the warning. This is acceptable because the check is advisory only and 'entire doctor' is the authoritative repair path.
Types ¶
type AttributionParams ¶ added in v0.5.3
type AttributionParams struct {
BaseTree *object.Tree // Session base commit tree
ShadowTree *object.Tree // Shadow branch tree (checkpoint snapshot)
HeadTree *object.Tree // HEAD commit tree
ParentTree *object.Tree // HEAD's first parent tree (nil for initial commits)
FilesTouched []string // Agent-touched file paths
PromptAttributions []PromptAttribution // Per-prompt user edit snapshots
RepoDir string // Worktree path for git CLI commands
ParentCommitHash string // HEAD's first parent hash (preferred diff base for non-agent files)
AttributionBaseCommit string // Session base commit hash (fallback for non-agent file detection)
HeadCommitHash string // HEAD commit hash for git diff-tree
AllAgentFiles map[string]struct{} // Files touched by ALL agent sessions (cross-session exclusion)
}
AttributionParams bundles the inputs for CalculateAttributionWithAccumulated.
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/checkpoints/v1 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 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 types.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(ctx context.Context) ([]CheckpointInfo, error)
ListCheckpoints returns all checkpoints from the entire/checkpoints/v1 branch. Scans sharded paths: <id[:2]>/<id[2:]>/ directories containing metadata.json.
func ReadCheckpointMetadata ¶
func ReadCheckpointMetadata(tree checkpoint.FileReader, checkpointPath string) (*CheckpointInfo, error)
ReadCheckpointMetadata reads metadata.json from a checkpoint path on entire/checkpoints/v1. 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.
Uses streaming json.Decoder and minimal structs to avoid loading large nested objects (Summary, InitialAttribution, TokenUsage) into memory.
func ReadCheckpointMetadataFromSubtree ¶ added in v0.5.1
func ReadCheckpointMetadataFromSubtree(tree checkpoint.FileReader, checkpointPath string) (*CheckpointInfo, error)
ReadCheckpointMetadataFromSubtree reads checkpoint metadata from a tree that is already rooted at the checkpoint directory (e.g., after tree.Tree(checkpointID.Path())). checkpointPath is the original sharded path (e.g., "ca/b75de47439") and is used to strip the prefix from absolute session metadata paths stored in the summary.
func ResolveLatestCheckpointFromMap ¶ added in v0.5.0
func ResolveLatestCheckpointFromMap(cpIDs []id.CheckpointID, infoMap map[id.CheckpointID]CheckpointInfo) (CheckpointInfo, bool)
ResolveLatestCheckpointFromMap picks the checkpoint with the latest CreatedAt from a list of checkpoint IDs. Filters to IDs present in infoMap, then picks the one with the most recent CreatedAt.
type CleanupItem ¶
type CleanupItem struct {
Type CleanupType
ID string // Branch name, session ID, or checkpoint ID
RefOID string // For ref-based items: the OID observed at listing time (compare-and-swap)
Reason string // Why this item is being cleaned
}
CleanupItem represents an item that can be cleaned up.
func ListAllItems ¶ added in v0.5.4
func ListAllItems(ctx context.Context) ([]CleanupItem, error)
ListAllItems returns all Entire items for full cleanup. This includes all shadow branches and all session states regardless of whether they have checkpoints or active shadow branches.
func ListEligibleV2Generations ¶ added in v0.5.6
func ListEligibleV2Generations(ctx context.Context, s *settings.EntireSettings) ([]CleanupItem, []string, error)
ListEligibleV2Generations returns archived checkpoints v2 /full/* generations eligible for deletion based on the configured retention window, along with warnings for malformed generations that were skipped.
func ListOrphanedSessionStates ¶
func ListOrphanedSessionStates(ctx context.Context) ([]CleanupItem, error)
ListOrphanedSessionStates returns session state files that are orphaned. A session state is orphaned if:
- No checkpoints on entire/checkpoints/v1 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
V2Generations []string // Deleted archived v2 generation refs
FailedBranches []string // Shadow branches that failed to delete
FailedStates []string // Session states that failed to delete
FailedCheckpoints []string // Checkpoints that failed to delete
FailedV2Refs []string // Archived v2 generation refs that failed to delete
}
CleanupResult contains the results of a cleanup operation.
func DeleteAllCleanupItems ¶
func DeleteAllCleanupItems(ctx context.Context, 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 item to clean up.
const ( CleanupTypeShadowBranch CleanupType = "shadow-branch" CleanupTypeSessionState CleanupType = "session-state" CleanupTypeCheckpoint CleanupType = "checkpoint" CleanupTypeV2Generation CleanupType = "v2-generation" )
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
Prompts []string // User prompts from the condensed session
TotalTranscriptLines int // Total transcript units after this condensation (JSONL line count or message count by agent format)
CompactTranscriptLines int // New compact transcript lines added by this checkpoint (0 if v2 disabled); used to advance CompactTranscriptStart
Transcript []byte // Raw transcript bytes for downstream consumers (trail title generation)
Skipped bool // True if condensation was skipped (no transcript or files to condense)
}
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 // User prompts from the current checkpoint portion
FilesTouched []string
TokenUsage *agent.TokenUsage // Token usage calculated from transcript (since CheckpointTranscriptStart)
}
ExtractedSessionData contains data extracted from a shadow branch.
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 NewManualCommitStrategy ¶
func NewManualCommitStrategy() *ManualCommitStrategy
NewManualCommitStrategy creates a new manual-commit strategy instance.
func (*ManualCommitStrategy) CanRewind ¶
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(ctx context.Context, 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(_ context.Context, commitMsgFile string) error
func (*ManualCommitStrategy) CondenseAndMarkFullyCondensed ¶ added in v0.5.3
func (s *ManualCommitStrategy) CondenseAndMarkFullyCondensed(ctx context.Context, sessionID string) error
CondenseAndMarkFullyCondensed condenses an ENDED session and marks it FullyCondensed in one operation. Used by the session stop hook to eagerly clean up sessions so PostCommit doesn't have to process them.
This does NOT call CondenseSessionByID because that method has two behaviors we don't want: (1) it calls clearSessionState when no shadow branch exists (deletes the state file entirely), and (2) it sets Phase = IDLE. Instead, we inline the condensation logic with ENDED-appropriate behavior.
Fail-open: if condensation fails, the session is left in its current state and PostCommit will still process it on the next commit.
func (*ManualCommitStrategy) CondenseSession ¶
func (s *ManualCommitStrategy) CondenseSession(ctx context.Context, repo *git.Repository, checkpointID id.CheckpointID, state *SessionState, committedFiles map[string]struct{}, opts ...condenseOpts) (*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.
For mid-session commits (no Stop/SaveStep called yet), the shadow branch may not exist. In this case, data is extracted from the live transcript instead.
func (*ManualCommitStrategy) CondenseSessionByID ¶ added in v0.3.13
func (s *ManualCommitStrategy) CondenseSessionByID(ctx context.Context, sessionID string) error
CondenseSessionByID condenses a session by its ID and cleans up. This is used by "entire doctor" to salvage stuck sessions.
func (*ManualCommitStrategy) CountOtherActiveSessionsWithCheckpoints ¶ added in v0.3.12
func (s *ManualCommitStrategy) CountOtherActiveSessionsWithCheckpoints(ctx context.Context, currentSessionID string) (int, error)
CountOtherActiveSessionsWithCheckpoints counts how many other active sessions from the SAME worktree (different from currentSessionID) have created checkpoints on the SAME base commit (current HEAD). This is used to show an informational message about concurrent sessions that will be included in the next commit. Returns 0, nil if no such sessions exist.
func (*ManualCommitStrategy) FindSessionsForCommit ¶
func (s *ManualCommitStrategy) FindSessionsForCommit(ctx context.Context, 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(ctx context.Context) ([]*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(ctx context.Context, 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/checkpoints/v1 branch.
func (*ManualCommitStrategy) GetLogsOnlyRewindPoints ¶
func (s *ManualCommitStrategy) GetLogsOnlyRewindPoints(ctx context.Context, limit int) ([]RewindPoint, error)
GetLogsOnlyRewindPoints finds commits in the current branch's history that have condensed session logs on the entire/checkpoints/v1 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/checkpoints/v1 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(_ context.Context, checkpoint Checkpoint) string
GetMetadataRef returns a reference to the metadata for the given checkpoint. For manual-commit strategy, returns the sharded path on entire/checkpoints/v1 branch.
func (*ManualCommitStrategy) GetRewindPoints ¶
func (s *ManualCommitStrategy) GetRewindPoints(ctx context.Context, limit int) ([]RewindPoint, error)
GetRewindPoints returns available rewind points. Uses checkpoint.GitStore.ListTemporaryCheckpoints for reading from shadow branches.
func (*ManualCommitStrategy) GetSessionInfo ¶
func (s *ManualCommitStrategy) GetSessionInfo(ctx context.Context) (*SessionInfo, error)
GetSessionInfo returns the current session info.
func (*ManualCommitStrategy) GetSessionMetadataRef ¶
func (s *ManualCommitStrategy) GetSessionMetadataRef(ctx context.Context, _ string) string
GetSessionMetadataRef returns a reference to the most recent metadata commit for a session. For manual-commit strategy, metadata lives on the entire/checkpoints/v1 branch.
func (*ManualCommitStrategy) GetTaskCheckpoint ¶
func (s *ManualCommitStrategy) GetTaskCheckpoint(ctx context.Context, point RewindPoint) (*TaskCheckpoint, error)
GetTaskCheckpoint retrieves a task checkpoint.
func (*ManualCommitStrategy) GetTaskCheckpointTranscript ¶
func (s *ManualCommitStrategy) GetTaskCheckpointTranscript(ctx context.Context, point RewindPoint) ([]byte, error)
GetTaskCheckpointTranscript retrieves the transcript for a task checkpoint.
func (*ManualCommitStrategy) HandleTurnEnd ¶ added in v0.3.13
func (s *ManualCommitStrategy) HandleTurnEnd(ctx context.Context, state *SessionState) error
func (*ManualCommitStrategy) HasBlobFetcher ¶ added in v0.5.1
func (s *ManualCommitStrategy) HasBlobFetcher() bool
HasBlobFetcher reports whether a blob fetcher is configured. Used in tests to verify the strategy is properly wired for treeless fetch support.
func (*ManualCommitStrategy) InitializeSession ¶
func (s *ManualCommitStrategy) InitializeSession(ctx context.Context, sessionID string, agentType types.AgentType, transcriptPath string, userPrompt string, model 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). userPrompt is the user's prompt text (stored truncated as LastPrompt for display). model is the LLM model identifier (e.g., "claude-sonnet-4-20250514"); empty if unknown.
func (*ManualCommitStrategy) ListOrphanedItems ¶
func (s *ManualCommitStrategy) ListOrphanedItems(ctx context.Context) ([]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) PostCommit ¶
func (s *ManualCommitStrategy) PostCommit(ctx context.Context) error
func (*ManualCommitStrategy) PostRewrite ¶ added in v0.5.6
func (s *ManualCommitStrategy) PostRewrite(ctx context.Context, rewriteType string, r io.Reader) error
PostRewrite is called by the git post-rewrite hook after amend/rebase operations. It keeps session linkage aligned with rewritten commit SHAs in the current worktree.
func (*ManualCommitStrategy) PrePush ¶
func (s *ManualCommitStrategy) PrePush(ctx context.Context, remote string) error
PrePush is called by the git pre-push hook before pushing to a remote. It pushes the entire/checkpoints/v1 branch alongside the user's push (unless v1 writes are disabled by checkpoints_version: 2), and pushes v2 refs whenever IsPushV2RefsEnabled is true — i.e. either checkpoints_v2 + push_v2_refs, or checkpoints_version: 2.
If a checkpoint_remote is configured in settings, checkpoint branches/refs are pushed to the derived URL instead of the user's push remote.
Configuration options (stored in .entire/settings.json under strategy_options):
- push_sessions: false to disable automatic pushing of checkpoints
- checkpoint_remote: {"provider": "github", "repo": "org/repo"} to push to a separate repo
- push_v2_refs: true to enable pushing v2 refs (requires checkpoints_v2)
- checkpoints_version: 2 to skip the v1 metadata branch entirely and force v2 ref pushes on
func (*ManualCommitStrategy) PrepareCommitMsg ¶
func (*ManualCommitStrategy) PreviewRewind ¶
func (s *ManualCommitStrategy) PreviewRewind(ctx context.Context, 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 ¶
Reset deletes the shadow branch and session state for the current HEAD. This allows starting fresh without existing checkpoints.
func (*ManualCommitStrategy) ResetSession ¶ added in v0.3.13
func (s *ManualCommitStrategy) ResetSession(ctx context.Context, w, errW io.Writer, sessionID string) error
ResetSession clears a single session's state and removes the shadow branch if no other sessions reference it. File changes remain in the working directory.
func (*ManualCommitStrategy) RestoreLogsOnly ¶
func (s *ManualCommitStrategy) RestoreLogsOnly(ctx context.Context, w, errW io.Writer, point RewindPoint, force bool) ([]RestoredSession, error)
RestoreLogsOnly restores session logs from a logs-only rewind point. This fetches the transcript from entire/checkpoints/v1 and writes it to the agent's session 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. Returns info about each restored session so callers can print correct per-session resume commands.
func (*ManualCommitStrategy) Rewind ¶
func (s *ManualCommitStrategy) Rewind(ctx context.Context, w, errW io.Writer, point RewindPoint) error
func (*ManualCommitStrategy) SaveStep ¶ added in v0.4.6
func (s *ManualCommitStrategy) SaveStep(ctx context.Context, step StepContext) error
SaveStep saves a checkpoint to the shadow branch. Uses checkpoint.GitStore.WriteTemporary for git operations.
func (*ManualCommitStrategy) SaveTaskStep ¶ added in v0.4.6
func (s *ManualCommitStrategy) SaveTaskStep(ctx context.Context, step TaskStepContext) error
SaveTaskStep saves a task step checkpoint to the shadow branch. Uses checkpoint.GitStore.WriteTemporaryTask for git operations.
func (*ManualCommitStrategy) SetBlobFetcher ¶ added in v0.5.1
func (s *ManualCommitStrategy) SetBlobFetcher(f checkpoint.BlobFetchFunc)
SetBlobFetcher configures on-demand blob fetching for the checkpoint store. Must be called before the first checkpoint store access (e.g., before RestoreLogsOnly).
func (*ManualCommitStrategy) ValidateRepository ¶
func (s *ManualCommitStrategy) ValidateRepository() error
ValidateRepository validates that the repository is suitable for this strategy.
type PromptAttribution ¶
type PromptAttribution = session.PromptAttribution
PromptAttribution is an alias for session.PromptAttribution.
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 RepairV2GenerationMetadataResult ¶ added in v0.6.0
type RepairV2GenerationMetadataResult struct {
Repaired []string
Skipped []string
Failed []string
Warnings []string
}
RepairV2GenerationMetadataResult describes archived v2 generation metadata repair work performed by RepairV2GenerationMetadata.
func RepairV2GenerationMetadata ¶ added in v0.6.0
func RepairV2GenerationMetadata(ctx context.Context) (*RepairV2GenerationMetadataResult, error)
RepairV2GenerationMetadata rewrites generation.json for archived v2 /full/* generation refs using the timestamp envelope from raw transcripts. Remote archived refs are repaired with force-with-lease when they exist on the checkpoint remote.
type RestoredSession ¶ added in v0.4.3
type RestoredSession struct {
SessionID string
Agent types.AgentType
Prompt string
CreatedAt time.Time // From session metadata; used by resume to determine most recent
}
RestoredSession describes a single session that was restored by RestoreLogsOnly. Each session may come from a different agent, so callers use this to print per-session resume commands without re-reading the metadata tree.
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/checkpoints/v1, 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/checkpoints/v1/<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 types.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 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/checkpoints/v1 branch, plus any additional sessions from strategies implementing SessionSource. It automatically discovers all registered strategies and merges their sessions.
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 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 SessionState ¶
SessionState is an alias for session.State. Previously this was a separate struct with manual conversion functions.
func ListSessionStates ¶ added in v0.3.13
func ListSessionStates(ctx context.Context) ([]*SessionState, error)
ListSessionStates returns all session states from the state directory. This is a package-level function that doesn't require a specific strategy instance.
func LoadSessionState ¶
func LoadSessionState(ctx context.Context, sessionID string) (*SessionState, error)
LoadSessionState loads the session state for the given session ID. Returns (nil, nil) when session file doesn't exist or session is stale (not an error condition). Stale sessions are automatically deleted by the underlying StateStore.
type StepContext ¶ added in v0.4.6
type StepContext 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 types.AgentType
// Transcript position at step/turn start - tracks what was added during this step
StepTranscriptIdentifier string // Last identifier when step started (UUID for Claude, message ID for Gemini)
StepTranscriptStart int // Transcript line count when this step/turn started
// TokenUsage contains the token usage for this checkpoint
TokenUsage *agent.TokenUsage
}
StepContext contains all information needed for saving a step checkpoint. All file paths should be pre-filtered and normalized by the CLI layer.
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. Uses os.Root for traversal-resistant file reads within the metadata directory.
type TaskStepContext ¶ added in v0.4.6
type TaskStepContext 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 types.AgentType
}
TaskStepContext contains all information needed for saving a task step 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.
type V2GenerationRef ¶ added in v0.5.6
type V2GenerationRef struct {
Name string
RefOID string // Commit hash for compare-and-swap; empty skips the check
}
V2GenerationRef pairs a generation name with the OID observed at listing time.
Source Files
¶
- checkpoint_remote.go
- cleanup.go
- common.go
- content_overlap.go
- generation_repair.go
- hook_managers.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_migration.go
- manual_commit_push.go
- manual_commit_reset.go
- manual_commit_rewind.go
- manual_commit_session.go
- manual_commit_types.go
- messages.go
- metadata_reconcile.go
- push_common.go
- push_v2.go
- resolve_transcript.go
- session.go
- session_state.go
- strategy.go