import type { GitFileDiff, SessionCapabilities, SessionEvent, WorkspaceCaptureManifest } from "@opengeni/sdk"; import { type ClientOverride } from "../provider.js"; export type UseSandboxGitOptions = ClientOverride & { /** Live event log (usually `useSessionEvents().events`) — drives auto-refresh * on `git.changed`. */ events?: SessionEvent[] | undefined; /** Repo root within the workspace (multi-repo). Default: workspace root. */ repoPath?: string | undefined; /** All repository roots in the workspace. When supplied, status and diff are * aggregated into one workspace-wide result and paths are workspace-relative. */ repoPaths?: readonly string[] | undefined; /** Diff the staged index vs HEAD (`--cached`) instead of the working tree. */ staged?: boolean | undefined; /** Review scope. `branch` compares the current branch with the remote default * branch, `working` shows uncommitted edits, and `staged` shows the index. * `staged` above remains as a compatibility alias. */ comparison?: SandboxGitComparison | undefined; /** Hold off the initial fetch. Default true. */ enabled?: boolean | undefined; /** Pause live reads/invalidation while preserving the last rendered result. */ active?: boolean | undefined; /** Lease liveness. `null` means capability negotiation is still pending and * blocks live I/O. When not warm, the diff is served from the capture instead * of a live `gitDiff` RPC. Omission preserves legacy direct-hook behavior. */ liveness?: SessionCapabilities["liveness"] | null | undefined; /** The latest turn-end capture (from `useWorkspaceCapture`). Seeds the diff * immediately; a warm box reconciles live and leaves this durable review * surface in place if the live request is temporarily unavailable. */ capture?: WorkspaceCaptureManifest | null | undefined; }; export type SandboxGitComparison = "branch" | "working" | "staged"; /** A Git diff qualified into workspace scope. `repoRoot` is present for the * workspace-wide path and lets review UI group real repositories without * guessing from the first path segment. */ export type SandboxGitFileDiff = GitFileDiff & { repoRoot?: string | undefined; }; export type UseSandboxGitResult = { /** Working-tree (or staged) diff vs HEAD — the structured hunks the Pierre * diff view renders. */ diff: SandboxGitFileDiff[]; branch: string | null; /** Whether a repo is actually mounted (drives "no repository" vs "no changes"). */ isRepo: boolean; ahead: number; behind: number; /** Number and workspace-relative roots of repositories represented here. */ repoCount: number; repoRoots: string[]; refresh: () => Promise; /** Which source the diff is served from: the live box or the turn-end capture. */ source: "live" | "capture" | null; /** When the served capture was taken (ISO), when `source === "capture"`. */ capturedAt: string | null; loading: boolean; error: Error | null; }; /** * Project the Git service into the Pierre diff data contract: structured * `GitFileDiff[]` (per-file hunks with per-line old/new numbers, rename * detection, binary flag, add/del counts) plus branch + ahead/behind. When the * box is warm the `git diff` runs in-box (API-direct); when it is cold/offline the * diff is served from the turn-end capture instead. Refreshes on * `git.changed`; reconciles live in place on the cold→warm transition. */ export declare function useSandboxGit(sessionId: string | null | undefined, options?: UseSandboxGitOptions): UseSandboxGitResult;