/** * Pure diff-summary + destructive-heuristic module for `qfg push`. * * Implements Guard 3 (pre-push diff summary + destructive-change detection) * from `project/plans/cli-git-sync.md`. This module takes a pre-computed * list of `FileDelta`s (the caller is responsible for walking local vs. * remote trees after `git fetch`) and returns a grouped count + a plain-text * rendering suitable for human confirmation. * * Intentional non-goals: * - No fs / git / network I/O here. Keeps this pure and test-friendly. * - No prompts / TTY handling. The caller owns confirmation UX. * - No ANSI / unicode. Plain ASCII so CI transcripts stay readable. */ /** A single file-level change between the local working tree and remote HEAD. */ export interface FileDelta { /** * Local content for `added`/`modified`. Absent for `deleted`. Required by * the `configs.push` server endpoint when sending the delta over the wire. */ afterJson?: string; /** * Remote content for `modified`/`deleted`. Absent for `added`. Required by * the `configs.push` server endpoint to deep-diff per-environment rule * changes for authorization. */ beforeJson?: string; /** * `added` — present locally, absent on remote * `modified` — present in both, content differs * `deleted` — absent locally, present on remote */ kind: 'added' | 'deleted' | 'modified'; /** Path relative to repo root, e.g. `configs/pricing.json`. */ path: string; } export interface GroupCounts { added: number; deleted: number; modified: number; } export interface DiffSummary { /** Per-top-level-dir counts. See `KNOWN_GROUPS`; anything else lands in `other`. */ byGroup: Record; /** Whether any destructive heuristic fired. */ destructiveReasons: string[]; /** Human-readable reasons that each destructive heuristic fired (one per rule). */ isDestructive: boolean; /** * Render the plain-text summary shown before the user confirms. * All opts are optional; missing string opts render as ``. */ renderText(opts?: { branch?: string; localDir?: string; repoUrl?: string; workspaceSlug?: string; }): string; /** Sum across all groups, plus `filesTouched = added + modified + deleted`. */ totals: { filesTouched: number; } & GroupCounts; } export declare function summarizeDiff(deltas: FileDelta[], opts?: { totalFilesInRemote?: number; unpinned?: boolean; }): DiffSummary;