/**
 * @module _shared/scene-lint
 *
 * In-process Hyperframes lint pipeline for VibeFrame scene projects. Wraps
 * `runHyperframeLint` from `@hyperframes/producer` (its public lint entry
 * point) and adapts the output to VibeFrame's two-tier file structure:
 *
 *   project/
 *     index.html              # root composition  → linted as-is
 *     compositions/*.html     # sub-compositions  → producer's lint emits two
 *                                                   spurious findings here, so
 *                                                   we filter them out.
 *
 * Two findings are filtered for sub-compositions because they encode the
 * inverse rule (sub-comps SHOULD be wrapped in `<template>` and SHOULD NOT
 * have an `<html>` wrapper):
 *   - `standalone_composition_wrapped_in_template`
 *   - `root_composition_missing_html_wrapper`
 *
 * Pure helpers are exported for unit testing; `runProjectLint` does the
 * filesystem walk + lint orchestration. Mechanical `--fix` is intentionally
 * conservative — only `timed_element_missing_clip_class` is auto-fixed in
 * MVP 1.
 */
export type LintSeverity = "error" | "warning" | "info";
export interface LintFinding {
    code: string;
    severity: LintSeverity;
    message: string;
    file?: string;
    selector?: string;
    elementId?: string;
    fixHint?: string;
    snippet?: string;
}
export interface FileLintResult {
    /** Path relative to the project directory. */
    file: string;
    /** True for files under `compositions/` — used to filter false positives. */
    isSubComposition: boolean;
    findings: LintFinding[];
}
export interface FileFixResult {
    file: string;
    /** Codes that were mechanically fixed. */
    codes: string[];
}
export interface ProjectLintResult {
    ok: boolean;
    errorCount: number;
    warningCount: number;
    infoCount: number;
    files: FileLintResult[];
    fixed: FileFixResult[];
}
/** Producer's two findings that are inverse-rules for sub-compositions. */
export declare const SUB_COMP_FALSE_POSITIVES: ReadonlySet<string>;
/**
 * Discover scene files in a project. Returns the root composition (or null
 * if missing) plus every `*.html` file under `compositions/` recursively.
 *
 * Paths returned are absolute. The caller derives project-relative paths via
 * `relative(projectDir, path)`.
 */
export declare function discoverSceneFiles(opts: {
    projectDir: string;
    rootRel?: string;
}): Promise<{
    root: string | null;
    subs: string[];
}>;
/**
 * IEEE float noise threshold for clip-overlap findings. Authored timeline
 * values are exact to 2dp, but the producer computes each clip's end as
 * `start + duration` in binary floats — e.g. 8.26 + 10.98 =
 * 19.240000000000002, which it then flags as "overlapping" a clip starting
 * at 19.24. Anything under 5ms is float noise, not a real overlap.
 */
export declare const OVERLAP_EPSILON_SEC = 0.005;
/** True for overlapping_clips_same_track findings whose overlap is float noise. */
export declare function isEpsilonOverlapFinding(finding: LintFinding): boolean;
/**
 * Drop known false positives: float-epsilon clip overlaps (all files) and
 * the producer findings that are inverse-rules for sub-comp files. Other
 * findings pass through unchanged.
 */
export declare function filterSubCompFalsePositives(findings: LintFinding[], isSubComposition: boolean): LintFinding[];
/**
 * VibeFrame-side finding: inner phase clips inside a sub-composition.
 *
 * The producer's screenshot render mode does NOT toggle the visibility of
 * `.clip` elements INSIDE a sub-composition by their `data-start` window —
 * a scene split into clip phases (0-10s, 10-26s) renders BOTH phases
 * simultaneously and text stacks on top of itself. Root index.html clips
 * are unaffected (their windows work); this rule only applies to
 * sub-composition internals. Phase changes must instead be driven by GSAP
 * (animate the old phase out with autoAlpha, the new one in) inside
 * full-window clips.
 */
export declare function findInternalPhaseClipFindings(html: string): LintFinding[];
/**
 * Append VibeFrame-side findings for sub-composition HTML. Call at every
 * lint site (batch composer, scene_submit, scene repair, project lint) so
 * all authoring paths share the exact same contract.
 */
export declare function withVibeframeSubCompFindings(findings: LintFinding[], html: string, isSubComposition: boolean): LintFinding[];
/**
 * Apply mechanical `--fix` rewrites for known-safe finding codes. Returns the
 * (possibly unchanged) HTML and the list of codes that were fixed at least
 * once.
 *
 * MVP 1 only auto-fixes `timed_element_missing_clip_class` — adding the
 * `clip` class to elements that already carry timing attributes.
 *
 * Other "registration"/"paused" fixes are intentionally NOT mechanical —
 * they require structural reasoning (where to insert the `window.__timelines`
 * block, how to convert an unpaused timeline) that goes beyond a regex.
 * The lint output still surfaces them with `fixHint` for the agent or human
 * to apply.
 */
export declare function applyMechanicalFixes(html: string, findings: LintFinding[]): {
    html: string;
    fixedCodes: string[];
};
export interface RunProjectLintOptions {
    projectDir: string;
    rootRel?: string;
    /** Apply mechanical fixes and write files back. */
    fix?: boolean;
}
/**
 * Walk the project, lint every HTML file, optionally apply mechanical fixes,
 * and return aggregated counts. Throws only on FS errors; lint errors are
 * surfaced as findings, not exceptions.
 */
export declare function runProjectLint(opts: RunProjectLintOptions): Promise<ProjectLintResult>;
/** True if `root` exists and is a regular file. Used by callers that want to
 *  pre-validate before invoking `runProjectLint`. */
export declare function rootExists(projectDir: string, rootRel?: string): Promise<boolean>;
