Documentation
¶
Overview ¶
Package transaction provides atomic file operations with git-based rollback.
Description ¶
This package implements transactional file operations using git checkpoints. When a transaction begins, the current git state is captured. If the transaction fails or is explicitly rolled back, all changes are reverted to the checkpoint. If the transaction succeeds, changes can be committed as a single unit.
Thread Safety ¶
TransactionManager is safe for concurrent use from multiple goroutines. Only one transaction may be active at a time per manager instance.
Nested Transactions ¶
Nested transactions are NOT supported. Attempting to begin a transaction while one is already active will return ErrTransactionActive.
Index ¶
- Variables
- func LoggerWithTrace(ctx context.Context, logger *slog.Logger) *slog.Logger
- func SetMetricsEnabled(enabled bool)
- func ValidateConfig(config PreFlightConfig) error
- type Config
- type DefaultGitClient
- func (g *DefaultGitClient) Add(ctx context.Context, paths ...string) error
- func (g *DefaultGitClient) AddAll(ctx context.Context) error
- func (g *DefaultGitClient) BranchExists(ctx context.Context, name string) bool
- func (g *DefaultGitClient) Checkout(ctx context.Context, ref string) error
- func (g *DefaultGitClient) CleanUntracked(ctx context.Context) error
- func (g *DefaultGitClient) Commit(ctx context.Context, message string) error
- func (g *DefaultGitClient) CreateBranch(ctx context.Context, name string) error
- func (g *DefaultGitClient) CreateWorktree(ctx context.Context, path string, ref string) error
- func (g *DefaultGitClient) DeleteBranch(ctx context.Context, name string, force bool) error
- func (g *DefaultGitClient) GetCurrentBranch(ctx context.Context) (string, error)
- func (g *DefaultGitClient) HasBisectInProgress(ctx context.Context) bool
- func (g *DefaultGitClient) HasCherryPickInProgress(ctx context.Context) bool
- func (g *DefaultGitClient) HasMergeInProgress(ctx context.Context) bool
- func (g *DefaultGitClient) HasRebaseInProgress(ctx context.Context) bool
- func (g *DefaultGitClient) HasStagedChanges(ctx context.Context) bool
- func (g *DefaultGitClient) HasUnstagedChanges(ctx context.Context) bool
- func (g *DefaultGitClient) IsDetachedHead(ctx context.Context) bool
- func (g *DefaultGitClient) IsGitRepository(ctx context.Context) bool
- func (g *DefaultGitClient) RefExists(ctx context.Context, ref string) bool
- func (g *DefaultGitClient) RemoveWorktree(ctx context.Context, path string, force bool) error
- func (g *DefaultGitClient) ResetHard(ctx context.Context, ref string) error
- func (g *DefaultGitClient) RevParse(ctx context.Context, ref string) (string, error)
- func (g *DefaultGitClient) StashDrop(ctx context.Context, ref string) error
- func (g *DefaultGitClient) StashList(ctx context.Context) ([]StashEntry, error)
- func (g *DefaultGitClient) StashPop(ctx context.Context) error
- func (g *DefaultGitClient) StashPush(ctx context.Context, message string) error
- func (g *DefaultGitClient) Status(ctx context.Context) (*GitStatus, error)
- func (g *DefaultGitClient) WorktreeList(ctx context.Context) ([]WorktreeEntry, error)
- type GitClient
- type GitStatus
- type Manager
- func (m *Manager) Active() *Transaction
- func (m *Manager) Begin(ctx context.Context, sessionID string) (tx *Transaction, err error)
- func (m *Manager) Close() error
- func (m *Manager) Commit(ctx context.Context, message string) (result *Result, err error)
- func (m *Manager) IsActive() bool
- func (m *Manager) RecordModification(filePath string) error
- func (m *Manager) RecordModifications(paths []string) error
- func (m *Manager) Rollback(ctx context.Context, reason string) (result *Result, err error)
- type PreFlightConfig
- type PreFlightError
- type PreFlightGuard
- type PreFlightResult
- type PreFlightWarning
- type Result
- type StashEntry
- type Status
- type Strategy
- type Tracer
- func (t *Tracer) EndBegin(span trace.Span, tx *Transaction, err error)
- func (t *Tracer) EndCommit(span trace.Span, result *Result, err error)
- func (t *Tracer) EndGitOp(span trace.Span, err error)
- func (t *Tracer) EndRollback(span trace.Span, result *Result, err error)
- func (t *Tracer) RecordExpiration(ctx context.Context, txID string)
- func (t *Tracer) RecordStateTransition(ctx context.Context, txID string, from, to Status, duration time.Duration)
- func (t *Tracer) StartBegin(ctx context.Context, sessionID string, strategy Strategy) (context.Context, trace.Span)
- func (t *Tracer) StartCommit(ctx context.Context, tx *Transaction, message string) (context.Context, trace.Span)
- func (t *Tracer) StartGitOp(ctx context.Context, operation string) (context.Context, trace.Span)
- func (t *Tracer) StartRollback(ctx context.Context, tx *Transaction, reason string) (context.Context, trace.Span)
- type Transaction
- type WorktreeEntry
Constants ¶
This section is empty.
Variables ¶
var ( // ErrTransactionActive is returned when attempting to begin a transaction // while one is already in progress. ErrTransactionActive = errors.New("transaction already active") // ErrNoTransaction is returned when attempting to commit or rollback // when no transaction is active. ErrNoTransaction = errors.New("no active transaction") // ErrNotGitRepository is returned when the working directory is not // a git repository. ErrNotGitRepository = errors.New("not a git repository") // ErrRebaseInProgress is returned when a git rebase is in progress, // which would interfere with transaction operations. ErrRebaseInProgress = errors.New("git rebase in progress") // ErrMergeInProgress is returned when a git merge is in progress, // which would interfere with transaction operations. ErrMergeInProgress = errors.New("git merge in progress") // ErrDetachedHead is returned when HEAD is not attached to a branch. // Agent operations may not work correctly in detached HEAD state. ErrDetachedHead = errors.New("repository is in detached HEAD state") // ErrCherryPickInProgress is returned when a cherry-pick operation is incomplete. // Complete or abort the cherry-pick before starting agent operations. ErrCherryPickInProgress = errors.New("cherry-pick in progress") // ErrBisectInProgress is returned when a git bisect is in progress. // Complete or reset the bisect before starting agent operations. ErrBisectInProgress = errors.New("git bisect in progress") // ErrDirtyWorkingTree is returned when uncommitted changes are present. // Commit, stash, or discard changes before starting agent operations. ErrDirtyWorkingTree = errors.New("uncommitted changes in working tree") // ErrTransactionExpired is returned when a transaction has exceeded // its TTL and was auto-rolled back. ErrTransactionExpired = errors.New("transaction expired") // ErrRollbackFailed is returned when rollback fails, leaving the // repository in an inconsistent state requiring manual intervention. ErrRollbackFailed = errors.New("rollback failed: manual intervention required") // ErrCheckpointNotFound is returned when the checkpoint reference // cannot be found (may have been garbage collected or corrupted). ErrCheckpointNotFound = errors.New("checkpoint not found") // ErrMaxFilesExceeded is returned when trying to track more files // than the configured maximum. ErrMaxFilesExceeded = errors.New("maximum tracked files exceeded") )
Functions ¶
func LoggerWithTrace ¶
LoggerWithTrace returns a logger with trace context fields.
Description ¶
Extracts trace_id and span_id from the context and adds them to the logger for correlation with distributed traces.
Inputs ¶
- ctx: Context that may contain trace information.
- logger: Base logger to extend.
Outputs ¶
- *slog.Logger: Logger with trace_id and span_id if available.
func SetMetricsEnabled ¶
func SetMetricsEnabled(enabled bool)
SetMetricsEnabled controls whether metrics are recorded.
Thread Safety: Safe for concurrent use.
func ValidateConfig ¶
func ValidateConfig(config PreFlightConfig) error
ValidateConfig validates a PreFlightConfig for consistency.
Description ¶
Returns an error if the configuration is invalid or contradictory.
Inputs ¶
- config: Configuration to validate.
Outputs ¶
- error: Non-nil if configuration is invalid.
Types ¶
type Config ¶
type Config struct {
// RepoPath is the git repository root directory.
// Must be an absolute path.
RepoPath string
// Strategy is the checkpoint strategy to use.
// Default: StrategyWorktree (prevents LSP/IDE conflicts)
// Note: Use StrategyBranch if worktrees not supported or disk space is a concern.
Strategy Strategy
// TransactionTTL is how long a transaction can be active before
// auto-rollback. Zero means no timeout.
// Default: 30 minutes
TransactionTTL time.Duration
// GitTimeout is the maximum time for a single git operation.
// Default: 30 seconds
GitTimeout time.Duration
// MaxTrackedFiles is the maximum number of files to track per transaction.
// Prevents memory exhaustion on large operations.
// Default: 10000
MaxTrackedFiles int
// StateDir is where transaction state is persisted for crash recovery.
// Default: {RepoPath}/.aleutian/transactions
StateDir string
// CleanupOnInit removes stale transactions on manager creation.
// Default: true
CleanupOnInit bool
// TracingEnabled controls whether OpenTelemetry spans are emitted.
// When false, uses noop tracer for zero overhead.
// Default: true
TracingEnabled bool
// MetricsEnabled controls whether Prometheus metrics are recorded.
// Default: true
MetricsEnabled bool
// PreFlight configures pre-flight repository state validation.
// These checks run before Begin() to prevent data loss.
PreFlight PreFlightConfig
}
Config configures the TransactionManager behavior.
func DefaultConfig ¶
func DefaultConfig() Config
DefaultConfig returns a Config with sensible defaults.
Note on Strategy Default ¶
The default is StrategyWorktree to prevent IDE/LSP conflicts. When the agent uses branch switching, the user's gopls/LSP sees thousands of file changes, causing cache invalidation and IDE freezes. Worktrees isolate agent work to a separate directory, leaving the user's workspace untouched.
Use StrategyBranch if:
- Git worktrees are not supported (older git versions)
- Disk space is constrained (worktrees require ~2x repo size)
- User explicitly requests branch-based isolation
type DefaultGitClient ¶
type DefaultGitClient struct {
// contains filtered or unexported fields
}
DefaultGitClient implements GitClient using the git command line.
Description ¶
Executes git commands with configurable timeout and working directory. All operations are performed in the configured repository path.
Thread Safety ¶
All methods are safe for concurrent use.
func NewGitClient ¶
func NewGitClient(repoPath string, timeout time.Duration) (*DefaultGitClient, error)
NewGitClient creates a new git client for the specified repository.
Description ¶
Creates a client that executes git commands in the given directory.
Inputs ¶
- repoPath: Absolute path to the git repository.
- timeout: Maximum duration for each git operation.
Outputs ¶
- *DefaultGitClient: Ready-to-use git client.
- error: Non-nil if repoPath is not absolute.
func (*DefaultGitClient) Add ¶
func (g *DefaultGitClient) Add(ctx context.Context, paths ...string) error
Add stages files for commit.
Description ¶
Stages the specified files for the next commit.
Inputs ¶
- ctx: Context for timeout and cancellation.
- paths: File paths to stage.
Outputs ¶
- error: Non-nil if staging fails.
func (*DefaultGitClient) AddAll ¶
func (g *DefaultGitClient) AddAll(ctx context.Context) error
AddAll stages all changes for commit.
Description ¶
Stages all tracked and untracked changes.
Inputs ¶
- ctx: Context for timeout and cancellation.
Outputs ¶
- error: Non-nil if staging fails.
func (*DefaultGitClient) BranchExists ¶
func (g *DefaultGitClient) BranchExists(ctx context.Context, name string) bool
BranchExists checks if a branch exists.
Description ¶
Uses `git show-ref` to check for branch existence.
Inputs ¶
- ctx: Context for timeout and cancellation.
- name: Branch name to check.
Outputs ¶
- bool: True if the branch exists.
func (*DefaultGitClient) Checkout ¶
func (g *DefaultGitClient) Checkout(ctx context.Context, ref string) error
Checkout switches to the specified ref.
Description ¶
Checks out a branch, tag, or commit SHA.
Inputs ¶
- ctx: Context for timeout and cancellation.
- ref: Branch name, tag, or commit SHA.
Outputs ¶
- error: Non-nil if checkout fails.
func (*DefaultGitClient) CleanUntracked ¶
func (g *DefaultGitClient) CleanUntracked(ctx context.Context) error
CleanUntracked removes untracked files and directories.
Description ¶
Removes all untracked files and directories from the working tree. Does not remove ignored files.
Inputs ¶
- ctx: Context for timeout and cancellation.
Outputs ¶
- error: Non-nil if clean fails.
func (*DefaultGitClient) Commit ¶
func (g *DefaultGitClient) Commit(ctx context.Context, message string) error
Commit creates a new commit with the staged changes.
Description ¶
Creates a commit with the specified message. Fails if nothing is staged.
Inputs ¶
- ctx: Context for timeout and cancellation.
- message: Commit message.
Outputs ¶
- error: Non-nil if commit fails.
func (*DefaultGitClient) CreateBranch ¶
func (g *DefaultGitClient) CreateBranch(ctx context.Context, name string) error
CreateBranch creates a new branch at the current HEAD.
Description ¶
Creates a branch without switching to it.
Inputs ¶
- ctx: Context for timeout and cancellation.
- name: Branch name to create.
Outputs ¶
- error: Non-nil if branch already exists or creation fails.
func (*DefaultGitClient) CreateWorktree ¶
CreateWorktree creates a new git worktree at the specified path.
Description ¶
Creates a detached worktree at the given path, checked out to the specified ref. The worktree is independent from the main working directory.
Inputs ¶
- ctx: Context for timeout and cancellation.
- path: Absolute path for the new worktree.
- ref: Git ref to checkout (branch, tag, or commit SHA).
Outputs ¶
- error: Non-nil if worktree creation fails.
func (*DefaultGitClient) DeleteBranch ¶
DeleteBranch deletes a branch.
Description ¶
Deletes the specified branch. Use force=true for unmerged branches.
Inputs ¶
- ctx: Context for timeout and cancellation.
- name: Branch name to delete.
- force: If true, force delete even if unmerged.
Outputs ¶
- error: Non-nil if deletion fails.
func (*DefaultGitClient) GetCurrentBranch ¶
func (g *DefaultGitClient) GetCurrentBranch(ctx context.Context) (string, error)
GetCurrentBranch returns the current branch name.
Description ¶
Returns the current branch name, or "HEAD" if in detached HEAD state.
Inputs ¶
- ctx: Context for timeout and cancellation.
Outputs ¶
- string: Branch name or "HEAD".
- error: Non-nil if not a git repository.
func (*DefaultGitClient) HasBisectInProgress ¶
func (g *DefaultGitClient) HasBisectInProgress(ctx context.Context) bool
HasBisectInProgress checks if a git bisect is in progress.
Description ¶
Checks for .git/BISECT_LOG file which indicates an active bisect session.
Inputs ¶
- ctx: Context for timeout and cancellation.
Outputs ¶
- bool: True if a bisect is in progress.
func (*DefaultGitClient) HasCherryPickInProgress ¶
func (g *DefaultGitClient) HasCherryPickInProgress(ctx context.Context) bool
HasCherryPickInProgress checks if a cherry-pick is in progress.
Description ¶
Checks for .git/CHERRY_PICK_HEAD file which indicates an incomplete cherry-pick.
Inputs ¶
- ctx: Context for timeout and cancellation.
Outputs ¶
- bool: True if a cherry-pick is in progress.
func (*DefaultGitClient) HasMergeInProgress ¶
func (g *DefaultGitClient) HasMergeInProgress(ctx context.Context) bool
HasMergeInProgress checks if a merge is in progress.
Description ¶
Checks for .git/MERGE_HEAD file.
Inputs ¶
- ctx: Context for timeout and cancellation.
Outputs ¶
- bool: True if a merge is in progress.
func (*DefaultGitClient) HasRebaseInProgress ¶
func (g *DefaultGitClient) HasRebaseInProgress(ctx context.Context) bool
HasRebaseInProgress checks if a rebase is in progress.
Description ¶
Checks for .git/rebase-merge or .git/rebase-apply directories.
Inputs ¶
- ctx: Context for timeout and cancellation.
Outputs ¶
- bool: True if a rebase is in progress.
func (*DefaultGitClient) HasStagedChanges ¶
func (g *DefaultGitClient) HasStagedChanges(ctx context.Context) bool
HasStagedChanges checks if there are staged changes.
Description ¶
Uses `git diff --cached` to check for staged changes.
Inputs ¶
- ctx: Context for timeout and cancellation.
Outputs ¶
- bool: True if there are staged changes.
func (*DefaultGitClient) HasUnstagedChanges ¶
func (g *DefaultGitClient) HasUnstagedChanges(ctx context.Context) bool
HasUnstagedChanges checks if there are unstaged changes.
Description ¶
Uses `git diff` to check for unstaged changes.
Inputs ¶
- ctx: Context for timeout and cancellation.
Outputs ¶
- bool: True if there are unstaged changes.
func (*DefaultGitClient) IsDetachedHead ¶
func (g *DefaultGitClient) IsDetachedHead(ctx context.Context) bool
IsDetachedHead checks if the repository is in detached HEAD state.
Description ¶
Returns true if HEAD is not pointing to a branch (detached HEAD state). This is detected when `git rev-parse --abbrev-ref HEAD` returns "HEAD".
Inputs ¶
- ctx: Context for timeout and cancellation.
Outputs ¶
- bool: True if in detached HEAD state.
func (*DefaultGitClient) IsGitRepository ¶
func (g *DefaultGitClient) IsGitRepository(ctx context.Context) bool
IsGitRepository checks if the path is a git repository.
Description ¶
Uses `git rev-parse --git-dir` to determine if inside a git repository.
Inputs ¶
- ctx: Context for timeout and cancellation.
Outputs ¶
- bool: True if the path is inside a git repository.
func (*DefaultGitClient) RefExists ¶
func (g *DefaultGitClient) RefExists(ctx context.Context, ref string) bool
RefExists checks if a git ref exists.
Description ¶
Uses `git show-ref` to check if the ref exists.
Inputs ¶
- ctx: Context for timeout and cancellation.
- ref: Git reference to check.
Outputs ¶
- bool: True if the ref exists.
func (*DefaultGitClient) RemoveWorktree ¶
RemoveWorktree removes a git worktree.
Description ¶
Removes the worktree at the specified path. The worktree directory is deleted. Use force=true to remove even if there are uncommitted changes.
Inputs ¶
- ctx: Context for timeout and cancellation.
- path: Absolute path to the worktree to remove.
- force: If true, force removal even with uncommitted changes.
Outputs ¶
- error: Non-nil if removal fails.
func (*DefaultGitClient) ResetHard ¶
func (g *DefaultGitClient) ResetHard(ctx context.Context, ref string) error
ResetHard performs a hard reset to the specified ref.
Description ¶
Resets the working tree and index to match the specified commit. All uncommitted changes are discarded.
Inputs ¶
- ctx: Context for timeout and cancellation.
- ref: Commit SHA or ref to reset to.
Outputs ¶
- error: Non-nil if reset fails.
func (*DefaultGitClient) RevParse ¶
RevParse resolves a git ref to a commit SHA.
Description ¶
Resolves references like HEAD, branch names, or tags to full SHA.
Inputs ¶
- ctx: Context for timeout and cancellation.
- ref: Git reference to resolve.
Outputs ¶
- string: Full commit SHA.
- error: Non-nil if ref doesn't exist.
func (*DefaultGitClient) StashDrop ¶
func (g *DefaultGitClient) StashDrop(ctx context.Context, ref string) error
StashDrop removes a stash entry.
Description ¶
Removes the specified stash from the stash list.
Inputs ¶
- ctx: Context for timeout and cancellation.
- ref: Stash reference (e.g., "stash@{0}").
Outputs ¶
- error: Non-nil if drop fails.
func (*DefaultGitClient) StashList ¶
func (g *DefaultGitClient) StashList(ctx context.Context) ([]StashEntry, error)
StashList returns all stash entries.
Description ¶
Parses the stash list into structured entries.
Inputs ¶
- ctx: Context for timeout and cancellation.
Outputs ¶
- []StashEntry: List of stash entries.
- error: Non-nil if listing fails.
func (*DefaultGitClient) StashPop ¶
func (g *DefaultGitClient) StashPop(ctx context.Context) error
StashPop applies and removes the top stash.
Description ¶
Applies the most recent stash and removes it from the stash list.
Inputs ¶
- ctx: Context for timeout and cancellation.
Outputs ¶
- error: Non-nil if pop fails (e.g., conflicts).
func (*DefaultGitClient) StashPush ¶
func (g *DefaultGitClient) StashPush(ctx context.Context, message string) error
StashPush creates a new stash with the given message.
Description ¶
Stashes all tracked changes with the specified message. Includes untracked files.
Inputs ¶
- ctx: Context for timeout and cancellation.
- message: Descriptive message for the stash.
Outputs ¶
- error: Non-nil if stash fails.
func (*DefaultGitClient) Status ¶
func (g *DefaultGitClient) Status(ctx context.Context) (*GitStatus, error)
Status returns the current git status.
Description ¶
Parses `git status --porcelain` into a structured GitStatus.
Inputs ¶
- ctx: Context for timeout and cancellation.
Outputs ¶
- *GitStatus: Current repository status.
- error: Non-nil if status fails.
func (*DefaultGitClient) WorktreeList ¶
func (g *DefaultGitClient) WorktreeList(ctx context.Context) ([]WorktreeEntry, error)
WorktreeList returns all worktrees in the repository.
Description ¶
Parses the output of `git worktree list --porcelain` into structured entries.
Inputs ¶
- ctx: Context for timeout and cancellation.
Outputs ¶
- []WorktreeEntry: List of all worktrees including the main one.
- error: Non-nil if listing fails.
type GitClient ¶
type GitClient interface {
// IsGitRepository checks if the path is a git repository.
IsGitRepository(ctx context.Context) bool
// HasRebaseInProgress checks if a rebase is in progress.
HasRebaseInProgress(ctx context.Context) bool
// HasMergeInProgress checks if a merge is in progress.
HasMergeInProgress(ctx context.Context) bool
// IsDetachedHead checks if HEAD is detached (not on a branch).
IsDetachedHead(ctx context.Context) bool
// HasCherryPickInProgress checks if a cherry-pick is in progress.
HasCherryPickInProgress(ctx context.Context) bool
// HasBisectInProgress checks if a git bisect is in progress.
HasBisectInProgress(ctx context.Context) bool
// GetCurrentBranch returns the current branch name, or "HEAD" if detached.
GetCurrentBranch(ctx context.Context) (string, error)
// RevParse resolves a git ref to a commit SHA.
RevParse(ctx context.Context, ref string) (string, error)
// RefExists checks if a git ref exists.
RefExists(ctx context.Context, ref string) bool
// Stash operations
StashPush(ctx context.Context, message string) error
StashPop(ctx context.Context) error
StashDrop(ctx context.Context, ref string) error
StashList(ctx context.Context) ([]StashEntry, error)
// Branch operations
CreateBranch(ctx context.Context, name string) error
DeleteBranch(ctx context.Context, name string, force bool) error
Checkout(ctx context.Context, ref string) error
BranchExists(ctx context.Context, name string) bool
// Reset operations
ResetHard(ctx context.Context, ref string) error
CleanUntracked(ctx context.Context) error
// Commit operations
Add(ctx context.Context, paths ...string) error
AddAll(ctx context.Context) error
Commit(ctx context.Context, message string) error
HasStagedChanges(ctx context.Context) bool
HasUnstagedChanges(ctx context.Context) bool
// Status
Status(ctx context.Context) (*GitStatus, error)
// Worktree operations
CreateWorktree(ctx context.Context, path string, ref string) error
RemoveWorktree(ctx context.Context, path string, force bool) error
WorktreeList(ctx context.Context) ([]WorktreeEntry, error)
}
GitClient abstracts git operations for testing.
Description ¶
Implementations must be safe for concurrent use.
type GitStatus ¶
type GitStatus struct {
// Branch is the current branch name.
Branch string
// IsClean is true if there are no uncommitted changes.
IsClean bool
// StagedFiles are files staged for commit.
StagedFiles []string
// ModifiedFiles are files with unstaged changes.
ModifiedFiles []string
// UntrackedFiles are untracked files.
UntrackedFiles []string
}
GitStatus represents the current git working tree status.
type Manager ¶
type Manager struct {
// contains filtered or unexported fields
}
Manager provides atomic file operations with git-based rollback.
Description ¶
TransactionManager wraps file operations in git checkpoints. On failure, all changes can be rolled back to the pre-transaction state. On success, changes can be committed as a single atomic unit.
Thread Safety ¶
All public methods are safe for concurrent use. Only one transaction may be active at a time.
Nested Transactions ¶
Nested transactions are NOT supported. Calling Begin() while a transaction is active returns ErrTransactionActive.
func NewManager ¶
NewManager creates a new transaction manager.
Description ¶
Creates a manager with the specified configuration. If CleanupOnInit is true, recovers or cleans up any stale transactions from previous crashed sessions.
Inputs ¶
- config: Manager configuration. Use DefaultConfig() for defaults.
Outputs ¶
- *Manager: Ready-to-use transaction manager.
- error: Non-nil if setup fails.
Example ¶
config := transaction.DefaultConfig()
config.RepoPath = "/path/to/repo"
manager, err := transaction.NewManager(config)
if err != nil {
return err
}
defer manager.Close()
func NewManagerWithGit ¶
NewManagerWithGit creates a manager with a custom git client (for testing).
Description ¶
Allows injection of a mock GitClient for testing.
Inputs ¶
- config: Manager configuration.
- git: Custom git client implementation.
Outputs ¶
- *Manager: Ready-to-use transaction manager.
- error: Non-nil if setup fails.
func (*Manager) Active ¶
func (m *Manager) Active() *Transaction
Active returns the currently active transaction, or nil if none.
Description ¶
Returns a copy of the active transaction for inspection. The returned Transaction should not be modified.
Outputs ¶
- *Transaction: Copy of active transaction, or nil.
func (*Manager) Begin ¶
Begin starts a new transaction with a checkpoint.
Description ¶
Creates a checkpoint of the current git state. All subsequent file modifications can be rolled back to this point. Only one transaction may be active at a time.
Inputs ¶
- ctx: Context for timeout and cancellation.
- sessionID: Identifier for the agent session (for logging/debugging).
Outputs ¶
- *Transaction: The active transaction.
- error: ErrTransactionActive if a transaction is already in progress, ErrNotGitRepository if not a git repo, or other errors on failure.
Example ¶
tx, err := manager.Begin(ctx, "session-123")
if err != nil {
return err
}
// ... make changes ...
if failed {
manager.Rollback(ctx, "operation failed")
} else {
manager.Commit(ctx, "completed task")
}
func (*Manager) Close ¶
Close cleans up the manager.
Description ¶
If a transaction is active, it is rolled back. Auto-stashed changes are restored. Resources are released.
Outputs ¶
- error: Non-nil if rollback fails.
func (*Manager) Commit ¶
Commit finalizes the transaction and persists changes.
Description ¶
Completes the transaction, making all changes permanent. The checkpoint is removed. After commit, no rollback is possible.
Inputs ¶
- ctx: Context for timeout and cancellation.
- message: Commit message describing the changes.
Outputs ¶
- *Result: Information about the completed transaction.
- error: ErrNoTransaction if no transaction is active, or other errors.
func (*Manager) RecordModification ¶
RecordModification tracks a file change for auditing.
Description ¶
Records that a file was modified during this transaction. This is used for logging and debugging - the actual rollback uses git state.
Inputs ¶
- filePath: Path to the modified file.
Outputs ¶
- error: ErrMaxFilesExceeded if limit reached, nil otherwise.
func (*Manager) RecordModifications ¶
RecordModifications tracks multiple file changes.
Description ¶
Batch version of RecordModification for efficiency.
Inputs ¶
- paths: Paths to modified files.
Outputs ¶
- error: ErrMaxFilesExceeded if limit would be exceeded.
func (*Manager) Rollback ¶
Rollback discards all changes and restores to checkpoint.
Description ¶
Reverts all changes made since Begin() was called. The repository is restored to the exact state it was in when the transaction started.
Inputs ¶
- ctx: Context for timeout and cancellation. Note: rollback uses a background context internally to ensure completion even if ctx is cancelled.
- reason: Human-readable reason for the rollback (for logging).
Outputs ¶
- *Result: Information about the rolled-back transaction.
- error: ErrNoTransaction if no transaction is active, ErrRollbackFailed if rollback itself fails.
type PreFlightConfig ¶
type PreFlightConfig struct {
// Force skips the dirty working tree check (dangerous).
// Use only when you're certain the agent won't conflict with user changes.
Force bool
// AutoStash automatically stashes user changes before operations
// and restores them after. Conflicts may still occur on restore.
AutoStash bool
// AllowDetached permits operations in detached HEAD state.
// Useful for CI/CD pipelines that checkout specific commits.
AllowDetached bool
}
PreFlightConfig configures pre-flight check behavior.
Description ¶
Controls how the pre-flight guard validates repository state before allowing agent operations to proceed.
type PreFlightError ¶
type PreFlightError struct {
// Code is a machine-readable error identifier.
Code string
// Message is a human-readable description of the error.
Message string
// Details contains additional information, such as affected files
// or remediation steps.
Details []string
}
PreFlightError represents a fatal issue that blocks execution.
Description ¶
Contains structured error information for programmatic handling and human-readable messages for display.
func (*PreFlightError) Error ¶
func (e *PreFlightError) Error() string
Error implements the error interface.
type PreFlightGuard ¶
type PreFlightGuard struct {
// contains filtered or unexported fields
}
PreFlightGuard performs repository state validation before agent operations.
Description ¶
Validates that the repository is in a safe state for agent operations. This prevents data loss from agent modifications overwriting user's uncommitted work.
Thread Safety ¶
All methods are safe for concurrent use.
func NewPreFlightGuard ¶
func NewPreFlightGuard(git GitClient, config PreFlightConfig, logger *slog.Logger) *PreFlightGuard
NewPreFlightGuard creates a new pre-flight guard.
Description ¶
Creates a guard configured with the specified options.
Inputs ¶
- git: Git client for repository operations. Must not be nil.
- config: Configuration options.
- logger: Logger for diagnostic output (can be nil for no logging).
Outputs ¶
- *PreFlightGuard: Ready-to-use guard.
Panics ¶
- Panics if git is nil.
func (*PreFlightGuard) Check ¶
func (g *PreFlightGuard) Check(ctx context.Context) (*PreFlightResult, error)
Check performs all pre-flight validations.
Description ¶
Validates the repository state against all configured checks. Returns a result with Passed=true if the repository is safe for agent operations.
Inputs ¶
- ctx: Context for timeout and cancellation.
Outputs ¶
- *PreFlightResult: Check outcomes including errors, warnings, and stash ref.
- error: Non-nil only if the check itself failed (not if checks didn't pass).
Example ¶
guard := NewPreFlightGuard(git, config, logger)
result, err := guard.Check(ctx)
if err != nil {
return fmt.Errorf("preflight check failed: %w", err)
}
if !result.Passed {
return result.FirstError()
}
// Safe to proceed with agent operations
func (*PreFlightGuard) Cleanup ¶
func (g *PreFlightGuard) Cleanup(ctx context.Context, stashRef string) error
Cleanup restores stashed changes after agent operations complete.
Description ¶
If AutoStash was used during Check(), this method restores the stashed changes. Should be called regardless of whether agent operations succeeded or failed.
Inputs ¶
- ctx: Context for timeout and cancellation.
- stashRef: The StashRef from PreFlightResult. If empty, does nothing.
Outputs ¶
- error: Non-nil if restore failed. May indicate conflicts that need manual resolution.
Example ¶
defer func() {
if err := guard.Cleanup(ctx, result.StashRef); err != nil {
log.Warn("failed to restore stashed changes", "error", err)
}
}()
type PreFlightResult ¶
type PreFlightResult struct {
// Passed is true if all checks passed (no fatal errors).
Passed bool
// Errors are fatal issues that block execution.
Errors []PreFlightError
// Warnings are non-fatal issues the user should be aware of.
Warnings []PreFlightWarning
// StashRef is set if AutoStash was used, containing the stash reference.
// The caller must call Cleanup() with this reference after operations complete.
StashRef string
}
PreFlightResult contains the outcomes of pre-flight validation.
Description ¶
Aggregates all errors and warnings from the pre-flight checks. If Passed is false, at least one error is present and the operation should not proceed.
func (*PreFlightResult) FirstError ¶
func (r *PreFlightResult) FirstError() error
FirstError returns the first error, or nil if no errors.
Description ¶
Convenience method for returning a single error from the result.
func (*PreFlightResult) FormatErrors ¶
func (r *PreFlightResult) FormatErrors() string
FormatErrors returns a human-readable multi-line error summary.
Description ¶
Formats all errors with their details for display to the user.
type PreFlightWarning ¶
type PreFlightWarning struct {
// Code is a machine-readable warning identifier.
Code string
// Message is a human-readable description of the warning.
Message string
}
PreFlightWarning represents a non-fatal issue.
Description ¶
Warnings don't block execution but should be communicated to the user.
type Result ¶
type Result struct {
// TransactionID is the completed transaction's ID.
TransactionID string
// Status is the final status.
Status Status
// Duration is how long the transaction was active.
Duration time.Duration
// FilesModified is the count of files changed.
FilesModified int
// CommitSHA is the new commit SHA (if committed).
CommitSHA string
// RollbackReason is why the transaction was rolled back (if applicable).
RollbackReason string
}
Result contains information about a completed transaction.
type StashEntry ¶
StashEntry represents a git stash entry.
type Status ¶
type Status string
Status represents the current state of a transaction.
const ( // StatusIdle indicates no active transaction. StatusIdle Status = "idle" // StatusActive indicates a transaction is in progress. StatusActive Status = "active" // StatusCommitting indicates a commit is in progress. StatusCommitting Status = "committing" // StatusRollingBack indicates a rollback is in progress. StatusRollingBack Status = "rolling_back" // StatusCommitted indicates the transaction was successfully committed. StatusCommitted Status = "committed" // StatusRolledBack indicates the transaction was rolled back. StatusRolledBack Status = "rolled_back" // StatusFailed indicates the transaction failed (rollback also failed). StatusFailed Status = "failed" )
func (Status) IsTerminal ¶
IsTerminal returns true if the status is a terminal state.
type Strategy ¶
type Strategy string
Strategy defines how checkpoints are created and managed.
const ( // StrategyStash uses git stash to save the current state. // Pros: Simple, no branch pollution. // Cons: Can conflict on pop, limited metadata. // Best for: Small changes, quick operations. StrategyStash Strategy = "stash" // StrategyBranch creates a temporary branch for the transaction. // Pros: Clean history, easy to inspect agent's work. // Cons: More git operations, potential merge conflicts. // Best for: Complex changes, long-running transactions. StrategyBranch Strategy = "branch" // StrategyWorktree creates an isolated git worktree. // Pros: Complete isolation, can't corrupt original. // Cons: More disk space, path management complexity. // Best for: Sandboxed operations, parallel transactions. StrategyWorktree Strategy = "worktree" )
type Tracer ¶
type Tracer struct {
// contains filtered or unexported fields
}
Tracer provides OpenTelemetry tracing for transaction operations.
Description ¶
Wraps the OpenTelemetry tracer with transaction-specific span creation and attribute management. When disabled, returns noop spans for zero overhead.
Thread Safety ¶
All methods are safe for concurrent use.
func NewTracer ¶
NewTracer creates a new transaction tracer.
Inputs ¶
- logger: Logger for structured logging. Uses slog.Default() if nil.
- enabled: Whether tracing is enabled. When false, uses noop spans.
Outputs ¶
- *Tracer: Ready-to-use tracer instance.
func (*Tracer) EndBegin ¶
func (t *Tracer) EndBegin(span trace.Span, tx *Transaction, err error)
EndBegin completes a transaction begin span.
Inputs ¶
- span: The span to end.
- tx: The created transaction (may be nil on error).
- err: Error if begin failed.
func (*Tracer) EndCommit ¶
EndCommit completes a transaction commit span.
Inputs ¶
- span: The span to end.
- result: The commit result (may be nil on error).
- err: Error if commit failed.
func (*Tracer) EndGitOp ¶
EndGitOp completes a git operation span.
Inputs ¶
- span: The span to end.
- err: Error if the operation failed.
func (*Tracer) EndRollback ¶
EndRollback completes a transaction rollback span.
Inputs ¶
- span: The span to end.
- result: The rollback result (may be nil on error).
- err: Error if rollback failed.
func (*Tracer) RecordExpiration ¶
RecordExpiration records a transaction expiration event.
Inputs ¶
- ctx: Context containing the active span.
- txID: Transaction identifier.
func (*Tracer) RecordStateTransition ¶
func (t *Tracer) RecordStateTransition(ctx context.Context, txID string, from, to Status, duration time.Duration)
RecordStateTransition records a state transition event on the current span.
Inputs ¶
- ctx: Context containing the active span.
- txID: Transaction identifier.
- from: Previous state.
- to: New state.
- duration: Time spent in the previous state.
func (*Tracer) StartBegin ¶
func (t *Tracer) StartBegin(ctx context.Context, sessionID string, strategy Strategy) (context.Context, trace.Span)
StartBegin starts a span for a transaction begin operation.
Inputs ¶
- ctx: Parent context for span creation.
- sessionID: Agent session identifier.
- strategy: Checkpoint strategy being used.
Outputs ¶
- context.Context: Context with span attached.
- trace.Span: The created span. Caller must call End() when done.
func (*Tracer) StartCommit ¶
func (t *Tracer) StartCommit(ctx context.Context, tx *Transaction, message string) (context.Context, trace.Span)
StartCommit starts a span for a transaction commit operation.
Inputs ¶
- ctx: Parent context for span creation.
- tx: The transaction being committed.
- message: Commit message.
Outputs ¶
- context.Context: Context with span attached.
- trace.Span: The created span. Caller must call End() when done.
func (*Tracer) StartGitOp ¶
StartGitOp starts a child span for a git operation.
Inputs ¶
- ctx: Parent context (should contain parent span).
- operation: Name of the git operation (e.g., "create_branch", "reset_hard").
Outputs ¶
- context.Context: Context with span attached.
- trace.Span: The created span. Caller must call End() when done.
func (*Tracer) StartRollback ¶
func (t *Tracer) StartRollback(ctx context.Context, tx *Transaction, reason string) (context.Context, trace.Span)
StartRollback starts a span for a transaction rollback operation.
Inputs ¶
- ctx: Parent context for span creation.
- tx: The transaction being rolled back.
- reason: Why the rollback is occurring.
Outputs ¶
- context.Context: Context with span attached.
- trace.Span: The created span. Caller must call End() when done.
type Transaction ¶
type Transaction struct {
// ID is the unique identifier for this transaction.
ID string `json:"id"`
// SessionID links the transaction to an agent session.
SessionID string `json:"session_id"`
// StartedAt is when the transaction began (Unix milliseconds UTC).
StartedAt int64 `json:"started_at"`
// ExpiresAt is when the transaction will auto-rollback if not completed (Unix milliseconds UTC).
ExpiresAt int64 `json:"expires_at"`
// CheckpointRef is the git ref (commit SHA) to restore on rollback.
CheckpointRef string `json:"checkpoint_ref"`
// OriginalBranch is the branch we started on.
OriginalBranch string `json:"original_branch"`
// WorkBranch is the temporary branch name (for branch strategy).
WorkBranch string `json:"work_branch,omitempty"`
// WorktreePath is the worktree directory (for worktree strategy).
WorktreePath string `json:"worktree_path,omitempty"`
// StashRef is the stash reference (for stash strategy).
StashRef string `json:"stash_ref,omitempty"`
// ModifiedFiles tracks files changed during the transaction.
// Stored as a map for O(1) deduplication.
ModifiedFiles map[string]struct{} `json:"modified_files"`
// Status is the current transaction state.
Status Status `json:"status"`
// Strategy used for this transaction.
Strategy Strategy `json:"strategy"`
// RollbackReason is set if the transaction was rolled back.
RollbackReason string `json:"rollback_reason,omitempty"`
// Error is set if the transaction failed.
Error string `json:"error,omitempty"`
}
Transaction represents an active transactional checkpoint.
Description ¶
A Transaction captures the state at Begin() and allows either committing changes or rolling back to the captured state.
Thread Safety ¶
Transaction objects should only be accessed through the TransactionManager.
func (*Transaction) Duration ¶
func (t *Transaction) Duration() time.Duration
Duration returns how long the transaction has been active.
func (*Transaction) FileCount ¶
func (t *Transaction) FileCount() int
FileCount returns the number of files modified in this transaction.
func (*Transaction) Files ¶
func (t *Transaction) Files() []string
Files returns the list of modified files as a slice.
func (*Transaction) IsExpired ¶
func (t *Transaction) IsExpired() bool
IsExpired returns true if the transaction has exceeded its TTL.
type WorktreeEntry ¶
type WorktreeEntry struct {
// Path is the absolute filesystem path to the worktree.
Path string
// HEAD is the current commit SHA of the worktree.
HEAD string
// Branch is the branch name, or empty string if detached HEAD.
Branch string
// Locked indicates if the worktree is locked.
Locked bool
}
WorktreeEntry represents a git worktree.