git

package
v0.156.0 Latest Latest
Warning

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

Go to latest
Published: Sep 10, 2026 License: Apache-2.0 Imports: 24 Imported by: 0

Documentation

Index

Constants

View Source
const (
	FreshnessUnknown      = "unknown"
	FreshnessLocalChanges = "local changes"
)

Freshness status values returned by RepoFreshness. Exported since callers outside this package (e.g. cmd/agentico) switch on these literal strings.

View Source
const (
	PRStateOpen   = "open"
	PRStateClosed = "closed"
	PRStateMerged = "merged"
)

Pull-request states PRState can report.

View Source
const (
	CommentTypeReview     = "review"
	CommentTypeIssue      = "issue"
	CommentTypeReviewBody = "review_body"
)

PR comment type constants.

View Source
const (
	// AgenticURL is the public repository URL for attribution.
	AgenticURL = "https://github.com/doordash-oss/agentic-orchestrator"

	// AgenticoCommitEmail is the noreply address Agentico co-authors
	// programmatic commits under. GitHub matches co-author trailers to
	// profiles by email; a noreply address keeps attribution without
	// implying a human mailbox.
	AgenticoCommitEmail = "noreply@doordash-oss.github.com"

	// AgenticoName is the display name for Agentico's commit attribution.
	AgenticoName = "Agentico"

	// CommitSignatureTrailer is appended to programmatic commit messages as
	// a git trailer. Uses the Co-authored-by convention so GitHub renders
	// Agentico as a co-author on commits and pull requests.
	CommitSignatureTrailer = "Co-authored-by: " + AgenticoName + " <" + AgenticoCommitEmail + ">"

	// PRSignature is the markdown signature appended to PR bodies and comments.
	PRSignature = "\n\n---\n\n*Generated with [agentic orchestrator](" + AgenticURL + ")*"
)
View Source
const (
	LocalSourceModeDefault LocalSourceMode = "default"
	LocalSourceModeCurrent LocalSourceMode = "current"
	LocalSourceBranch                      = "branch"
	LocalSourceDetached                    = "detached"
)
View Source
const CrossRefSectionHeader = "## Related PRs"

CrossRefSectionHeader is the markdown header for the cross-reference section.

View Source
const DefaultCleanlinessPathLimit = 50

DefaultCleanlinessPathLimit caps each categorized path list in a CleanlinessReport so dirty-worktree diagnostics stay bounded.

View Source
const ProbeCacheMaxEntries = 512

ProbeCacheMaxEntries bounds how many worktrees a cache tracks. Keys are worktree paths, and children come and go, so an unbounded map would grow for the lifetime of the process.

View Source
const ProbeCacheTTL = 5 * time.Second

ProbeCacheTTL is how long a probe result is served before a background refresh is scheduled. Read paths poll far more often than a worktree changes, so anything shorter buys accuracy nobody can perceive at the cost of a subprocess per request.

Variables

View Source
var (
	// ErrInitializeNotARepository reports that the path is not a git
	// repository (replaced or removed since discovery).
	ErrInitializeNotARepository = errors.New("path is not a git repository")
	// ErrInitializeOperationActive reports an in-progress merge, rebase,
	// cherry-pick or revert in the repository.
	ErrInitializeOperationActive = errors.New("a merge, rebase, cherry-pick or revert is in progress")
	// ErrInitializeContentPresent reports staged, unstaged or untracked
	// user content in the repository.
	ErrInitializeContentPresent = errors.New("repository has staged, unstaged or untracked content")
	// ErrInitializeIdentityChanged reports that the repository no longer
	// matches the server-resolved identity that authorized the operation.
	ErrInitializeIdentityChanged = errors.New("repository identity changed before initialization")
	// ErrInitializeProbeFailed reports that repository state could not be
	// proved (probe failure, timeout or unexpected git output). Callers
	// must treat it as indeterminate, never as unborn or clean.
	ErrInitializeProbeFailed = errors.New("repository state could not be proved")
)

Eligibility conditions that the caller maps onto canonical refusal codes. They are distinguished errors — never classified from output text — so a failed probe can never be mistaken for a refusal or for an unborn repo.

View Source
var CleanlinessProbeTimeout = 20 * time.Second

CleanlinessProbeTimeout bounds `status --untracked-files=all`, which walks every untracked directory and so routinely runs several times longer than the cheap probes on a multi-gigabyte worktree. It needs its own headroom: a bound below the honest runtime turns a slow-but-healthy repo into a permanently indeterminate one, which fails closed and strands the actions it gates.

View Source
var ErrCleanlinessUnknown = errors.New("git worktree cleanliness is unknown")

ErrCleanlinessUnknown reports that no cleanliness result is available for a worktree yet: the first probe is still running, or a previous one failed. Callers gating destructive or refactor work must treat it as indeterminate — never as a clean worktree.

View Source
var ErrLocalSourceMissing = errors.New("local source is missing")
View Source
var ErrLocalSourceStale = errors.New("local source selection is stale")
View Source
var ErrProbeTimeout = errors.New("git probe timed out")

ErrProbeTimeout reports that a git probe exceeded ProbeTimeout. Callers must treat it as indeterminate, never as a clean or in-sync worktree.

View Source
var ErrSourceUpdateRefCASMismatch = errors.New("source update ref compare-and-swap mismatch")

ErrSourceUpdateRefCASMismatch reports that the ref's current value no longer matches the expected old value, so the mutation was refused.

View Source
var ErrSourceUpdateUnavailable = errors.New("source update unavailable")

ErrSourceUpdateUnavailable reports an attempt that could not prove a safe outcome: inspection failure, fetch failure, deadline expiry, or an ambiguous mutation boundary. It never claims the branch was rolled back or that a completed mutation failed.

View Source
var ErrWorktreeBusy = errors.New("git worktree mutation is in progress")

ErrWorktreeBusy reports that a cached read probe yielded to an in-flight worktree mutation. It provides no evidence about repository cleanliness.

View Source
var ForcePushFunc = defaultForcePush

ForcePushFunc is the function used by ForcePush. Tests can replace it to avoid real git-push operations.

View Source
var HeadProbeTimeout = 5 * time.Second

HeadProbeTimeout bounds HasHead invocations.

View Source
var IdentityProbeTimeout = 5 * time.Second

IdentityProbeTimeout bounds ResolveRepoIdentity invocations.

View Source
var ProbeTimeout = 3 * time.Second

ProbeTimeout bounds the cheap read-only git probes (freshness status/rev-parse/rev-list) so a hung git — cold cache on a huge worktree, network filesystem, index.lock contention — degrades to an indeterminate answer instead of stalling the caller. Overridable in tests.

View Source
var PushFunc = defaultPush

PushFunc is the function used by Push. Tests can replace it to avoid real git-push operations (e.g. when corporate hooks block pushes to local repos).

Functions

func BranchExistsOnRemote

func BranchExistsOnRemote(repoPath, branch string) bool

BranchExistsOnRemote checks whether a branch exists on the origin remote. Returns false if the bounded probe is unavailable or confirms absence. New callers should use ProbeRemoteBranch to retain the tri-state result.

func BranchName

func BranchName(featureSlug string) string

BranchName returns the full branch name for a feature.

func BuildCrossReferenceSection

func BuildCrossReferenceSection(featureName string, entries []CrossRefEntry) string

BuildCrossReferenceSection builds a markdown table of related PRs for a multi-repo feature. Returns empty string if there are fewer than 2 entries (no cross-refs for single-repo).

func ClosePR

func ClosePR(prURL string) error

ClosePR closes a GitHub PR by URL. Errors are returned but callers should treat them as non-fatal.

func CommitAll

func CommitAll(worktreePath, message string) error

CommitAll stages all changes (including untracked files) and creates a commit. The Agentic signature trailer is automatically appended to the commit message.

func CommitAllAndGetHead

func CommitAllAndGetHead(worktreePath, message string) (string, error)

CommitAllAndGetHead stages all changes, creates a commit when needed, and returns the full HEAD SHA after the operation. A clean worktree is not an error; the existing HEAD SHA is returned.

func CommitBodies

func CommitBodies(worktreePath string, baseBranch ...string) (string, error)

CommitBodies returns the full commit messages (subject + body) between the worktree branch and its base branch, separated by blank lines. Feeds PR description generation where the short oneline log is not descriptive enough.

func ConflictMarkerFiles added in v0.149.0

func ConflictMarkerFiles(worktreePath string) ([]string, error)

ConflictMarkerFiles lists the tracked files in the worktree at worktreePath that contain literal git conflict marker lines. The scan matches the `git grep`-based contract the generated rebase-child prompt and exit criteria already impose: the three conflict markers (start, middle separator, end) searched as anchored line expressions. A file must contain all three forms to be reported, so ordinary headings and dividers do not trip the gate. It is a literal marker scan, not an unmerged-index check. After the transaction commits child changes, `git diff --name-only --diff-filter=U` is vacuous, so only a content scan can prove a worktree is free of markers.

The marker patterns are constructed from split strings so this source file does not itself contain the literal marker sequences and false-positive on its own content.

Untracked files are ignored: `git grep` searches only tracked files. A clean tree returns an empty slice with a nil error. A git failure returns a nil slice and the error so callers can fail closed.

func CreateBackupBranch

func CreateBackupBranch(worktreePath, slug string) (string, error)

CreateBackupBranch creates a backup branch at the current HEAD in the given worktree. Returns the branch name. Format: feature/<slug>-pre-rewind-<unix_timestamp>

func CreatePR

func CreatePR(repoPath, branch, title, body string, draft bool, baseBranch ...string) (string, error)

CreatePR creates a GitHub PR for the branch pushed from repoPath. If baseBranch is provided and non-empty, the PR targets that branch instead of the repository's default branch (for stacked PRs). When draft is true the PR is created as a draft. If a PR already exists for the branch, the existing PR URL is returned instead of an error (the push already updated the remote branch).

func CreateRepository added in v0.156.0

func CreateRepository(ctx context.Context, dir string) error

CreateRepository builds a fresh repository inside dir: exactly one empty initial commit on the main branch, authored and committed with Agentico's explicit identity, with no remote and no push. The caller owns all path validation and isolation (dir is staged, hidden and ownership-marked before this runs); this adapter only performs the bounded git operations.

Every setting that could change the promised result is explicit on the command line: an empty template overrides a global init.templateDir, --initial-branch pins main over a global init.defaultBranch, and the commit's identity, signing and hooks are forced so no inherited global configuration can alter the author, add a signature, run hooks or change the message. The result is verified (branch and HEAD) before success is reported, so hostile configuration fails loudly instead of publishing a different repository.

func CurrentBranch

func CurrentBranch(repoPath string) string

CurrentBranch returns the branch currently checked out in the given repo.

func CurrentHeadSHA

func CurrentHeadSHA(worktreePath string) (string, error)

CurrentHeadSHA returns the full SHA of HEAD in the given worktree.

func DefaultBranch

func DefaultBranch(repoPath string) string

DefaultBranch returns the default branch for a repo by checking the remote HEAD, then the local HEAD symref, then falling back to well-known names (main, master).

func DiffStat

func DiffStat(worktreePath string, baseBranch ...string) (string, error)

DiffStat returns a per-file summary of additions/deletions between the worktree branch and its base branch. Useful as a compact signal of scope when the full diff is too large to prompt with.

func DiffSummary

func DiffSummary(worktreePath string, baseBranch ...string) (string, error)

DiffSummary returns the diff between the worktree branch and its base branch, including both committed and uncommitted (staged + unstaged) changes. If baseBranch is empty, it falls back to main/master.

func ExtractCrossReferenceSection

func ExtractCrossReferenceSection(body string) string

ExtractCrossReferenceSection extracts the cross-reference section from a PR body. Returns the section including the header, trimmed of trailing whitespace. Returns empty string if no cross-reference section is found.

func Fetch

func Fetch(worktreePath string) error

Fetch fetches the latest changes from origin for a worktree.

func FetchReviewThreadMap

func FetchReviewThreadMap(_ string, prURL string) (map[int]string, error)

FetchReviewThreadMap returns comment database ID → unresolved thread node ID for the PR. repoPath is retained for signature stability.

func ForcePush

func ForcePush(worktreePath, branch string) error

ForcePush force-pushes the current branch to origin.

func FormatIdentityDevice added in v0.156.0

func FormatIdentityDevice(v uint64) string

FormatIdentityDevice renders a device id as the decimal text used on the wire so 64-bit values stay exact in every client language.

func FormatIdentityInode added in v0.156.0

func FormatIdentityInode(v uint64) string

FormatIdentityInode renders an inode as decimal wire text.

func GetPRBody

func GetPRBody(prURL string) (string, error)

GetPRBody fetches the body of a GitHub PR by URL.

func HasHead added in v0.156.0

func HasHead(dir string) bool

HasHead reports whether the git repository at dir has at least one commit on HEAD. A repository without commits (an unborn branch, e.g. right after cloning an empty remote) is still a valid repository but cannot start feature work.

func HasOriginRemote

func HasOriginRemote(repoPath string) bool

HasOriginRemote returns true if the repo at repoPath has an "origin" remote configured.

func HasUncommittedChanges

func HasUncommittedChanges(worktreePath string) bool

HasUncommittedChanges returns true if the worktree has staged, unstaged, or untracked changes.

func HasUncommittedChangesExcludingUntracked added in v0.154.0

func HasUncommittedChangesExcludingUntracked(worktreePath string, names ...string) (bool, error)

HasUncommittedChangesExcludingUntracked reports whether the worktree has staged, unstaged, or untracked changes, disregarding untracked entries whose path is in names. Tracked changes to those paths still count — only never-committed files matching the known-artifact names are ignored. A probe failure is surfaced as an error so an indeterminate worktree never reads as clean.

func InitRepository added in v0.149.0

func InitRepository(path string) error

InitRepository initializes a new git repository in the existing directory at path and creates an initial empty commit so HEAD resolves immediately (worktree setup requires a born HEAD). The caller owns all path validation (containment, emptiness, symlink resolution) — this adapter only performs the git operations.

func InjectCrossReferenceSection

func InjectCrossReferenceSection(body, section string) string

InjectCrossReferenceSection inserts the cross-reference section into a PR body. If the body already contains a cross-reference section, it is replaced. The section is placed before the PRSignature if present, otherwise appended.

func InjectPRSignature

func InjectPRSignature(body string) string

InjectPRSignature appends the agentic orchestrator signature to a PR body or comment. Idempotent — skips if the signature is already present.

func IsAncestor added in v0.149.0

func IsAncestor(repoPath, ancestor, descendant string) bool

IsAncestor reports whether ancestor is an ancestor of descendant in the repository at repoPath. It shells out to `git merge-base --is-ancestor <ancestor> <descendant>`, which exits 0 when the relationship holds and non-zero otherwise.

The primitive is conservative: it returns false on any git error, unknown commit, or when either argument is empty. Callers that need to distinguish "definitely not an ancestor" from "git could not answer" should run their own command; this boolean is for safety gates where a false result simply withholds a positive assertion.

func IsBehindLocal

func IsBehindLocal(worktreePath, baseBranch string) bool

IsBehindLocal checks if the current branch is behind a local base branch. Returns true if there are commits on baseBranch not in the current branch.

func IsBehindRemote

func IsBehindRemote(worktreePath, baseBranch string) bool

IsBehindRemote checks if the local branch is behind the remote base branch. Returns true if there are commits on origin/<baseBranch> not in the local branch.

func LatestCommitSHA

func LatestCommitSHA(worktreePath string) (string, error)

LatestCommitSHA returns the short SHA of HEAD in the given directory.

func LockRepositories added in v0.156.0

func LockRepositories(repoPaths []string) func()

LockRepositories serializes an operation with Agentico's existing Git mutation guards. Locks are deduplicated by canonical common directory and acquired in lexical order so multi-repository acceptance cannot deadlock.

func LockRepositoryUntil added in v0.156.0

func LockRepositoryUntil(ctx context.Context, repoPath string) (unlock func(), ok bool)

LockRepositoryUntil acquires one repository's mutation lock, bounded by ctx. It uses the same canonical common-directory identity as LockRepositories, so an origin check serializes with feature acceptance, setup, and other guarded mutations; a single-lock acquisition cannot deadlock against a multi-lock holder. The returned unlock must be called when ok is true.

func MergeFeatureBranch

func MergeFeatureBranch(repoPath, featureBranch, baseBranch string) error

MergeFeatureBranch merges the given feature branch into baseBranch in the repo at repoPath. It checks out baseBranch, performs a --no-ff merge, then checks out the original branch. Returns an error with a conflict hint if the merge fails due to conflicts.

func MergeInProgress added in v0.149.0

func MergeInProgress(worktreePath string) bool

MergeInProgress reports whether a merge is underway in the worktree at worktreePath. An in-progress merge leaves a MERGE_HEAD file under the worktree's resolved git directory until `git merge --continue` / `git commit` / `git merge --abort` clears it. The probe mirrors the existing rebase-in-progress probe: it reports conservatively (false) on any error resolving or stating the git directory.

func MergeNoFF added in v0.149.0

func MergeNoFF(worktreePath, ref, message string) error

MergeNoFF merges ref into the checked-out branch of the worktree at worktreePath with an explicit two-parent --no-ff merge commit, even when a fast-forward would be possible. Callers (child-to-parent integration) use this to create a durable merge boundary on an already checked-out parent branch — unlike MergeFeatureBranch, no checkout dance happens, so the parent worktree, branch, and HEAD are never moved except by the merge commit itself. ref may be a branch name or a full commit SHA; integration passes the recorded child head SHA so the merge applies exactly the durable anchor regardless of later child-branch movement.

On failure any recorded in-progress merge (conflicts) is aborted so HEAD and the worktree return to the exact pre-merge state; a pre-apply refusal (dirty working tree blocking the merge) needs no abort because git never started one. Either way the branch ref is guaranteed unchanged when an error is returned.

func PRBaseBranch

func PRBaseBranch(_ string, prURL string) string

PRBaseBranch returns the base branch of an open PR via the GitHub API. prURL should be a full GitHub PR URL. Returns empty string on any error.

func PRState added in v0.149.0

func PRState(_ string, prURL string) (string, error)

PRState reports whether the PR at prURL is still open. An empty string means the state could not be determined, and the accompanying error says why. Callers must treat the indeterminate answer as "unknown", never as "closed".

func ParsePRURL

func ParsePRURL(prURL string) (owner, repo string, number int, err error)

ParsePRURL extracts owner, repo, and PR number from a GitHub PR URL. Expected format: https://github.com/owner/repo/pull/123

func ParseRemoteURL added in v0.149.0

func ParseRemoteURL(remote string) (host, owner, repo string, err error)

ParseRemoteURL extracts host, owner, and repository name from a git remote URL in https, ssh://, or scp-like (git@host:owner/repo) form.

func Push

func Push(worktreePath, branch string) error

Push pushes a worktree's branch to origin.

func PushRewrittenBranch added in v0.151.0

func PushRewrittenBranch(worktreePath, branch string) error

PushRewrittenBranch replaces a remote branch only when any remote-only commits are provably redundant merges of history already present in HEAD.

func ReadRefSHA added in v0.149.0

func ReadRefSHA(repoPath, ref string) (string, error)

ReadRefSHA returns the full SHA of the named ref (e.g. "refs/heads/main" or "main") in the given repo path, or an error if the ref does not resolve.

func Rebase

func Rebase(worktreePath, baseBranch string) error

Rebase rebases the current branch onto the specified base branch. Returns nil on success. If there are conflicts, returns an error and aborts the rebase to leave the worktree clean.

func RebaseInProgress

func RebaseInProgress(worktreePath string) bool

RebaseInProgress reports whether the worktree has an unfinished rebase. A rebase leaves either a rebase-merge/ (interactive / merge-strategy rebase) or a rebase-apply/ (am-based rebase) directory inside the worktree's git dir until `git rebase --continue` / `--abort` / `--skip` clears it. Callers use this to detect stuck rebases before treating the branch as "done".

func RebaseLocal

func RebaseLocal(worktreePath, baseBranch string) error

RebaseLocal rebases the current branch onto a local base branch (no origin/ prefix). Used for repos without a remote. Aborts on conflict to leave the worktree clean.

func RemoveCrossReferenceSection

func RemoveCrossReferenceSection(body string) string

RemoveCrossReferenceSection removes the cross-reference section from a PR body. Cleans up extra whitespace left behind.

func ReplyToIssueComment

func ReplyToIssueComment(_ string, prURL, body string) error

ReplyToIssueComment posts a top-level conversation comment on a PR.

func ReplyToPRComment

func ReplyToPRComment(_ string, prURL string, commentID int, body string) error

ReplyToPRComment posts a reply to a specific review comment.

func RepoFreshness added in v0.149.0

func RepoFreshness(worktreePath string) string

func ResolveReviewThread

func ResolveReviewThread(_ string, threadNodeID string) error

ResolveReviewThread resolves a single review thread. Thread node IDs come from FetchReviewThreadMap on the same PR; the API host is assumed to be github.com because no PR URL reaches this call.

func RetroactivelyUpdateCrossRefs

func RetroactivelyUpdateCrossRefs(featureName string, entries []CrossRefEntry, currentRepoName string) []error

RetroactivelyUpdateCrossRefs updates the cross-reference sections in all related PRs (except the current repo's PR). Errors are collected and returned rather than aborting on the first failure.

func SortReviewCommentsChronologically added in v0.149.0

func SortReviewCommentsChronologically(comments []ReviewComment)

SortReviewCommentsChronologically orders comments by their GitHub creation time in ascending order. Comments without a parseable timestamp are placed after dated comments, with ID as a deterministic tie-breaker.

func StatRepoDirectory added in v0.156.0

func StatRepoDirectory(path string) (uint64, uint64, string, error)

StatRepoDirectory reads the stable filesystem identity of a Git common directory. It also supports staging directories before clone publication.

func UpdatePRBody

func UpdatePRBody(prURL, newBody string) error

UpdatePRBody updates the body of a GitHub PR by URL.

func UpdateRefCAS added in v0.149.0

func UpdateRefCAS(repoPath, ref, oldSHA, newSHA string) error

UpdateRefCAS performs a compare-and-swap ref update: the ref is updated to newSHA only if its current value equals oldSHA. If the current value differs, an *RefCASMismatchError is returned with the observed SHA. The update is atomic (git update-ref is atomic on the ref file).

The ref should be a full ref path (e.g. "refs/heads/main") or a short name that git can resolve. The repoPath is the main repository path (not a worktree), since ref updates operate on the shared object database.

Types

type BranchCandidateResult added in v0.156.0

type BranchCandidateResult struct {
	State    BranchProbeState
	Warnings []BranchProbeWarning
}

BranchCandidateResult reports whether a candidate is usable. Unavailable means locally unique and usable, with warnings describing unknown origins.

func ProbeBranchCandidate added in v0.156.0

func ProbeBranchCandidate(ctx context.Context, repos []BranchProbeRepository, branch string, options BranchProbeOptions) (BranchCandidateResult, error)

ProbeBranchCandidate checks every local branch before contacting any origin. Local probe failures fail closed because local uniqueness must be proved.

type BranchProbeCommandResult added in v0.156.0

type BranchProbeCommandResult struct {
	Stdout      string
	Diagnostics string
	ExitCode    int
	Err         error
}

BranchProbeCommandResult is a completed and reaped command result.

type BranchProbeOptions added in v0.156.0

type BranchProbeOptions struct {
	OperationTimeout time.Duration
	DiagnosticLimit  int
	Runner           BranchProbeRunner
}

BranchProbeOptions contains per-call controls. Zero values use bounded production defaults, keeping tests from mutating package globals.

type BranchProbeRepository added in v0.156.0

type BranchProbeRepository struct {
	Name        string
	Path        string
	ProbeOrigin bool
}

BranchProbeRepository is one selected checkout participating in collision checking. ProbeOrigin is false for local-only repositories.

type BranchProbeResult added in v0.156.0

type BranchProbeResult struct {
	State       BranchProbeState
	Diagnostics string
}

BranchProbeResult is the bounded result of probing one branch name.

func ProbeRemoteBranch added in v0.156.0

func ProbeRemoteBranch(ctx context.Context, repoPath, branch string, options BranchProbeOptions) BranchProbeResult

ProbeRemoteBranch checks the exact origin branch without fetching. Exit code 2 from git ls-remote --exit-code proves absence; all other failures are unavailable rather than evidence of absence.

type BranchProbeRunner added in v0.156.0

type BranchProbeRunner interface {
	Run(ctx context.Context, repoPath string, args []string, diagnosticLimit int) BranchProbeCommandResult
}

BranchProbeRunner is the process boundary used by branch probes.

type BranchProbeRunnerFunc added in v0.156.0

type BranchProbeRunnerFunc func(context.Context, string, []string, int) BranchProbeCommandResult

BranchProbeRunnerFunc adapts a function for deterministic callers and tests.

func (BranchProbeRunnerFunc) Run added in v0.156.0

func (f BranchProbeRunnerFunc) Run(ctx context.Context, repoPath string, args []string, diagnosticLimit int) BranchProbeCommandResult

type BranchProbeState added in v0.156.0

type BranchProbeState string

BranchProbeState distinguishes a proved result from an unavailable remote.

const (
	BranchProbeAbsent      BranchProbeState = "absent"
	BranchProbeCollision   BranchProbeState = "collision"
	BranchProbeUnavailable BranchProbeState = "unavailable"
)

type BranchProbeWarning added in v0.156.0

type BranchProbeWarning struct {
	Repository  string
	Branch      string
	Diagnostics string
}

BranchProbeWarning attributes an unavailable best-effort origin probe.

type CheckoutHeadState added in v0.156.0

type CheckoutHeadState struct {
	Ref string
	SHA string
}

CheckoutHeadState is one observed checkout HEAD: the full symbolic ref or the literal "detached", plus the resolved commit.

func ResolveCheckoutHead added in v0.156.0

func ResolveCheckoutHead(ctx context.Context, repoPath string, options OriginCheckOptions) (CheckoutHeadState, error)

ResolveCheckoutHead exposes the observed checkout HEAD for read-model snapshots that bind Update expectations.

type CheckoutReconcileObservation added in v0.156.0

type CheckoutReconcileObservation struct {
	HeadRef string
	HeadSHA string
	State   CheckoutReconcileState
}

CheckoutReconcileObservation is one settlement read's observation of the original checkout holding the attempted branch. HeadRef and HeadSHA are empty when they could not be read.

type CheckoutReconcileState added in v0.156.0

type CheckoutReconcileState string

CheckoutReconcileState is the observed state of the original checkout that held the attempted update's branch. The target branch SHA alone only proves the target commit is present; the original tip alone does not prove the index and files were untouched. Only a clean checkout whose HEAD is the observed branch tip supports a whole-checkout completion claim.

const (
	// CheckoutReconcileClean reports a checkout with a consistent index and
	// tracked working tree and no in-progress Git operation.
	CheckoutReconcileClean CheckoutReconcileState = "clean"
	// CheckoutReconcileDirty reports a checkout with staged, unstaged, or
	// otherwise inconsistent tracked content — possibly a partial or
	// externally changed checkout that truthful guidance must not attribute
	// to Agentico.
	CheckoutReconcileDirty CheckoutReconcileState = "dirty"
	// CheckoutReconcileOperationInProgress reports a merge, rebase,
	// cherry-pick, or revert in progress in the checkout.
	CheckoutReconcileOperationInProgress CheckoutReconcileState = "operation_in_progress"
	// CheckoutReconcileUnobserved reports the checkout state could not be
	// completely inspected; no whole-checkout claim may be based on it.
	CheckoutReconcileUnobserved CheckoutReconcileState = "unobserved"
)

type CleanlinessCache added in v0.149.0

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

CleanlinessCache decorates an inspector with a bounded, deduplicated, never-blocking cache for read paths that only display cleanliness. It is deliberately not used by launch-time preflights, which must observe the worktree as it is at the moment they act.

Probe failures (including ErrProbeTimeout) are cached and returned as-is, and a nil report with no error is converted to ErrCleanlinessUnknown, so an indeterminate worktree never reads as clean.

func NewCleanlinessCache added in v0.149.0

func NewCleanlinessCache(inspector CleanlinessInspector) *CleanlinessCache

NewCleanlinessCache caches inspector with the default TTL and bound.

func (*CleanlinessCache) InspectCleanliness added in v0.149.0

func (c *CleanlinessCache) InspectCleanliness(worktreePath string, maxPerCategory int) (*CleanlinessReport, error)

InspectCleanliness serves the cached report for worktreePath, refreshing in the background once the entry goes stale.

type CleanlinessInspector added in v0.149.0

type CleanlinessInspector interface {
	InspectCleanliness(worktreePath string, maxPerCategory int) (*CleanlinessReport, error)
}

CleanlinessInspector is the InspectCleanliness surface CleanlinessCache decorates.

type CleanlinessReport added in v0.149.0

type CleanlinessReport struct {
	Staged         []string
	Unstaged       []string
	Untracked      []string
	StagedTotal    int
	UnstagedTotal  int
	UntrackedTotal int
}

CleanlinessReport is the categorized result of inspecting a single git worktree. Staged / Unstaged / Untracked hold at most the requested number of paths each; the *Total fields always report full counts so callers can surface truncation. Ignored paths are excluded by git itself (git status --porcelain skips them without --ignored).

func (*CleanlinessReport) Dirty added in v0.149.0

func (r *CleanlinessReport) Dirty() bool

Dirty reports whether any category carries at least one path.

type ConflictMarkerScanError added in v0.149.0

type ConflictMarkerScanError struct {
	WorktreePath string
	Err          error
	Output       string
}

ConflictMarkerScanError records a failure scanning a worktree for conflict markers. Callers should fail closed on a non-nil scan error.

func (*ConflictMarkerScanError) Error added in v0.149.0

func (e *ConflictMarkerScanError) Error() string

func (*ConflictMarkerScanError) Unwrap added in v0.149.0

func (e *ConflictMarkerScanError) Unwrap() error

type CrossRefEntry

type CrossRefEntry struct {
	RepoName string
	Branch   string
	PRURL    string // empty = pending, "(failed)" = failed repo
}

CrossRefEntry describes one repo's PR status for cross-reference rendering.

type DiffPreview

type DiffPreview struct {
	Path         string
	OldPath      string
	Operation    string // add, update, delete, rename
	AddedLines   int
	RemovedLines int
	Patch        string
	Fingerprint  string
}

DiffPreview is a compact, file-scoped preview of a working tree change.

func BranchDiffPreviews added in v0.149.0

func BranchDiffPreviews(worktreePath, baseBranch string) ([]DiffPreview, error)

BranchDiffPreviews returns compact per-file previews for the worktree's branch against the base branch. The diff captures both committed feature-branch changes and uncommitted working-tree changes — everything that would be published or merged if the branch were pushed and opened as a PR against the base. Untracked files appear as additions. The base branch is resolved via resolveBase when empty.

func SingleFileDiffPreview

func SingleFileDiffPreview(worktreePath, baseBranch, relPath string) (*DiffPreview, error)

SingleFileDiffPreview returns a compact diff preview for a single file compared to the base branch. The relPath must be relative to the worktree root. Returns (nil, nil) if the file has no changes vs base.

type ExecBranchProbeRunner added in v0.156.0

type ExecBranchProbeRunner struct {
	Executable string
	// contains filtered or unexported fields
}

ExecBranchProbeRunner runs the production argument-vector probe. Executable defaults to git and is injectable for deterministic process-lifecycle tests.

func (ExecBranchProbeRunner) Run added in v0.156.0

func (r ExecBranchProbeRunner) Run(ctx context.Context, repoPath string, args []string, diagnosticLimit int) BranchProbeCommandResult

type ExecSourceUpdateRefRunner added in v0.156.0

type ExecSourceUpdateRefRunner struct{}

ExecSourceUpdateRefRunner is the production argument-vector runner.

func (ExecSourceUpdateRefRunner) Run added in v0.156.0

func (ExecSourceUpdateRefRunner) Run(ctx context.Context, repoPath, stdin string, args []string, diagnosticLimit int) BranchProbeCommandResult

type FetchOriginBranchResult added in v0.156.0

type FetchOriginBranchResult struct {
	State       FetchOriginState
	SHA         string
	Diagnostics string
}

FetchOriginBranchResult is the bounded outcome of fetching the mapped origin branch.

func FetchOriginBranch added in v0.156.0

func FetchOriginBranch(ctx context.Context, repoPath string, mapping OriginMapping, options OriginCheckOptions) FetchOriginBranchResult

FetchOriginBranch proves the mapped branch's remote state and fetches only that branch. Existence is proved by the current ls-remote attempt (exit 2 proves absence); a present branch is fetched with an explicit refspec plus a refmap override so configured fetch mappings, tag following, and submodule recursion cannot broaden the operation or target local branches. The returned SHA comes from the remote-tracking ref this fetch wrote, never from a cached ref or FETCH_HEAD.

type FetchOriginState added in v0.156.0

type FetchOriginState string

FetchOriginState distinguishes a proved fetch outcome from an unavailable attempt. Absent means the current attempt proved the remote branch missing; every other failure is Unavailable, never evidence of absence.

const (
	FetchOriginFetched     FetchOriginState = "fetched"
	FetchOriginAbsent      FetchOriginState = "absent"
	FetchOriginUnavailable FetchOriginState = "unavailable"
)

type FreshnessCache added in v0.149.0

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

FreshnessCache decorates RepoFreshness with a bounded, deduplicated, never-blocking cache so repeated read-model requests for the same worktree cost one background git probe rather than up to three subprocesses each.

func NewFreshnessCache added in v0.149.0

func NewFreshnessCache() *FreshnessCache

NewFreshnessCache caches RepoFreshness with the default TTL and bound.

func NewFreshnessCacheWithProbe added in v0.149.0

func NewFreshnessCacheWithProbe(probe func(worktreePath string) string) *FreshnessCache

NewFreshnessCacheWithProbe caches an arbitrary freshness probe.

func (*FreshnessCache) Freshness added in v0.149.0

func (c *FreshnessCache) Freshness(worktreePath string) string

Freshness reports the freshness of worktreePath from cache, refreshing in the background once the entry goes stale.

type GitLockContentionError added in v0.153.0

type GitLockContentionError struct {
	LockPath string
	Age      time.Duration
}

GitLockContentionError reports a Git mutation that exhausted its retry window while a known lock remained in place.

func (*GitLockContentionError) Error added in v0.153.0

func (e *GitLockContentionError) Error() string

type InitializeOutcome added in v0.156.0

type InitializeOutcome struct {
	// Branch is the branch that received (or already carried) the initial
	// commit, verbatim, including slash-containing names.
	Branch string
	// Head is the resolved HEAD commit after the operation.
	Head string
	// AlreadyInitialized reports that HEAD already resolved (a competing
	// initializer or an external commit won): no commit was created and
	// nothing was overwritten. The caller treats it as refresh-only
	// success.
	AlreadyInitialized bool
}

InitializeOutcome reports what the initialize operation did.

func InitializeRepository added in v0.156.0

func InitializeRepository(ctx context.Context, dir string) (InitializeOutcome, error)

InitializeRepository creates exactly one empty root commit in the existing unborn repository at dir, preserving its origin remotes, its valid symbolic branch (verbatim, including slash-containing names) and every existing file. It never reinitializes, republishes or pushes.

Eligibility is proved before any mutation: the repository must have no commits, no staged, unstaged or untracked content (ignored files are untouched and allowed), and no in-progress merge, rebase, cherry-pick or revert. A resolved existing commit short-circuits as a refresh-only success without any content check, so an already-initialized repository refreshes even when it has local changes.

Exactly-once is structural rather than advisory: the commit object is built without touching the index or running hooks (git commit-tree), and the branch ref is created with a compare-and-swap update-ref whose old value is empty — the ref must not exist. A competing initializer that created the ref first therefore makes this fail and re-read HEAD instead of producing a second commit or replacing the competing commit. The whole sequence holds the shared per-path mutation lock, so Agentico's own affected-checkout mutations on the same repository serialize with it.

func InitializeRepositoryAtIdentity added in v0.156.0

func InitializeRepositoryAtIdentity(ctx context.Context, dir string, expected RepoIdentity) (InitializeOutcome, error)

InitializeRepositoryAtIdentity is InitializeRepository with an additional identity fence. The expected identity is re-resolved while holding the shared repository mutation lock, so a checkout replaced after catalog resolution cannot inherit the prior request's authority.

type LocalSource added in v0.156.0

type LocalSource struct {
	Mode   LocalSourceMode
	Kind   string
	Branch string
	Commit string
}

func AcceptLocalSource added in v0.156.0

func AcceptLocalSource(ctx context.Context, repoPath string, expected LocalSourceExpectation) (LocalSource, error)

AcceptLocalSource revalidates a displayed source against the same checkout. Branch tips may advance only when Git proves the displayed commit is an ancestor of the current tip; detached sources must remain byte-for-byte unchanged.

func InspectLocalSource added in v0.156.0

func InspectLocalSource(ctx context.Context, repoPath string, mode LocalSourceMode) (LocalSource, error)

InspectLocalSource resolves the exact local commit selected by the shared creation mode. Remote refs can nominate a default branch but can never act as its source; the corresponding refs/heads branch must exist locally.

type LocalSourceExpectation added in v0.156.0

type LocalSourceExpectation struct {
	Identity       RepoIdentity
	Mode           LocalSourceMode
	Kind           string
	Branch         string
	ObservedCommit string
}

type LocalSourceMode added in v0.156.0

type LocalSourceMode string

type LocalSourceStaleError added in v0.156.0

type LocalSourceStaleError struct {
	Reason    string
	Refreshed LocalSource
}

func (*LocalSourceStaleError) Error added in v0.156.0

func (e *LocalSourceStaleError) Error() string

func (*LocalSourceStaleError) Unwrap added in v0.156.0

func (e *LocalSourceStaleError) Unwrap() error

type MergeCandidateConflictError added in v0.149.0

type MergeCandidateConflictError struct {
	ParentTip     string
	ChildHead     string
	ConflictFiles []string
}

MergeCandidateConflictError indicates the merge candidate creation failed due to a conflict. The parent ref and worktree are untouched.

func (*MergeCandidateConflictError) Error added in v0.149.0

type MergeCandidateResult added in v0.149.0

type MergeCandidateResult struct {
	CandidateSHA  string
	ConflictFiles []string
}

MergeCandidateResult holds the outcome of creating a merge candidate without advancing the parent ref.

func CreateMergeCandidate added in v0.149.0

func CreateMergeCandidate(mainRepo, parentTip, childHead, message string) (*MergeCandidateResult, error)

CreateMergeCandidate creates an explicit two-parent no-fast-forward merge commit in a temporary detached worktree at parentTip, merging childHead into it, and returns the resulting merge commit SHA. The parent ref and parent worktree are never touched: the merge runs in a disposable worktree that is removed after the candidate SHA is captured.

The merge commit's first parent is parentTip and its second parent is childHead, matching the integration boundary contract. Even when a fast-forward would be possible, the --no-ff flag forces an explicit merge commit.

On conflict, the temporary worktree is cleaned up and ConflictFiles is populated; the returned error is a *MergeCandidateConflictError.

type MergeIntoOutcome added in v0.154.0

type MergeIntoOutcome int

MergeIntoOutcome categorises the result of a MergeInto operation.

const (
	// MergeIntoSuccess means the merge completed (or ref was already merged).
	MergeIntoSuccess MergeIntoOutcome = iota
	// MergeIntoConflict means conflicts remain in the worktree.
	MergeIntoConflict
	// MergeIntoFailed means a non-conflict failure occurred and the merge was aborted.
	MergeIntoFailed
)

type MergeIntoResult added in v0.154.0

type MergeIntoResult struct {
	Outcome       MergeIntoOutcome
	ConflictFiles []string
	Err           error
}

MergeIntoResult is the outcome, conflict files, and error from MergeInto.

func MergeInto added in v0.154.0

func MergeInto(worktreePath, ref, message string) MergeIntoResult

MergeInto merges ref into the branch checked out in the worktree with an explicit --no-ff merge commit. Unlike MergeNoFF, on conflict the merge is NOT aborted — MERGE_HEAD and conflict markers are left in place so an agent can resolve them and commit. Re-entry while a merge is already in progress returns Conflict again; a ref already reachable from HEAD returns Success without a new commit.

type OriginCheckOptions added in v0.156.0

type OriginCheckOptions struct {
	// CommandTimeout bounds cheap local commands (config, rev-parse,
	// rev-list, worktree list, status).
	CommandTimeout time.Duration
	// DiagnosticLimit bounds captured diagnostics.
	DiagnosticLimit int
	// Runner is the process boundary. nil uses the production
	// argument-vector runner with non-interactive environment.
	Runner BranchProbeRunner
	// Now reports the comparison time. nil uses time.Now.
	Now func() time.Time
}

OriginCheckOptions carries per-call controls. Zero values use bounded production defaults; tests inject runners and clocks instead of mutating package globals. Network commands (ls-remote, fetch) are bounded only by the caller's context deadline, which must cover the whole attempt.

type OriginCheckPlan added in v0.156.0

type OriginCheckPlan struct {
	Source      LocalSource
	Status      OriginCheckStatus
	Mapping     *OriginMapping
	Diagnostics string
}

OriginCheckPlan is the local-only resolution of one selected source: the locally resolved source plus either a terminal status that needs no origin contact or a mapping whose branch must be fetched and compared.

func PlanOriginCheck added in v0.156.0

func PlanOriginCheck(ctx context.Context, repoPath string, mode LocalSourceMode, options OriginCheckOptions) OriginCheckPlan

PlanOriginCheck resolves the selected source and its origin mapping with local commands only. It never contacts origin: detached, no-origin, other-upstream, local-base-missing, and unknown outcomes are complete here, while a resolved mapping requires a fetch before comparison.

type OriginCheckStatus added in v0.156.0

type OriginCheckStatus string

OriginCheckStatus is the typed outcome of comparing a selected local source with its mapped origin branch. Every value is a distinct user-facing state; unavailable fields are represented by their absence, never by invented SHAs, counts, or timestamps.

const (
	// OriginCheckChecking reports an attempt in flight.
	OriginCheckChecking OriginCheckStatus = "checking"
	// OriginCheckUpToDate reports local == freshly fetched origin.
	OriginCheckUpToDate OriginCheckStatus = "up_to_date"
	// OriginCheckBehind reports the origin branch has commits the local
	// source lacks.
	OriginCheckBehind OriginCheckStatus = "behind"
	// OriginCheckAhead reports the local source has commits origin lacks.
	OriginCheckAhead OriginCheckStatus = "ahead"
	// OriginCheckDiverged reports both sides have unique commits.
	OriginCheckDiverged OriginCheckStatus = "diverged"
	// OriginCheckNoOrigin reports no origin remote is configured.
	OriginCheckNoOrigin OriginCheckStatus = "no_origin"
	// OriginCheckRemoteBranchMissing reports the mapped origin branch was
	// proved absent by the current attempt.
	OriginCheckRemoteBranchMissing OriginCheckStatus = "remote_branch_missing"
	// OriginCheckOtherUpstream reports the selected branch explicitly tracks
	// an upstream other than origin (including local upstream tracking).
	OriginCheckOtherUpstream OriginCheckStatus = "other_upstream"
	// OriginCheckDetached reports a detached local source; there is no branch
	// to track and no fetch is attempted.
	OriginCheckDetached OriginCheckStatus = "detached"
	// OriginCheckLocalBaseMissing reports the selected local source is
	// missing or unborn; no remote-only fallback exists.
	OriginCheckLocalBaseMissing OriginCheckStatus = "local_base_missing"
	// OriginCheckUnknown reports an attempt that could not prove any of the
	// above (inspection, mapping, authentication, trust, network, or timeout
	// failures).
	OriginCheckUnknown OriginCheckStatus = "unknown"
)

type OriginComparison added in v0.156.0

type OriginComparison struct {
	Status       OriginCheckStatus
	LocalSHA     string
	FetchedSHA   string
	OriginBranch string
	AheadCount   int
	BehindCount  int
	CheckedAt    time.Time
}

OriginComparison is one proved comparison between a recorded local SHA and a freshly fetched origin SHA. It is evidence about those SHAs only, never a transaction against external Git state.

func CompareOriginSource added in v0.156.0

func CompareOriginSource(ctx context.Context, repoPath string, localSHA, fetchedSHA string, mapping OriginMapping, options OriginCheckOptions) (OriginComparison, error)

CompareOriginSource compares the recorded local SHA with the freshly fetched SHA. The comparison is evidence about exactly those SHAs.

type OriginMapping added in v0.156.0

type OriginMapping struct {
	Branch string
}

OriginMapping is the resolved origin tracking for one selected branch. The mapping comes from the branch's configured upstream (exact remote branch, including differently named branches) or, without upstream configuration, the same-name origin fallback. A configured mapping is preserved even when its cached remote-tracking ref is absent.

type PendingWork added in v0.149.0

type PendingWork struct {
	Commits          int
	DestinationAhead int
	Dirty            bool
}

PendingWork is local work measured against a delivery destination — the remote branch behind a pull request, or the base branch of a local merge.

func PendingAgainst added in v0.149.0

func PendingAgainst(worktreePath, dest string) (PendingWork, bool)

PendingAgainst measures work in worktreePath that has not reached dest. It reads local refs only — never fetching, never mutating — so it is safe in a side-effect-free preflight. ok is false when dest does not resolve, which is the honest answer for a missing remote-tracking ref.

func (PendingWork) Pending added in v0.149.0

func (w PendingWork) Pending() bool

Pending reports whether local work has not reached the destination.

type ProbeCache added in v0.149.0

type ProbeCache[V any] struct {
	// contains filtered or unexported fields
}

ProbeCache serves the result of an expensive git probe from memory. A fresh key is served from the map; a stale key is served from the map too and a single background refresh is scheduled, so no caller after the first ever waits on git. Concurrent callers for the same key collapse onto that one probe, so a burst of reads costs one git invocation rather than one per read. Only a cold key — nothing cached at all — waits, joining the same shared probe (itself bounded by ProbeTimeout) rather than inventing an answer.

func NewProbeCache added in v0.149.0

func NewProbeCache[V any](ttl time.Duration, max int, probe func(key string) V) *ProbeCache[V]

NewProbeCache builds a cache over probe. A ttl or max of zero or less applies ProbeCacheTTL / ProbeCacheMaxEntries.

func (*ProbeCache[V]) Get added in v0.149.0

func (c *ProbeCache[V]) Get(key string) V

Get returns the value for key, serving a stale value immediately while a refresh runs in the background. Only the first call for a key waits.

type PullRebaseOutcome

type PullRebaseOutcome int

PullRebaseOutcome categorises the result of a PullRebase operation.

const (
	// PullRebaseSuccess means the rebase succeeded or was a no-op.
	PullRebaseSuccess PullRebaseOutcome = iota
	// PullRebaseConflict means the rebase encountered merge conflicts and was aborted.
	PullRebaseConflict
	// PullRebaseFailure means a non-conflict failure occurred.
	PullRebaseFailure
)

type PullRebaseResult

type PullRebaseResult struct {
	Outcome PullRebaseOutcome
	Err     error
}

PullRebaseResult is the outcome and error from a PullRebase operation.

func PullRebase

func PullRebase(worktreePath, branch string) PullRebaseResult

PullRebase fetches from origin and rebases the current branch onto the remote tracking branch. This syncs local commits on top of any remote changes to the same branch before pushing.

Outcomes:

  • Success: remote branch absent (first publish), already up-to-date, or rebase succeeded
  • Conflict: rebase had conflicts; rebase aborted, worktree left clean
  • Failure: network/auth/fetch error or other non-conflict failure

type RebaseOutcome

type RebaseOutcome int

RebaseOutcome categorises the result of a RebaseOnto operation.

const (
	// RebaseSuccess means the rebase completed without conflicts.
	RebaseSuccess RebaseOutcome = iota
	// RebaseConflict means conflicts remain in the worktree.
	RebaseConflict
	// RebaseFailed means a non-conflict failure occurred and the rebase was aborted.
	RebaseFailed
)

type RebaseResult

type RebaseResult struct {
	Outcome       RebaseOutcome
	ConflictFiles []string
	Err           error
}

RebaseResult is the outcome, conflict files, and error from RebaseOnto.

func RebaseOnto

func RebaseOnto(worktreePath, target string) RebaseResult

RebaseOnto rebases the current branch onto the given target ref (e.g. "origin/master"). Unlike Rebase, on conflict the rebase is NOT aborted — the worktree is left mid-rebase with conflict markers in the files so an agent can resolve them and run "git rebase --continue".

type RefCASMismatchError added in v0.149.0

type RefCASMismatchError struct {
	Ref      string
	Expected string
	Observed string
}

RefCASMismatchError is returned when a compare-and-swap ref update fails because the ref's current SHA does not match the expected old SHA.

func (*RefCASMismatchError) Error added in v0.149.0

func (e *RefCASMismatchError) Error() string

type RepoIdentity added in v0.156.0

type RepoIdentity struct {
	Path      string
	CommonDir string
	Device    uint64
	Inode     uint64
	BirthTime string
}

RepoIdentity is the server-resolved identity of a repository checkout. Path is the canonical checkout path and CommonDir the resolved Git common directory, so linked worktrees that share a common directory stay distinguishable from their main checkout. Device and Inode pin the Git common directory itself: replacing a checkout, or replacing the Git repository at the same path, invalidates the prior identity instead of silently adopting the replacement. BirthTime, when the filesystem exposes it, also distinguishes replacements that reuse the deleted directory's inode. Ordinary commits, branch checkouts, discovery refreshes and reconnects leave the identity unchanged.

func ResolveRepoIdentity added in v0.156.0

func ResolveRepoIdentity(dir string) (RepoIdentity, bool)

ResolveRepoIdentity resolves the identity of the git repository checkout at dir. It reports false when dir is not a usable work tree (for example a bare repository, a broken .git pointer, or a missing git executable); the caller decides how to surface that to the user.

func (RepoIdentity) Equal added in v0.156.0

func (a RepoIdentity) Equal(b RepoIdentity) bool

Equal reports whether two identities describe the same repository checkout on the same server.

type ReviewComment

type ReviewComment struct {
	ID   int    `json:"id"`
	Path string `json:"path"`
	Line int    `json:"line"`
	Body string `json:"body"`
	User struct {
		Login string `json:"login"`
	} `json:"user"`
	CreatedAt string `json:"created_at"`
	DiffHunk  string `json:"diff_hunk"`
	InReplyTo int    `json:"in_reply_to_id"`
	Type      string `json:"type"`
	RepoName  string `json:"repo_name,omitempty"`
}

ReviewComment is a GitHub PR comment (inline review or issue conversation).

func FetchPRComments

func FetchPRComments(_ string, prURL string) ([]ReviewComment, error)

FetchPRComments fetches inline review comments, general conversation comments, and submitted review bodies via the GitHub API. It excludes replies to inline comments so each returned item represents one addressable feedback thread or top-level PR comment. repoPath is retained for signature stability; the API needs only the PR URL.

type RewritePushError added in v0.151.0

type RewritePushError struct {
	Kind              RewritePushErrorKind
	Branch            string
	RemoteOnlyCommits int
	Err               error
}

RewritePushError reports a safety refusal without exposing raw Git output. Err retains bounded command or classification detail for errors.Is/As.

func (*RewritePushError) Error added in v0.151.0

func (e *RewritePushError) Error() string

func (*RewritePushError) Unwrap added in v0.151.0

func (e *RewritePushError) Unwrap() error

type RewritePushErrorKind added in v0.151.0

type RewritePushErrorKind string

RewritePushErrorKind identifies a safety refusal while replacing a remote branch after its local history was rewritten.

const (
	// RewritePushRemoteDiverged means the inspected remote contains work that
	// cannot be proven redundant with the rewritten local history.
	RewritePushRemoteDiverged RewritePushErrorKind = "remote_diverged"
	// RewritePushRemoteChanged means the remote moved after inspection and the
	// explicit lease correctly rejected the push.
	RewritePushRemoteChanged RewritePushErrorKind = "remote_changed"
)

type SourceReconcileReport added in v0.156.0

type SourceReconcileReport struct {
	State    SourceReconcileState
	LocalSHA string
	// Checkout is the observed state of the original checkout holding the
	// branch, populated only when the caller asked to settle an
	// original-checkout update (the echoed binding's checkout HEAD was the
	// branch itself) and the original checkout still holds the branch. A nil
	// Checkout on such a request means the checkout no longer holds the
	// branch.
	Checkout *CheckoutReconcileObservation
}

SourceReconcileReport is one settlement read's typed observation.

func ReconcileSourceUpdateState added in v0.156.0

func ReconcileSourceUpdateState(ctx context.Context, repoPath, branch, expectedLocalSHA, expectedOriginSHA string, observeCheckout bool, options OriginCheckOptions) (SourceReconcileReport, error)

ReconcileSourceUpdateState reads the requested branch's current tip and reports it against the attempted update's two expected tips, optionally observing the original checkout that held the branch. The caller must already hold the repository's canonical common-directory mutation lock and must have established that no admitted update attempt on this repository can still mutate: only then is the read a settlement. The read is local-only — it never fetches, mutates, or infers anything from a cached comparison. Unresolvable branches and unobservable checkouts are settled observations; inspection failures of the tip fail closed.

type SourceReconcileState added in v0.156.0

type SourceReconcileState string

SourceReconcileState is the typed settlement of one uncertain update attempt: what the requested branch's tip proves after the attempt can no longer mutate. It is an observation of the ref, never an inference about transport completion.

const (
	// SourceReconcileTargetPresent reports the branch tip is the expected
	// origin SHA the attempt was expected to advance it to.
	SourceReconcileTargetPresent SourceReconcileState = "expected_target_present"
	// SourceReconcileOriginalTip reports the branch tip is still the
	// expected local SHA displayed before the attempt.
	SourceReconcileOriginalTip SourceReconcileState = "original_tip_remains"
	// SourceReconcileLocalChanged reports the branch tip is neither
	// expected value: something else moved it, and the observation says
	// nothing about whether the attempt succeeded.
	SourceReconcileLocalChanged SourceReconcileState = "local_state_changed"
	// SourceReconcileBranchMissing reports the branch no longer resolves.
	SourceReconcileBranchMissing SourceReconcileState = "branch_missing"
)

type SourceUpdateExpectation added in v0.156.0

type SourceUpdateExpectation struct {
	Mode              LocalSourceMode
	Branch            string
	OriginBranch      string
	ExpectedLocalSHA  string
	ExpectedOriginSHA string
	CheckoutHeadRef   string
	CheckoutHeadSHA   string
}

SourceUpdateExpectation binds one displayed Update-from-origin decision to the exact observed state it was based on. Every field is an expectation the update revalidates against freshly resolved state; none of them is authority over which repository or ref is mutated.

type SourceUpdateOptions added in v0.156.0

type SourceUpdateOptions struct {
	OriginCheckOptions

	// UpdateRefRunner performs the CAS mutation; nil uses the production
	// runner.
	UpdateRefRunner SourceUpdateRefRunner
	// BeforeCAS runs under coordination immediately before the final
	// revalidation and compare-and-swap. Production callers leave it nil;
	// deterministic tests inject races here.
	BeforeCAS func()
}

SourceUpdateOptions carries per-call controls for the source update. Zero values use bounded production defaults; deterministic tests inject runners, clocks, and pre-CAS hooks instead of mutating package globals.

type SourceUpdateOutcome added in v0.156.0

type SourceUpdateOutcome struct {
	Result      SourceUpdateResult
	Reason      SourceUpdateReason
	PreviousSHA string
	LocalSHA    string
	FetchedSHA  string

	// Plan is the freshly resolved local-only selection state.
	Plan OriginCheckPlan
	// Comparison is a fresh local-versus-origin comparison for the current
	// selection when this attempt fetched the mapped branch.
	Comparison *OriginComparison
	// RemoteBranchMissing records a proved-absent mapped origin branch.
	RemoteBranchMissing bool
	// FetchUnavailable records that the fresh status fetch could not be
	// proved; the status row must not present old counts as current.
	FetchUnavailable bool
	// Blockers are the observed advisory update blockers for the fresh
	// status row.
	Blockers []UpdateBlocker
	// CheckoutHolders lists the linked worktree paths holding the branch for
	// branch_checked_out refusals.
	CheckoutHolders []string
}

SourceUpdateOutcome is one update attempt's typed result. For stale refusals the snapshot fields carry freshly resolved status evidence for the current selection, never the displayed expectations.

func UpdateSourceFromOrigin added in v0.156.0

func UpdateSourceFromOrigin(ctx context.Context, repoPath string, expected SourceUpdateExpectation, options SourceUpdateOptions) (SourceUpdateOutcome, error)

UpdateSourceFromOrigin advances exactly one local branch to a freshly fetched origin commit. A branch no checkout holds advances by an expected-old-value compare-and-swap that moves only the ref; a branch held only by the original checkout at repoPath advances through Git's working-tree-aware fast-forward, which moves the branch, symbolic HEAD, index, and tracked working files together; a branch held by any other linked worktree is refused with that worktree's remediation.

The caller must already hold the repository's canonical common-directory mutation lock: the update, origin checks, feature acceptance, and setup serialize on that boundary. Agentico coordination does not claim atomic exclusion of arbitrary external Git processes; the pre-mutation revalidation and the CAS old-value check are the final arbititors on the ref-only path, and the original-checkout path treats an unprovable mutation-boundary outcome as unavailability for the settlement flow. The update never resets, rebases, forces, stashes, cleans, stages local content, pushes, or runs hooks, never creates merge commits, never deletes or breaks Git ref/index locks (including old ones), and bounds every subprocess by ctx, reaping processes before returning.

Stale refusals return an outcome rather than an error: the mutation was refused, not attempted and failed. Unprovable attempts (inspection, fetch, ancestry, or deadline failures, and ambiguous mutation boundaries) return an error wrapping ErrSourceUpdateUnavailable and leave any claim about the repository's final state unproved.

type SourceUpdateReason added in v0.156.0

type SourceUpdateReason string

SourceUpdateReason names one typed stale refusal.

const (
	// SourceUpdateReasonCheckoutChanged reports the observed checkout HEAD
	// changed since display, even when the selected source is unchanged.
	SourceUpdateReasonCheckoutChanged SourceUpdateReason = "checkout_changed"
	// SourceUpdateReasonSourceChanged reports the selected source no longer
	// matches (mode, kind, branch, or a disappeared local ref).
	SourceUpdateReasonSourceChanged SourceUpdateReason = "source_changed"
	// SourceUpdateReasonMappingChanged reports the origin mapping changed,
	// including a missing origin or a non-origin upstream.
	SourceUpdateReasonMappingChanged SourceUpdateReason = "mapping_changed"
	// SourceUpdateReasonLocalTipChanged reports the local branch tip moved,
	// including a ref change that failed the expected-old-value check.
	SourceUpdateReasonLocalTipChanged SourceUpdateReason = "local_tip_changed"
	// SourceUpdateReasonOriginTipChanged reports the freshly fetched origin
	// tip differs from the displayed one.
	SourceUpdateReasonOriginTipChanged SourceUpdateReason = "origin_tip_changed"
	// SourceUpdateReasonOriginBranchMissing reports this attempt proved the
	// mapped origin branch absent on the remote.
	SourceUpdateReasonOriginBranchMissing SourceUpdateReason = "origin_branch_missing"
	// SourceUpdateReasonNotFastForward reports the local branch is ahead of
	// or diverged from origin; only a proved fast-forward may advance it.
	SourceUpdateReasonNotFastForward SourceUpdateReason = "not_fast_forward"
	// SourceUpdateReasonBranchCheckedOut reports the branch is checked out
	// in a linked worktree; that worktree's own checkout must be updated
	// separately. A branch held only by the original catalog checkout is the
	// eligible original-checkout path, never this refusal.
	SourceUpdateReasonBranchCheckedOut SourceUpdateReason = "branch_checked_out"
	// SourceUpdateReasonDirtyCheckout reports the original checkout holding
	// the branch has staged, unstaged, or untracked content, so a
	// working-tree-aware fast-forward refuses.
	SourceUpdateReasonDirtyCheckout SourceUpdateReason = "dirty_checkout"
	// SourceUpdateReasonCheckoutOperationInProgress reports a merge, rebase,
	// cherry-pick, or revert — including a sequence between commits — is in
	// progress in the original checkout.
	SourceUpdateReasonCheckoutOperationInProgress SourceUpdateReason = "checkout_operation_in_progress"
	// SourceUpdateReasonIgnoredPathCollision reports an incoming tracked
	// path of the fast-forward would overwrite ignored files or directories
	// in the original checkout.
	SourceUpdateReasonIgnoredPathCollision SourceUpdateReason = "ignored_path_collision"
	// SourceUpdateReasonCheckoutConflict reports the working-tree-aware
	// fast-forward itself refused after every pre-mutation check passed, and
	// the refusal was proved to have left the checkout untouched (typically
	// a local change that raced the final checks).
	SourceUpdateReasonCheckoutConflict SourceUpdateReason = "checkout_conflict"
)

type SourceUpdateRefRunner added in v0.156.0

type SourceUpdateRefRunner interface {
	Run(ctx context.Context, repoPath, stdin string, args []string, diagnosticLimit int) BranchProbeCommandResult
}

SourceUpdateRefRunner performs the compare-and-swap ref mutation. It is a separate boundary from BranchProbeRunner because the CAS needs stdin; the production runner reaps its process group under the attempt context.

type SourceUpdateResult added in v0.156.0

type SourceUpdateResult string

SourceUpdateResult is the typed outcome of one update attempt. Stale is a refusal that left the repository untouched, not a failure to run.

const (
	SourceUpdateUpdated         SourceUpdateResult = "updated"
	SourceUpdateAlreadyUpToDate SourceUpdateResult = "already_up_to_date"
	SourceUpdateStale           SourceUpdateResult = "stale"
)

type SourceUpdateUnavailableError added in v0.156.0

type SourceUpdateUnavailableError struct {
	Diagnostics string
}

SourceUpdateUnavailableError carries bounded, credential-redacted diagnostics for an unprovable attempt.

func (*SourceUpdateUnavailableError) Error added in v0.156.0

func (*SourceUpdateUnavailableError) Unwrap added in v0.156.0

func (e *SourceUpdateUnavailableError) Unwrap() error

type UpdateBlocker added in v0.156.0

type UpdateBlocker string

UpdateBlocker names one observed, advisory reason a future branch update would not be safe or defined. Eligibility never authorizes a mutation.

const (
	// UpdateBlockerLocalNotBehind reports the local source is not strictly
	// behind origin (ahead, diverged, or up to date), so no plain update is
	// defined.
	UpdateBlockerLocalNotBehind UpdateBlocker = "local_not_behind"
	// UpdateBlockerDirtyTargetCheckout reports the checkout holding the
	// selected branch has uncommitted changes, including untracked files.
	UpdateBlockerDirtyTargetCheckout UpdateBlocker = "dirty_target_checkout"
	// UpdateBlockerGitOperationInProgress reports a Git mutation guarded by
	// Agentico's common-directory boundary is running for the repository.
	UpdateBlockerGitOperationInProgress UpdateBlocker = "git_operation_in_progress"
	// UpdateBlockerBranchCheckedOutInWorktree reports the selected branch is
	// checked out in a linked worktree.
	UpdateBlockerBranchCheckedOutInWorktree UpdateBlocker = "branch_checked_out_in_worktree"
	// UpdateBlockerCheckoutOperationInProgress reports a merge, rebase,
	// cherry-pick, or revert — including a sequence between commits — is in
	// progress in the original checkout holding the selected branch.
	UpdateBlockerCheckoutOperationInProgress UpdateBlocker = "checkout_operation_in_progress"
	// UpdateBlockerIgnoredPathCollision reports an incoming tracked path of
	// the fast-forward would overwrite ignored files or directories in the
	// original checkout holding the selected branch.
	UpdateBlockerIgnoredPathCollision UpdateBlocker = "ignored_path_collision"
	// UpdateBlockerCheckoutUninspectable reports the checkout's safety state
	// could not be inspected; an inspection failure is ineligible, never
	// evidence of safety.
	UpdateBlockerCheckoutUninspectable UpdateBlocker = "checkout_uninspectable"
	// UpdateBlockerComparisonUnavailable reports no fresh comparison exists
	// to base an update decision on.
	UpdateBlockerComparisonUnavailable UpdateBlocker = "comparison_unavailable"
)

func ProbeUpdateEligibility added in v0.156.0

func ProbeUpdateEligibility(ctx context.Context, repoPath, branch string, comparison *OriginComparison, options OriginCheckOptions) (bool, []UpdateBlocker)

ProbeUpdateEligibility reports the advisory update eligibility for one selected branch together with every observed blocker. It must be called outside Agentico's common-directory mutation boundary: the boundary lock itself is one of the observed blockers. A branch held by the original checkout is eligible only when its checkout is provably safe: clean (including untracked files), free of an in-progress Git operation, and free of ignored-content collisions against the freshly compared range — the optional comparison supplies that range when one exists. Unrelated dirty files in other checkouts never disqualify an unoccupied branch, and an inspection failure is a blocker, never evidence of safety. Eligibility never authorizes a mutation; the update revalidates everything at execution.

type WorktreeManager

type WorktreeManager struct {
	BaseDir string
}

func NewWorktreeManager

func NewWorktreeManager(baseDir string) *WorktreeManager

func (*WorktreeManager) Create

func (w *WorktreeManager) Create(repoPath, featureSlug, repoName, startPoint string) (string, error)

Create creates a new worktree branching from startPoint. If startPoint is empty, HEAD is used (preserving legacy behavior).

func (*WorktreeManager) CreateMergeCandidate added in v0.149.0

func (m *WorktreeManager) CreateMergeCandidate(mainRepo, parentTip, childHead, message string) (*MergeCandidateResult, error)

CreateMergeCandidate exposes the package-level function on the manager.

func (*WorktreeManager) CurrentBranch added in v0.149.0

func (m *WorktreeManager) CurrentBranch(worktreePath string) string

CurrentBranch returns the branch checked out in the given worktree (or "" when it cannot be determined), exposed on the manager so the orchestrator can reach it through a narrow structural interface.

func (*WorktreeManager) CurrentHeadSHA added in v0.149.0

func (w *WorktreeManager) CurrentHeadSHA(worktreePath string) (string, error)

CurrentHeadSHA reports the full SHA of HEAD in the given worktree, exposing the package-level helper through the manager so refactor-child exact-base capture works through the feature.WorktreeOps wiring.

func (*WorktreeManager) ExpectedPath added in v0.145.0

func (w *WorktreeManager) ExpectedPath(featureSlug, repoName string) string

func (*WorktreeManager) InspectCleanliness added in v0.149.0

func (w *WorktreeManager) InspectCleanliness(worktreePath string, maxPerCategory int) (*CleanlinessReport, error)

InspectCleanliness reports staged, unstaged, and untracked changes in the given worktree using `git status --porcelain --untracked-files=all`. Ignored files are absent (porcelain excludes them without --ignored). --untracked-files=all expands untracked directories so every nested file is counted and listed individually (no collapsed `dir/` entries); totals and bounded lists therefore reflect affected paths, not directory entries. Each category list is bounded to maxPerCategory entries (<= 0 applies DefaultCleanlinessPathLimit) while totals keep the true counts. A probe that exceeds CleanlinessProbeTimeout yields a nil report and an ErrProbeTimeout error, never a clean one.

func (*WorktreeManager) MergeNoFF added in v0.149.0

func (m *WorktreeManager) MergeNoFF(worktreePath, ref, message string) error

MergeNoFF exposes the package-level merge on the manager so the orchestrator can reach it through a narrow structural interface.

func (*WorktreeManager) RefSHA added in v0.149.0

func (m *WorktreeManager) RefSHA(repoPath, ref string) (string, error)

RefSHA returns the full SHA of the named ref in the given repo path.

func (*WorktreeManager) Remove

func (w *WorktreeManager) Remove(worktreePath string, deleteBranch bool) error

Remove deletes a worktree and, when requested, its ephemeral branch, discovering the main repository and branch from the live worktree. Material cleanup failures (unremovable worktree, failed prune after a manual fallback, failed branch deletion) are returned so callers can record and retry them; genuinely absent resources (missing worktree directory, already-deleted branch) are idempotent success.

Once a worktree is deregistered its identity can no longer be discovered from the path, so callers that must guarantee branch deletion across retries (e.g. child integration cleanup) should use RemoveRef with the recorded identity instead.

func (*WorktreeManager) RemoveRef added in v0.149.0

func (w *WorktreeManager) RemoveRef(worktreePath, mainRepo, branch string) error

RemoveRef deletes a worktree and its ephemeral branch using the recorded main-repository and branch identity, so a retried cleanup still reaches the branch even after an earlier partial removal deregistered the worktree. An empty branch skips branch deletion; an already-absent branch is success.

func (*WorktreeManager) ResetToBase

func (w *WorktreeManager) ResetToBase(worktreePath, baseBranch string) error

ResetToBase hard-resets a worktree back to its base branch, discarding all local commits and changes on the feature branch.

func (*WorktreeManager) ResetToBaseLocal

func (w *WorktreeManager) ResetToBaseLocal(worktreePath, baseBranch string) error

ResetToBaseLocal hard-resets a worktree back to its local base branch ref, without fetching from any remote. Used for repos without an origin remote.

func (*WorktreeManager) ResetToCommit

func (w *WorktreeManager) ResetToCommit(worktreePath, commitSHA string) error

ResetToCommit hard-resets a worktree to a local commit SHA without fetching from any remote, then cleans untracked files.

func (*WorktreeManager) UpdateRef added in v0.149.0

func (m *WorktreeManager) UpdateRef(repoPath, ref, oldSHA, newSHA string) error

UpdateRef performs a compare-and-swap ref update on the given repo.

Jump to

Keyboard shortcuts

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