import type { ExecResult, ExtensionAPI } from "@earendil-works/pi-coding-agent"; /** * Result of checking the repository state. */ export interface GitStatus { hasChanges: boolean; raw: string; } /** * Wrapper around git operations used by the extension. * * All commands are run via `pi.exec()` so they inherit pi's environment * (PATH, SSH keys, git config, etc.). */ export declare class GitOperations { private readonly pi; constructor(pi: ExtensionAPI); /** * Get the current HEAD commit SHA. * Returns `null` when git is not available or HEAD cannot be resolved. */ getHead(): Promise; /** * Check whether the current directory is inside a git working tree. * Returns `true` on success, `false` if not a git repo. */ isInsideGitRepo(): Promise; /** * Run `git status --short` and return whether there are uncommitted changes. */ checkStatus(): Promise; /** * Stage all changes via `git add -A`. */ stageAll(): Promise; /** * Stage all changes except submodule-related paths (`ignoreSubmodules`). * * Runs `git add -A`, then unstages everything that is a submodule pin from * the parent's perspective: gitlink entries (mode 160000 in the index — * covering registered submodules and absorbed embedded repositories alike) * and `.gitmodules`. Only paths that actually differ from HEAD after the * add are unstaged. */ stageAllIgnoringSubmodules(): Promise; /** * Get the stat summary of staged changes (`git diff --cached --stat`). */ getStagedStat(): Promise; /** * Get the full diff of staged changes (`git diff --cached --submodule=log`). * * `--submodule=log` adds a summary of the commits contained in each * submodule (gitlink) change — e.g. `Submodule sub ..:` followed * by the child commit subjects — so commit-message generation can describe * what actually changed inside the submodule instead of only seeing the * `Subproject commit` pointer bump. It is a no-op for regular files. */ getStagedDiff(): Promise; /** * Get the name-status of staged changes (`git diff --cached --name-status`). */ getStagedNameStatus(): Promise; /** * Check whether a merge conflict is in progress. * Returns `true` if the index is locked (conflict markers present, etc.) */ hasMergeConflict(): Promise; /** * Execute the commit with the given message. * Returns the raw stdout output of `git commit`. */ commit(message: string): Promise; /** * Unstage a specific file (`git restore --staged -- `). * * Throws when the git command fails (non-zero exit), ensuring callers * (e.g. the commit pipeline) can detect the failure and abort/clean up * instead of silently committing unselected files. */ unstageFile(file: string): Promise; /** * Unstage all changes (`git reset HEAD --`). */ unstageAll(): Promise; /** * Check whether there are any uncommitted changes (staged, unstaged, or untracked). * Uses `git status --porcelain` for machine-parseable output. * Returns true if there are any changes relative to HEAD. */ checkUncommittedChanges(): Promise; /** * List submodule paths whose checked-out HEAD is a **detached orphan**: * it differs from the gitlink recorded in the parent index and is * unreachable from any ref (`git for-each-ref --contains HEAD` is empty). * * Running `git submodule update` in this state checks out the gitlink SHA * and discards the orphaned commits (reflog-only survival). Commits that * sit on a branch survive an update, so they are not reported. * * Returns an empty array when the repo has no gitlinks, submodules are in * sync, missing/uninitialised, or their HEAD is reachable from a ref. */ findOrphanedSubmoduleHeads(): Promise>; /** * Count how many consecutive checkpoint commits exist at HEAD. * * Walks backwards from HEAD and stops at the first commit whose subject * does not start with the given marker (or, when `sessionId` is provided, * whose `Checkpoint-Session` trailer does not match). * * @param marker Subject prefix to match (e.g. `"wip(checkpoint):"`). * @param sessionId When provided, only count commits whose * `Checkpoint-Session` trailer equals this value. When omitted, count * every consecutive subject-matching commit (backward-compatible * behaviour). */ countCheckpointCommits(marker: string, sessionId?: string): Promise; /** * Soft reset the last N commits, keeping their changes staged. * * When `HEAD~N` exists (normal case), equivalent to `git reset --soft HEAD~N`. * When `HEAD~N` does not exist because N >= total commits in the repo * (e.g. every commit is a checkpoint), uses `git update-ref -d HEAD` to * remove all commits while preserving staged changes. */ resetSoft(commitCount: number): Promise; /** * Check whether the index contains any staged changes. * Uses `git diff --cached --quiet`: exit code 1 means there are differences, * 0 means the index matches HEAD. */ hasStagedChanges(): Promise; /** * Stage only the given files (`git add -- ...`). */ stageFiles(files: string[]): Promise; /** * Get the name of the current branch, or `null` when HEAD is detached or * git cannot resolve it. Used for the `Checkpoint-Branch` trailer. */ getCurrentBranch(): Promise; /** * Return the last N commits in `%H%x00%s` format (with session/branch * trailers appended after the subject), newest first. */ getRecentCommits(maxCount: number, skip?: number): Promise; /** * Resolve the SHA of the upstream tip (`@{upstream}`, falling back to * `origin/HEAD` when the branch has no upstream). Returns `null` when * neither ref can be resolved. */ getUpstreamTip(): Promise; /** * Count how many commits on HEAD are not on the upstream branch * (`git rev-list --count ..HEAD`). On a linear history this is * the index of the upstream tip relative to HEAD — reorganising any range * whose oldest commit is at or below this index rewrites already-pushed * commits. * * Returns `null` when no upstream can be resolved (nothing to protect * against). */ getUpstreamAheadCount(): Promise; /** * Walk backwards from HEAD and return every reachable commit whose subject * starts with `marker`, along with its SHA, `Checkpoint-Session` and * `Checkpoint-Branch` trailer values (or `null` when absent). * * Uses `%(trailers:key=...,valueonly)` so the trailer value is the empty * string (not `"NONE"`) when the key is missing — which becomes `null` * after `.trim() || null`. */ findReachableCheckpoints(marker: string): Promise>; /** * Return checkpoint commits reachable from HEAD but not from `ref` — i.e. * checkpoints that arrived during this run, typically via a merge of a * branch whose agent crashed before `agent_end` reorganisation. */ findCheckpointsSince(ref: string, marker: string): Promise>; /** * Extract the diff of a single commit (relative to its first parent) and * apply it to the index via `git apply --cached`. * * Used for scattered checkpoint reassembly: when target-session checkpoints * are interleaved with foreign checkpoints, each target commit's diff is * staged independently without moving HEAD. * * Returns `{ success: true }` on success, or `{ success: false, error } * when the apply fails (e.g. conflict). */ applyCommitDiffToIndex(sha: string): Promise<{ success: boolean; error?: string; }>; /** * Hard reset HEAD, index, and working tree to a specific commit. * Equivalent to `git reset --hard `. */ hardReset(sha: string): Promise; /** * Compute the diff between two commits and apply it to both the working * tree and the index via `git apply --3way --index`. * * Pipe is used so the diff is streamed rather than written to a temp file. */ applyRangeDiff(ancestor: string, descendant: string): Promise<{ success: boolean; error?: string; }>; /** * Cherry-pick a single commit onto the current HEAD. * Returns `{ success: true }` on success, or `{ success: false, error }` * when the cherry-pick fails (e.g. conflict). */ cherryPick(sha: string): Promise<{ success: boolean; error?: string; }>; } //# sourceMappingURL=git-operations.d.ts.map