import type { GitRepoStatus } from './git-types.js';
import { type DaemonBuildInfo } from '../build-info.js';
import { type ChangeImpactConfig, type ChangeImpactKind } from './change-impact-config.js';
/**
 * TTL for the happy-path result cache (C1). reconcile fires every 4s and mesh_status
 * is polled; a single getGitRepoStatus on a 1-submodule repo spawns ~13-15 git
 * processes (+ optional network fetch) which on Windows is ~10-15s. Within this short
 * window, repeat callers that share the same option shape are served the already
 * collected status instead of re-shelling. Kept well under the 4s reconcile cadence so
 * a genuinely fresh probe still happens at least roughly once per reconcile tick.
 */
export declare const GIT_STATUS_CACHE_TTL_MS = 1500;
/** Test seam: clear the last-known-good status cache between cases. */
export declare function __resetGitStatusCacheForTests(): void;
/** Alias matching the task's requested name. */
export declare const __resetGitStatusCache: typeof __resetGitStatusCacheForTests;
/** Test-only introspection: number of memoized Change Impact evaluations. */
export declare function __changeImpactEvalCacheSizeForTests(): number;
export interface GitStatusOptions {
    timeoutMs?: number;
    /** When true, include submodule status in the result. Defaults to true. */
    includeSubmodules?: boolean;
    /** Optional filter to exclude specific submodule paths from status */
    submoduleIgnorePaths?: string[];
    /**
     * When true, refresh the tracked remote before trusting ahead/behind.
     * Callers should opt into this only for convergence-critical surfaces.
     */
    refreshUpstream?: boolean;
    /**
     * When true, bypass the C1 TTL result cache: always re-collect a fresh status
     * (ignoring any cached entry younger than GIT_STATUS_CACHE_TTL_MS). The freshly
     * collected result still UPDATES the cache so subsequent normal callers benefit.
     *
     * Mutating / decision callers (mesh_fast_forward preflight + post-merge re-read,
     * refine submodule alignment pre/post status) MUST set this — acting on a stale
     * ahead/behind or submodule sync verdict is the primary correctness hazard of the
     * cache. Read-only/observe callers (mesh_status, git-monitor, reconcile) leave it
     * unset and enjoy the dedup.
     */
    forceFresh?: boolean;
    /**
     * Test/override seam for the daemon build stamp used by the stale-build
     * detector. Production callers omit this so the real baked-in build commit
     * (getDaemonBuildInfo) is used.
     */
    daemonBuildInfo?: DaemonBuildInfo;
    /**
     * Change Impact policy override. When provided, the daemonBuildBehind
     * classifier uses this declarative config instead of auto-loading the repo's
     * `.adhdev/change-impact.*` file. When omitted, getGitRepoStatus auto-loads the
     * repo config (cached); when neither is present the built-in ADHDev default
     * policy applies, preserving the legacy behavior exactly.
     *
     * Pass `null` to force the built-in default policy and skip auto-loading (used
     * to assert legacy parity in tests).
     */
    changeImpactConfig?: ChangeImpactConfig | null;
}
/**
 * C2: minimum interval between actual `git fetch` network calls per workspace. A
 * refreshUpstream caller within this window does NOT re-fetch; it serves ahead/behind
 * from the locally-re-read porcelain (which is always fresh every call). So
 * refreshUpstream becomes "fetch if the local remote-tracking ref is stale" rather than
 * "always pay a network round trip". Only the upstream ahead/behind can age up to this
 * throttle; local working-tree status never does.
 */
export declare const GIT_FETCH_THROTTLE_MS = 30000;
export declare function getGitRepoStatus(workspace: string, options?: GitStatusOptions): Promise<GitRepoStatus>;
/** Coarse change-impact verdict produced from a changed-file list. */
export interface ChangedPackageClassification {
    isDaemonAffecting: boolean;
    affectedPackages: string[];
    /**
     * DOCS-ROOT: three-way change area, refining the binary isDaemonAffecting so a
     * docs-only branch is distinguishable from a code (web) branch:
     *   'daemon' — a daemon-runtime package (or an unknown/ambiguous path) changed;
     *              full validation + daemon rebuild/restart required.
     *   'web'    — only web-only packages changed; web validation but no daemon restart.
     *   'none'   — no package changed at all; every changed file is a benign non-runtime
     *              root file (docs/markers). No code validation is meaningful — only an
     *              explicit docs-scoped profile (e.g. docs:verify) should run.
     * Derived from the same facts as isDaemonAffecting, so it never contradicts it
     * (changeArea === 'daemon' ⇔ isDaemonAffecting === true).
     */
    changeArea: ChangeImpactKind;
}
/**
 * Ref-parameterized change-impact classification for a repo/worktree, reusing the
 * exact daemon-vs-web bucketing that the stale-build detector uses — but over an
 * arbitrary `fromRef..toRef` range (e.g. a refine base head → branch head) instead
 * of the live daemon's build commit → HEAD, and WITHOUT any daemonBuildInfo caching.
 *
 * Policy is resolved the same way as getGitRepoStatus: an explicit
 * `options.changeImpactConfig` wins; otherwise the repo's `.adhdev/change-impact.*`
 * is auto-loaded; otherwise the built-in ADHDev default policy applies. The
 * classification uses `git diff --name-only fromRef..toRef`.
 *
 * FAIL-OPEN on error: if the diff can't be collected (bad ref, not a repo), the
 * caller should treat "no verdict" as "run everything" — so we throw rather than
 * returning a misleading benign verdict. Callers wrap this in try/catch and leave
 * changeImpact undefined on failure. Unclassified/new packages still default to
 * isDaemonAffecting:true (never silently skipped).
 */
export declare function classifyChangedPackages(repoPath: string, fromRef: string, toRef: string, options?: GitStatusOptions): Promise<ChangedPackageClassification>;
interface ParsedPorcelainStatus {
    branch: string | null;
    /** Full HEAD object id from `# branch.oid`, or null when detached/unborn. */
    headOid: string | null;
    upstream: string | null;
    ahead: number;
    behind: number;
    staged: number;
    modified: number;
    untracked: number;
    deleted: number;
    renamed: number;
    conflictFiles: string[];
}
export declare function parsePorcelainV2Status(output: string): ParsedPorcelainStatus;
export {};
