import type { Draft } from "../draft.js"; import { type Flags } from "../utils/cli.js"; export type Severity = "error" | "warning" | "info"; export interface Finding { id: string; severity: Severity; message: string; location: { kind: "segment" | "material" | "track" | "file" | "draft"; ref: string; } | null; fixable: boolean; fix_hint: string | null; } export interface ValidateOpts { strict?: boolean; checkAssets?: boolean; checkTimelines?: boolean; ids?: string[]; skip?: string[]; /** Override CapCut's projects-root for the meta.* checks (defaults to * defaultProjectsRoot()). Mainly for tests + non-standard installs. */ projectsRoot?: string; } export interface ValidateCtx { draft: Draft; draftDir: string | null; /** Exact ids of every material across all Array.isArray slots. */ idSet: Set; /** Every id reachable from a segment (material_id + extra_material_refs) or a * non-empty effect bind_segment_id — the union used for orphan polarity. */ referencedIdSet: Set; opts: ValidateOpts; } /** The segment-orphan ids in the three media/text slots, grouped per slot — the * shared definition of "orphan" that `gc` deletes against (so validate and gc * never drift). Reuses the SAME reachability union (collectReferencedIds); a * material absent from it is genuinely unreferenced (0 material->material edges, * verified across all fixtures). Returns ids, not Findings — so gc can tell * videos from audios, which the single `orphan_media` finding id cannot. */ export declare function collectOrphans(draft: Draft): { texts: string[]; videos: string[]; audios: string[]; }; /** True when the draft has an error-severity invariant break that makes a * destructive gc unsafe: a dangling segment->material ref (already inconsistent) * or a duplicate material id (which makes "the orphan with id X" ambiguous). gc * refuses on either. Pure — does NOT run the full linter / FS checks. */ export declare function hasBlockingErrors(draft: Draft): boolean; /** Cheap structural fingerprint — never a deep-equal (CapCut's mirror differs in * many benign fields). Only catastrophic drift (duration / segment count) trips. */ export declare function draftSignature(d: { duration?: unknown; tracks?: unknown; }): string; interface CheckDef { id: string; run: (ctx: ValidateCtx) => Finding[]; /** When present and false, the check is counted as skipped (FS/opt-in gates). */ gate?: (ctx: ValidateCtx) => boolean; } export declare const CHECKS: CheckDef[]; export interface Report { schema: "capcut-david/validate@1"; ok: boolean; findings: Finding[]; summary: { errors: number; warnings: number; info: number; checks_run: number; checks_skipped: number; }; } export declare function runValidate(draft: Draft, draftDir: string | null, opts: ValidateOpts): Report; /** Exit code for a run that COMPLETED (tool failures exit 1 elsewhere): * 0 = nothing at/above the failure threshold, 2 = something is. */ export declare function reportExitCode(report: Report): number; /** * CLI entry. Read-only: never writes a byte. Returns the process exit code * (0/2) — a tool failure (bad path / unparseable JSON) throws a CliError that * the index.ts try/catch turns into exit 1, never reaching here. * * `projectInput` is the ORIGINAL argument (dir or file). findDraft collapses * both to the same draft_content.json, so we re-derive the dir-vs-file * distinction here: a bare file → draftDir null → FS meta.* checks skip. */ export declare function cmdValidate(draft: Draft, filePath: string, projectInput: string, flags: Flags): number; export {};