/** Shared between the mirror engine and the settings page. */ export type MirrorDirection = "both" | "pull" | "push"; export type ConflictStrategy = "merge" | "prefer-local" | "prefer-remote"; export type MirrorTrigger = "schedule" | "webhook" | "push" | "manual"; export const MIRROR_DIRECTIONS: MirrorDirection[] = ["both", "pull", "push"]; export const CONFLICT_STRATEGIES: ConflictStrategy[] = ["merge", "prefer-local", "prefer-remote"]; export const DIRECTION_LABELS: Record = { both: "Bidirectional (pull and push)", pull: "Pull only (remote → here)", push: "Push only (here → remote)", }; export const STRATEGY_LABELS: Record = { merge: "Auto-merge; park conflicts for review", "prefer-local": "Auto-merge; conflicting lines keep this repository's side", "prefer-remote": "Auto-merge; conflicting lines keep the remote's side", }; export type MirrorConflict = { ref: string; reason: string; paths: string[]; localSha: string | null; remoteSha: string | null; /** Branch holding the remote tip so it can be merged by hand (in a pull request or locally). */ parkedAs: string | null; }; export type SyncReport = { pulled: string[]; pushed: string[]; merged: string[]; deletedLocal: string[]; deletedRemote: string[]; conflicts: MirrorConflict[]; refused: string[]; skipped: number; }; export type MirrorRun = { startedAt: number; finishedAt: number; trigger: MirrorTrigger; error: string | null; report: SyncReport | null; }; export type MirrorStatus = { enabled: boolean; remoteUrl: string; username: string | null; hasToken: boolean; direction: MirrorDirection; strategy: ConflictStrategy; branches: string[]; syncTags: boolean; propagateDeletes: boolean; configuredBy: string; hourly: boolean; nextRunAt: number | null; pendingAt: number | null; running: boolean; eventsToday: number; eventBudget: number; runs: MirrorRun[]; };