/** * Git diff integration for drift detection * * Shells out to git to determine what files changed between the current * working tree and a base ref (typically main/master). */ import type { ChangedFile } from '../../types/index.js'; export interface GitDiffOptions { rootPath: string; baseRef: string; pathFilter?: string[]; includeUnstaged: boolean; } export interface GitDiffResult { resolvedBase: string; files: ChangedFile[]; hasUnstagedChanges: boolean; currentBranch: string; } /** * Classify a file path as test/config/generated */ export declare function classifyFile(filePath: string): Pick; /** * Check if a file is a skippable binary/lock file */ export declare function isSkippableFile(filePath: string): boolean; /** * Check whether `rootPath` is inside a git work tree. * * Asks git (`rev-parse --is-inside-work-tree`) rather than testing for a `.git` * entry at `rootPath`. The old `access(rootPath/.git)` test recognized only the * repository ROOT: a monorepo package directory (`repo/packages/foo`) failed it and * every git-derived signal (churn, coupling, provenance, structural diff) silently * went empty there, even though every git shell-out with that cwd succeeds. * `--is-inside-work-tree` is true for the root, any subdirectory, a worktree, and a * submodule checkout alike; it is false inside the `.git` directory and outside any * repository. (Worktrees/submodules previously passed only incidentally because * their `.git` is a file.) */ export declare function isGitRepository(rootPath: string): Promise; /** * Check whether `rootPath` is the ROOT of a git work tree (not a subdirectory of one). * * True iff {@link getRepoPrefix} is the empty string — i.e. inside a work tree AND at * its top level. This is behaviorally identical to the pre-work-tree-aware * `access(rootPath/.git)` test across every case (normal root, worktree/submodule * root where `.git` is a file, subdirectory, `.git` dir, bare repo, non-repo), so it * is the drop-in for git-signal callers that JOIN git's repo-root-relative path output * against analyzed-root-relative data and are therefore only correct when the analyzed * root IS the repository root (drift, decisions, staleness, review). Below-root support * for those flows is out of scope for this change; pinning them here preserves their * exact prior "root-only" behavior instead of silently joining mismatched path frames. */ export declare function isGitRepositoryRoot(rootPath: string): Promise; /** * The repo-root → analyzed-root path prefix, for re-framing git's path-list output. * * Git emits `diff`/`log --name-only` paths relative to the REPOSITORY ROOT * regardless of cwd, while the analyzer's node paths are relative to the analyzed * root. At the repo root the two agree; below it they diverge, so every churn / * provenance / diff join must translate between them. Returns: * - `''` when `rootPath` IS the repository root (re-framing is a no-op), * - `'packages/foo/'` (trailing slash) when `rootPath` is a subdirectory, * - `null` when `rootPath` is not inside a work tree. */ export declare function getRepoPrefix(rootPath: string): Promise; /** * Re-frame one repo-root-relative git path to be relative to the analyzed root, * given a {@link getRepoPrefix} value. Returns `null` for a path OUTSIDE the analyzed * subtree (the caller drops it) or for the analyzed directory itself. With an empty * prefix (the repo root) it is the identity — so callers that re-frame unconditionally * are byte-for-byte unchanged at the root. */ export declare function reframeRepoPath(repoRelPath: string, prefix: string): string | null; /** * Get the current branch name */ export declare function getCurrentBranch(rootPath: string): Promise; /** * Validate a user-supplied git ref to prevent unexpected git argument injection. * Allows branch/tag names, SHA hashes, relative refs (HEAD~1, @{upstream}), and * the empty-tree SHA. Rejects refs containing shell metacharacters or null bytes. * * Argument-injection guard (mcp-security: Subprocess Argument Safety): a ref is * always passed to git as a single argv element, which prevents shell injection but * NOT flag interpretation — `--upload-pack=...` or `--output=x` would still be read * by git as an OPTION. Real refs/branches/SHAs never begin with `-`, so a * leading-dash ref is rejected outright; this is the validation half of the spec's * "`--` separator OR allowlist" requirement (ref operands are also placed after `--` * at the call sites where git supports it). */ export declare function validateGitRef(ref: string): void; /** * True iff `ref` resolves to a commit in the repo at `rootPath`. Unlike * `resolveBaseRef` (which silently falls back to main/master/HEAD~1), this answers * the plain question "does the caller's ref exist?" so a consumer can disclose a * fallback instead of briefing against a base the caller never asked for. Validates * the ref first (argument-injection guard); any failure → false, never throws. */ export declare function refExists(rootPath: string, ref: string): Promise; /** * Resolve a base ref, falling back through main → master → HEAD~1 */ export declare function resolveBaseRef(rootPath: string, preferredRef: string): Promise; /** * The disclosed resolution of a `--base` ref. `requested` is what the caller asked * for (verbatim, or the command's default sentinel); `resolved` is the ref git will * actually diff against after {@link resolveBaseRef}'s main → master → HEAD~1 fallback. * `fellBack` is true exactly when the caller passed an EXPLICIT ref that git could not * resolve — so `resolved` is a base the caller did not ask for. A conclusion command * must never present a verdict over a fallback base without disclosing this. */ export interface BaseRefResolution { requested: string; resolved: string; fellBack: boolean; } /** * Resolve a base ref AND disclose whether the caller's requested ref actually * resolved — the single "resolve-or-disclose" point every `--base` command shares * (fix-cli-conclusion-honesty). Advisory commands surface `fellBack` as a caveat; * certification commands treat it as fatal unless the caller opts into fallback. * * The `auto`/empty sentinel (the briefing default that explicitly REQUESTS the * fallback chain) never counts as a fallback. For an explicit ref we confirm the * fallback with {@link refExists}, so a ref that resolves to a differently-spelled * commit (e.g. a short SHA, a tag) is correctly reported as resolved, not fallen-back. */ export declare function resolveBaseRefDisclosed(rootPath: string, requestedRef: string): Promise; /** * Get the unified diff content for a specific file against a base ref. * Returns the diff text, truncated to maxChars to fit LLM context windows. */ export declare function getFileDiff(rootPath: string, filePath: string, baseRef: string, maxChars?: number): Promise; /** * Get commit messages between baseRef and HEAD as a single string. * Returns empty string if no commits or git fails. */ export declare function getCommitMessages(rootPath: string, baseRef: string): Promise; /** * Get changed files between working tree and a base ref */ export declare function getChangedFiles(options: GitDiffOptions): Promise; //# sourceMappingURL=git-diff.d.ts.map