import type { SeriesState, EpisodeScript } from '../series/types.js'; import { type ProjectStatus } from '../session/status.js'; import { type WorkshopDraft } from '../mini-drama/workshop.js'; import type { LoopManifest } from '../mini-drama/loop-engine.js'; import type { StreamManifest } from '../mini-drama/stream-engine.js'; export interface ProjectListEntry { name: string; slug: string; dir: string; } export interface ShotMedia { key: string; shotNumber: number; panel?: string; clip?: string; dialogue?: string; qaVerdict?: string; qaIssues?: string[]; /** * Reference-usage summary from the panel's recipe sidecar: which character * identities were anchored to real reference bytes at draft/refine time and * which fell back to prompt text. Undefined for panels with no recorded * usage (pre-2026-08-11 drafts, or no-character shots). */ refUsage?: { base: string; anchored: string[]; textOnly: string[]; }; /** * Character/location reference images this panel was DRAFTED or REFINED * from (per its recipe sidecar) that no longer exist on disk — i.e. they * were archived/removed after the panel was made. A non-empty list means * the panel still depicts the old reference and should be regenerated. * Labels are the reference's last two path segments (e.g. * "detectives-study/medium.png"). Video-render passes are excluded: they * feed the .mp4, not the .png panel. */ staleRefs?: string[]; } export interface UnitMedia { unitId: string; file?: string; shotNumbers: number[]; model?: string; prompt?: string; } export interface EpisodeState { episode: number; script: EpisodeScript | null; scriptVersions: number[]; qaReport: unknown; videoQaReport: unknown; generationPlan: unknown; shots: ShotMedia[]; units: UnitMedia[]; finalCut?: string; music?: string; /** Loop-preview state, when `venice-video loop` has run for this episode. */ loop?: LoopManifest; /** Stream state, when `venice-video stream` has run for this episode. */ stream?: StreamManifest; } export interface ProjectState { series: SeriesState; status: ProjectStatus | null; workshop: WorkshopDraft | null; episodes: EpisodeState[]; characters: Array<{ name: string; dir: string; art: string[]; angles: AngleArt[]; gender?: string; age?: string; description?: string; wardrobe?: string; voiceLocked: boolean; }>; locations: Array<{ name: string; slug: string; art: string[]; angles: AngleArt[]; }>; } export declare function listProjects(workspaceDir: string): Promise; export interface AngleArt { /** Angle name: front/three-quarter/profile/full-body or wide/medium/detail. */ angle: string; /** Project-relative image path, when the angle has been generated. */ image?: string; /** The positive prompt used, from the .prompt.json sidecar (characters only). */ prompt?: string; /** * The entity's locked description changed since this art was generated * (workshop revision or manual edit) — the image depicts the OLD look and * should be regenerated or archived. */ stale?: boolean; } export declare function collectProjectState(projectDir: string): Promise; //# sourceMappingURL=state.d.ts.map