/** * Type definitions for vidpipe CLI pipeline. * * Domain types covering transcription, video metadata, short-clip planning, * social-media post generation, and end-to-end pipeline orchestration. * * ### Timestamp convention * All `start` and `end` fields are in **seconds from the beginning of the video** * (floating-point, e.g. 12.345). This matches Whisper's output format and * FFmpeg's `-ss` / `-to` parameters. */ /** Social-media platforms supported for post generation. */ declare enum Platform { TikTok = "tiktok", YouTube = "youtube", Instagram = "instagram", LinkedIn = "linkedin", X = "x" } /** * A single word with precise start/end timestamps from Whisper. * * Word-level timestamps are the foundation of the karaoke caption system — * each word knows exactly when it's spoken, enabling per-word highlighting. * Whisper produces these via its `--word_timestamps` flag. * * @property word - The spoken word (may include leading/trailing whitespace) * @property start - When this word begins, in seconds from video start * @property end - When this word ends, in seconds from video start */ interface Word { word: string; start: number; end: number; } /** * A sentence/phrase-level segment from Whisper transcription. * * Segments are Whisper's natural grouping of words into sentences or clauses. * They're used for SRT/VTT subtitle generation (one cue per segment) and for * silence removal (segments that fall entirely within a removed region are dropped). * * @property id - Sequential segment index (0-based) * @property text - Full text of the segment * @property start - Segment start time in seconds * @property end - Segment end time in seconds * @property words - The individual words with their own timestamps */ interface Segment { id: number; text: string; start: number; end: number; words: Word[]; } /** * Complete transcript result from Whisper. * * Contains both segment-level and word-level data. The top-level `words` array * is a flat list of all words across all segments — this is the primary input * for the ASS caption generator's karaoke highlighting. * * @property text - Full transcript as a single string * @property segments - Sentence/phrase-level segments * @property words - Flat array of all words with timestamps (used by ASS captions) * @property language - Detected language code (e.g. "en") * @property duration - Total video duration in seconds */ interface Transcript { text: string; segments: Segment[]; words: Word[]; language: string; duration: number; } /** * Metadata for a video file after ingestion into the repo structure. * * @property originalPath - Where the file was picked up from (e.g. recordings/ folder) * @property repoPath - Canonical path within the repo's asset directory * @property videoDir - Directory containing all generated assets for this video * @property slug - URL/filesystem-safe name derived from the filename (e.g. "my-video-2024-01-15") * @property filename - Original filename with extension * @property duration - Video duration in seconds (from ffprobe) * @property size - File size in bytes * @property createdAt - File creation timestamp * @property layout - Detected layout metadata (webcam region, etc.) */ interface VideoFile { originalPath: string; repoPath: string; videoDir: string; slug: string; filename: string; duration: number; size: number; createdAt: Date; layout?: VideoLayout; /** Path to generated thumbnail image for this video */ thumbnailPath?: string; } /** * Detected layout metadata for a video. * Captures webcam and screen region positions for use in aspect ratio conversion * and production effects. */ interface VideoLayout { /** Video dimensions */ width: number; height: number; /** Detected webcam overlay region (null if no webcam detected) */ webcam: WebcamRegion | null; /** Main screen content region (computed as inverse of webcam) */ screen: ScreenRegion | null; } /** * Webcam overlay region in a screen recording. */ interface WebcamRegion { x: number; y: number; width: number; height: number; position: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'; confidence: number; } /** * Main screen content region (area not occupied by webcam). */ interface ScreenRegion { x: number; y: number; width: number; height: number; } type AspectRatio = '16:9' | '9:16' | '1:1' | '4:5'; type VideoPlatform = 'tiktok' | 'youtube-shorts' | 'instagram-reels' | 'instagram-feed' | 'linkedin' | 'youtube' | 'twitter'; /** * Caption rendering style. * - `'shorts'` — large centered pop captions for short-form clips (landscape 16:9) * - `'medium'` — smaller bottom-positioned captions for longer content * - `'portrait'` — Opus Clips style for 9:16 vertical video (green highlight, * scale-pop animation, larger fonts for small-screen viewing) */ type CaptionStyle = 'shorts' | 'medium' | 'portrait' | 'portrait-lower'; interface ShortClipVariant { path: string; aspectRatio: AspectRatio; platform: VideoPlatform; width: number; height: number; /** Whether a split-screen layout (screen + webcam panels) was used. */ isSplitScreen?: boolean; } /** * A single time range within a short clip. * * Short clips can be **composite** — made of multiple non-contiguous segments * from the original video, concatenated together. Each segment describes one * contiguous range. * * @property start - Start time in the original video (seconds) * @property end - End time in the original video (seconds) * @property description - Human-readable description of what happens in this segment */ interface ShortSegment { start: number; end: number; description: string; } /** * A planned short clip (15–60s) extracted from the full video. * * May be a single contiguous segment or a **composite** of multiple segments * concatenated together (e.g. an intro + punchline from different parts of * the video). The `segments` array defines the source time ranges; `totalDuration` * is the sum of all segment durations. * * @property id - Unique identifier (e.g. "short-1") * @property title - Human-readable title for the clip * @property slug - Filesystem-safe slug (e.g. "typescript-tip-generics") * @property segments - One or more time ranges from the original video * @property totalDuration - Sum of all segment durations in seconds * @property outputPath - Path to the extracted video file * @property captionedPath - Path to the captioned version (if generated) * @property description - Short description for social media * @property tags - Hashtags / topic tags * @property variants - Platform-specific aspect-ratio variants (portrait, square, etc.) */ /** Hook pattern used to capture viewer attention in the first 1-3 seconds */ type HookType = 'cold-open' | 'curiosity-gap' | 'contradiction' | 'result-first' | 'bold-claim' | 'question'; /** Primary emotional trigger that drives engagement (shares, saves, comments) */ type EmotionalTrigger = 'awe' | 'humor' | 'surprise' | 'empathy' | 'outrage' | 'practical-value'; /** Narrative arc structure used in short clips */ type ShortNarrativeStructure = 'result-method-proof' | 'doing-x-wrong' | 'expectation-vs-reality' | 'mini-list' | 'tension-release' | 'loop'; interface ShortClip { id: string; title: string; slug: string; segments: ShortSegment[]; totalDuration: number; outputPath: string; captionedPath?: string; description: string; tags: string[]; hook?: string; variants?: ShortClipVariant[]; /** Hook pattern classification — how the opening captures attention */ hookType?: HookType; /** Primary emotional driver that makes this clip engaging */ emotionalTrigger?: EmotionalTrigger; /** Viral potential score (1-20) based on hook strength, emotion, shareability, completion, replay */ viralScore?: number; /** Narrative arc pattern used in this clip */ narrativeStructure?: ShortNarrativeStructure; /** Why would someone share this with a friend? */ shareReason?: string; /** Whether the content naturally loops back to the beginning */ isLoopCandidate?: boolean; /** Path to generated thumbnail image for this short clip */ thumbnailPath?: string; /** GitHub Issue number of the matched/created idea for this clip (per-clip idea tagging) */ ideaIssueNumber?: number; } /** A planned medium clip segment */ interface MediumSegment { start: number; end: number; description: string; } /** Narrative arc structure used in medium clips */ type MediumNarrativeStructure = 'open-loop-steps-payoff' | 'problem-deepdive-solution' | 'story-arc' | 'debate-comparison' | 'tutorial-micropayoffs'; /** Classification of medium clip content type */ type MediumClipType = 'deep-dive' | 'tutorial' | 'story-arc' | 'debate' | 'problem-solution'; interface MediumClip { id: string; title: string; slug: string; segments: MediumSegment[]; totalDuration: number; outputPath: string; captionedPath?: string; description: string; tags: string[]; hook: string; topic: string; /** Hook pattern classification — how the opening captures attention */ hookType?: HookType; /** Primary emotional driver that makes this clip engaging */ emotionalTrigger?: EmotionalTrigger; /** Viral potential score (1-20) based on hook strength, emotion, shareability, completion, replay */ viralScore?: number; /** Narrative arc pattern used in this clip */ narrativeStructure?: MediumNarrativeStructure; /** Content type classification */ clipType?: MediumClipType; /** Why would someone save this to reference later? */ saveReason?: string; /** Retention hooks planned at ~15-20 second intervals within the clip */ microHooks?: string[]; /** Path to generated thumbnail image for this medium clip */ thumbnailPath?: string; /** GitHub Issue number of the matched/created idea for this clip (per-clip idea tagging) */ ideaIssueNumber?: number; } interface SocialPost { platform: Platform; content: string; hashtags: string[]; links: string[]; characterCount: number; outputPath: string; } /** * A chapter marker for YouTube's chapters feature. * * @property timestamp - Start time in seconds (YouTube shows these as clickable markers) * @property title - Short chapter title (shown in the progress bar) * @property description - Longer description for the README/summary */ interface Chapter { timestamp: number; title: string; description: string; } interface VideoSnapshot { timestamp: number; description: string; outputPath: string; } interface VideoSummary { title: string; overview: string; keyTopics: string[]; snapshots: VideoSnapshot[]; markdownPath: string; } /** Placement region for an image overlay on video */ type OverlayRegion = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right' | 'center-right' | 'center-left'; /** Where on screen to place an overlay image */ interface OverlayPlacement { region: OverlayRegion; avoidAreas: string[]; sizePercent: number; } /** A moment in the video identified by Gemini as needing a visual aid */ interface EnhancementOpportunity { timestampStart: number; timestampEnd: number; topic: string; imagePrompt: string; reason: string; placement: OverlayPlacement; confidence: number; } /** A generated image overlay ready for FFmpeg compositing */ interface GeneratedOverlay { opportunity: EnhancementOpportunity; imagePath: string; width: number; height: number; } /** Result of the visual enhancement stage */ interface VisualEnhancementResult { enhancedVideoPath: string; overlays: GeneratedOverlay[]; analysisTokens: number; imageGenCost: number; } declare enum PipelineStage { Ingestion = "ingestion", Transcription = "transcription", SilenceRemoval = "silence-removal", VisualEnhancement = "visual-enhancement", Chapters = "chapters", Captions = "captions", CaptionBurn = "caption-burn", IntroOutro = "intro-outro", Summary = "summary", IdeaDiscovery = "idea-discovery", Shorts = "shorts", MediumClips = "medium-clips", SocialMedia = "social-media", ShortPosts = "short-posts", MediumClipPosts = "medium-clip-posts", Blog = "blog", QueueBuild = "queue-build", CloudUpload = "cloud-upload" } /** * Per-stage outcome record for pipeline observability. * * @property stage - Which pipeline stage this result is for * @property success - Whether the stage completed without throwing * @property error - Error message if the stage failed * @property duration - Wall-clock time in milliseconds */ interface StageResult { stage: PipelineStage; success: boolean; error?: string; duration: number; } /** * Complete output of a pipeline run. * * Fields are optional because stages can fail independently — a failed * transcription means no summary, but the video metadata is still available. * * @property totalDuration - Total pipeline wall-clock time in milliseconds */ interface PipelineResult { video: VideoFile; transcript?: Transcript; editedVideoPath?: string; captions?: string[]; captionedVideoPath?: string; enhancedVideoPath?: string; introOutroVideoPath?: string; summary?: VideoSummary; chapters?: Chapter[]; shorts: ShortClip[]; mediumClips: MediumClip[]; socialPosts: SocialPost[]; blogPost?: string; stageResults: StageResult[]; totalDuration: number; } /** * Structured progress events emitted during pipeline execution. * * Discriminated union on the `event` field. Consumers parse JSONL from stderr * when `--progress` is passed to `vidpipe process`. */ type ProgressEvent = PipelineStartEvent | StageStartEvent | StageCompleteEvent | StageErrorEvent | StageSkipEvent | PipelineCompleteEvent; interface PipelineStartEvent { event: 'pipeline:start'; videoPath: string; totalStages: number; timestamp: string; } interface StageStartEvent { event: 'stage:start'; stage: PipelineStage; stageNumber: number; totalStages: number; name: string; timestamp: string; } interface StageCompleteEvent { event: 'stage:complete'; stage: PipelineStage; stageNumber: number; totalStages: number; name: string; duration: number; success: true; timestamp: string; } interface StageErrorEvent { event: 'stage:error'; stage: PipelineStage; stageNumber: number; totalStages: number; name: string; duration: number; error: string; timestamp: string; } interface StageSkipEvent { event: 'stage:skip'; stage: PipelineStage; stageNumber: number; totalStages: number; name: string; reason: string; timestamp: string; } interface PipelineCompleteEvent { event: 'pipeline:complete'; totalDuration: number; stagesCompleted: number; stagesFailed: number; stagesSkipped: number; timestamp: string; } /** * Result of the silence removal stage. * * @property editedPath - Path to the video with silence regions cut out * @property removals - Time ranges that were removed (in original video time). * Used by {@link adjustTranscript} to shift transcript timestamps. * @property keepSegments - Inverse of removals — the time ranges that were kept. * Used by the single-pass caption burn to re-create the edit from the original. * @property wasEdited - False if no silence was found and the video is unchanged */ interface SilenceRemovalResult { editedPath: string; removals: { start: number; end: number; }[]; keepSegments: { start: number; end: number; }[]; wasEdited: boolean; } /** * Standard result wrapper for all Copilot SDK agent calls. * * @property success - Whether the agent completed its task * @property data - The parsed result (type varies by agent) * @property error - Error message if the agent failed * @property usage - Token counts for cost tracking */ interface AgentResult { success: boolean; data?: T; error?: string; usage?: { promptTokens: number; completionTokens: number; }; } /** Character limits per social media platform */ declare const PLATFORM_CHAR_LIMITS: Record; /** * Maps vidpipe Platform enum values to Late API platform strings. * Platform.X = 'x' but Late API expects 'twitter'. */ declare function toLatePlatform(platform: Platform): string; /** * Maps a Late API platform string back to vidpipe Platform enum. * * Validates the input against known Platform values to avoid admitting * unknown/unsupported platforms via an unchecked cast. * * @throws {Error} If the platform is not supported */ declare function fromLatePlatform(latePlatform: string): Platform; /** * Normalizes raw platform strings (e.g., from user input or API responses) * to Late API platform names. Handles X/Twitter variants and case-insensitivity. * * @example * normalizePlatformString('X') // 'twitter' * normalizePlatformString('x (twitter)') // 'twitter' * normalizePlatformString('YouTube') // 'youtube' */ declare function normalizePlatformString(raw: string): string; /** Status lifecycle for content ideas */ type IdeaStatus = 'draft' | 'ready' | 'recorded' | 'published'; /** * Record of a piece of content published from an idea. * Appended to `Idea.publishedContent` when queue items are approved/published. */ interface IdeaPublishRecord { /** Content type that was published */ clipType: 'video' | 'short' | 'medium-clip'; /** Platform where content was published */ platform: Platform; /** Links back to QueueItemMetadata.id */ queueItemId: string; /** When the content was published (ISO 8601) */ publishedAt: string; /** Late API post ID for tracking/managing the scheduled post */ latePostId: string; /** Late API dashboard URL for viewing the post */ lateUrl: string; /** Final published URL if available */ publishedUrl?: string; } /** * A content idea generated by the IdeationAgent or created manually. * * Ideas flow through the pipeline: they are created during ideation, * linked to recordings during processing, and tracked through publishing. * The `status` field tracks the lifecycle: draft → ready → recorded → published. */ interface Idea { /** GitHub Issue number — the primary identifier */ issueNumber: number; /** GitHub Issue URL (e.g., https://github.com/htekdev/content-management/issues/1) */ issueUrl: string; /** Repository full name (e.g., htekdev/content-management) */ repoFullName: string; /** Legacy slug ID for migration compatibility (e.g., "idea-copilot-debugging") */ id: string; /** Main topic/title of the idea (= issue title) */ topic: string; /** The attention-grabbing angle (≤80 chars) */ hook: string; /** Who this content is for */ audience: string; /** The one thing the viewer should remember */ keyTakeaway: string; /** Bullet points to cover in the recording */ talkingPoints: string[]; /** Target platforms for this content (derived from platform:* labels) */ platforms: Platform[]; /** Lifecycle status (derived from status:* label) */ status: IdeaStatus; /** Tags for categorization and matching (derived from freeform labels) */ tags: string[]; /** When the idea was created (from issue created_at) */ createdAt: string; /** When the idea was last updated (from issue updated_at) */ updatedAt: string; /** Deadline for publishing this idea's content (ISO 8601 date). Agent sets based on timeliness: * - Hot trend: 3-5 days out * - Timely event: 1-2 weeks out * - Evergreen: 3-6 months out */ publishBy: string; /** Video slug linked after recording — parsed from video-link issue comments */ sourceVideoSlug?: string; /** Why this is timely — context from trend research */ trendContext?: string; /** Tracks every piece of content published for this idea — parsed from issue comments */ publishedContent?: IdeaPublishRecord[]; } /** Input for creating a new idea — omits fields derived from GitHub Issue metadata */ interface CreateIdeaInput { /** Main topic/title (becomes issue title) */ topic: string; /** The attention-grabbing angle (≤80 chars) */ hook: string; /** Who this content is for */ audience: string; /** The one thing the viewer should remember */ keyTakeaway: string; /** Bullet points to cover in the recording */ talkingPoints: string[]; /** Target platforms for this content */ platforms: Platform[]; /** Tags for categorization and matching */ tags: string[]; /** Deadline for publishing (ISO 8601 date) */ publishBy: string; /** Why this is timely — context from trend research */ trendContext?: string; } /** Filters for querying ideas from GitHub Issues */ interface IdeaFilters { /** Filter by lifecycle status */ status?: IdeaStatus; /** Filter by target platform */ platform?: Platform; /** Filter by tag label */ tag?: string; /** Filter by priority label */ priority?: 'hot-trend' | 'timely' | 'evergreen'; /** Maximum number of results */ limit?: number; } /** Discriminated type for structured issue comments */ type IdeaCommentData = { type: 'publish-record'; record: IdeaPublishRecord; } | { type: 'video-link'; videoSlug: string; linkedAt: string; }; /** Schedule time slot for a platform */ interface ScheduleSlot { platform: string; scheduledFor: string; postId?: string; itemId?: string; label?: string; } /** File extensions accepted as pipeline input. */ declare const SUPPORTED_VIDEO_EXTENSIONS: readonly [".mp4", ".webm"]; /** Available modes for the `ideate start` command */ type StartMode = 'interview'; /** A single question-answer pair from an interview session */ interface QAPair { /** The question asked by the agent */ question: string; /** The user's response */ answer: string; /** ISO 8601 timestamp of when the question was asked */ askedAt: string; /** ISO 8601 timestamp of when the answer was provided */ answeredAt: string; /** Sequential question number (1-based) */ questionNumber: number; } /** Context provided alongside a question */ interface QuestionContext { /** Why this question is being asked */ rationale: string; /** Which idea field this question explores (if any) */ targetField?: keyof CreateIdeaInput; /** Sequential question number (1-based) */ questionNumber: number; } /** Insights discovered during an interview that can update idea fields */ interface InterviewInsights { /** Refined talking points discovered from Q&A */ talkingPoints?: string[]; /** Refined key takeaway */ keyTakeaway?: string; /** Refined hook angle */ hook?: string; /** Refined audience description */ audience?: string; /** Additional trend context discovered */ trendContext?: string; /** New tags suggested */ tags?: string[]; } /** Result of a completed interview session */ interface InterviewResult { /** The idea that was interviewed */ ideaNumber: number; /** Full Q&A transcript */ transcript: QAPair[]; /** Insights discovered by the agent */ insights: InterviewInsights; /** Fields that were updated on the idea */ updatedFields: (keyof CreateIdeaInput)[]; /** Total duration of the interview in milliseconds */ durationMs: number; /** Whether the interview completed naturally or was ended early */ endedBy: 'agent' | 'user'; } /** Discriminated union of all interview events */ type InterviewEvent = InterviewStartEvent | QuestionAskedEvent | AnswerReceivedEvent | ThinkingStartEvent | ThinkingEndEvent | ToolCallStartEvent | ToolCallEndEvent | InsightDiscoveredEvent | InterviewCompleteEvent | InterviewErrorEvent; interface InterviewStartEvent { readonly event: 'interview:start'; readonly ideaNumber: number; readonly mode: StartMode; readonly ideaTopic: string; readonly timestamp: string; } interface QuestionAskedEvent { readonly event: 'question:asked'; readonly question: string; readonly context: QuestionContext; readonly timestamp: string; } interface AnswerReceivedEvent { readonly event: 'answer:received'; readonly questionNumber: number; readonly answer: string; readonly timestamp: string; } interface ThinkingStartEvent { readonly event: 'thinking:start'; readonly timestamp: string; } interface ThinkingEndEvent { readonly event: 'thinking:end'; readonly durationMs: number; readonly timestamp: string; } interface ToolCallStartEvent { readonly event: 'tool:start'; readonly toolName: string; readonly timestamp: string; } interface ToolCallEndEvent { readonly event: 'tool:end'; readonly toolName: string; readonly durationMs: number; readonly timestamp: string; } interface InsightDiscoveredEvent { readonly event: 'insight:discovered'; readonly insight: string; readonly field: keyof CreateIdeaInput; readonly timestamp: string; } interface InterviewCompleteEvent { readonly event: 'interview:complete'; readonly result: InterviewResult; readonly timestamp: string; } interface InterviewErrorEvent { readonly event: 'interview:error'; readonly error: string; readonly timestamp: string; } /** * Async function that provides an answer to a question. * Called by the agent when it needs user input. * The SDK consumer or CLI UI implements this to show the question and collect the response. */ type AnswerProvider = (question: string, context: QuestionContext) => Promise; /** A single section in a recording agenda, mapped to one idea. */ interface AgendaSection { /** Section position (1-based) */ order: number; /** Section title for the recording outline */ title: string; /** GitHub Issue number of the idea this section covers */ ideaIssueNumber: number; /** Estimated recording time in minutes */ estimatedMinutes: number; /** Talking points to cover in this section (from the idea + agent refinement) */ talkingPoints: string[]; /** Transition phrase to lead into the NEXT section (empty for last section) */ transition: string; /** Recording notes: key phrases, visual cues, energy direction */ notes: string; } /** Complete result from agenda generation. */ interface AgendaResult { /** Ordered list of recording sections */ sections: AgendaSection[]; /** Opening hook/intro text for the recording */ intro: string; /** Closing CTA/outro text */ outro: string; /** Total estimated recording duration in minutes */ estimatedDuration: number; /** Fully formatted markdown agenda ready to print or save */ markdown: string; /** Generation duration in milliseconds */ durationMs: number; } /** Options for generating a recording agenda. */ interface GenerateAgendaOptions { /** Override the output file path for the agenda markdown */ outputPath?: string; } interface AppEnvironment { OPENAI_API_KEY: string; WATCH_FOLDER: string; REPO_ROOT: string; FFMPEG_PATH: string; FFPROBE_PATH: string; EXA_API_KEY: string; EXA_MCP_URL: string; YOUTUBE_API_KEY: string; PERPLEXITY_API_KEY: string; LLM_PROVIDER: string; LLM_MODEL: string; ANTHROPIC_API_KEY: string; OUTPUT_DIR: string; BRAND_PATH: string; VERBOSE: boolean; SKIP_SILENCE_REMOVAL: boolean; SKIP_SHORTS: boolean; SKIP_MEDIUM_CLIPS: boolean; SKIP_SOCIAL: boolean; SKIP_CAPTIONS: boolean; SKIP_VISUAL_ENHANCEMENT: boolean; SKIP_INTRO_OUTRO: boolean; LATE_API_KEY: string; LATE_PROFILE_ID: string; SKIP_SOCIAL_PUBLISH: boolean; GEMINI_API_KEY: string; GEMINI_MODEL: string; /** GitHub repository for idea tracking (format: owner/repo) */ IDEAS_REPO: string; /** GitHub Personal Access Token with repo + project scopes */ GITHUB_TOKEN: string; /** Per-agent model overrides from MODEL_* env vars (e.g. MODEL_SHORTS_AGENT=gpt-4o) */ MODEL_OVERRIDES: Readonly>; /** Azure Storage account name for cloud persistence */ AZURE_STORAGE_ACCOUNT_NAME: string; /** Azure Storage account key for authentication */ AZURE_STORAGE_ACCOUNT_KEY: string; /** Azure Blob container name (default: vidpipe) */ AZURE_CONTAINER_NAME: string; } interface GlobalCredentials { openaiApiKey?: string; anthropicApiKey?: string; exaApiKey?: string; youtubeApiKey?: string; perplexityApiKey?: string; lateApiKey?: string; githubToken?: string; geminiApiKey?: string; azureStorageAccountName?: string; azureStorageAccountKey?: string; } interface GlobalDefaults { llmProvider?: string; llmModel?: string; outputDir?: string; watchFolder?: string; brandPath?: string; ideasRepo?: string; lateProfileId?: string; geminiModel?: string; scheduleConfig?: string; } interface GlobalConfig { credentials: GlobalCredentials; defaults: GlobalDefaults; } type DayOfWeek = 'mon' | 'tue' | 'wed' | 'thu' | 'fri' | 'sat' | 'sun'; interface TimeSlot { days: DayOfWeek[]; time: string; label: string; } interface ClipTypeSchedule { slots: TimeSlot[]; avoidDays: DayOfWeek[]; queueId?: string; queueName?: string; } interface PlatformSchedule { slots: TimeSlot[]; avoidDays: DayOfWeek[]; byClipType?: Record; } interface IdeaSpacingConfig { samePlatformHours: number; crossPlatformHours: number; } interface DisplacementConfig { enabled: boolean; canDisplace: 'non-idea-only'; } interface ScheduleConfig { timezone: string; platforms: Record; ideaSpacing?: IdeaSpacingConfig; displacement?: DisplacementConfig; } /** * Configuration options for the VidPipe SDK factory. * * All properties are optional so the SDK can be created with zero configuration. */ interface VidPipeConfig { openaiApiKey?: string; anthropicApiKey?: string; exaApiKey?: string; youtubeApiKey?: string; perplexityApiKey?: string; lateApiKey?: string; lateProfileId?: string; githubToken?: string; geminiApiKey?: string; llmProvider?: 'copilot' | 'openai' | 'claude'; llmModel?: string; outputDir?: string; watchFolder?: string; brandPath?: string; repoRoot?: string; verbose?: boolean; ideasRepo?: string; geminiModel?: string; } /** * Options for processing a video through the VidPipe pipeline. */ interface ProcessOptions { /** Comma-separated idea issue numbers to link to this video */ ideas?: number[]; /** Skip the silence removal stage */ skipSilenceRemoval?: boolean; /** Skip short clip generation */ skipShorts?: boolean; /** Skip medium clip generation */ skipMediumClips?: boolean; /** Skip social content generation */ skipSocial?: boolean; /** Skip caption generation and caption burn steps */ skipCaptions?: boolean; /** Skip visual enhancement processing */ skipVisualEnhancement?: boolean; /** Skip publishing generated social content */ skipSocialPublish?: boolean; /** Pipeline spec preset name or path to YAML spec file */ spec?: string; /** ISO 8601 date for the publish-by deadline of auto-created ideas (default: 7 days from now) */ publishBy?: string; /** Callback for real-time pipeline progress events (stage starts, completions, errors) */ onProgress?: (event: ProgressEvent) => void; } /** * Options for AI-assisted idea generation. */ interface IdeateOptions { /** Seed topics for idea generation */ topics?: string[]; /** Number of ideas to generate */ count?: number; /** Path to brand.json config */ brandPath?: string; /** When true, allows count=1 (bypasses minimum idea count). Used for single-topic idea creation. */ singleTopic?: boolean; } /** * Options for finding the next scheduling slot. */ interface SlotOptions { /** Idea issue numbers for spacing rules */ ideaIds?: number[]; /** Urgency deadline (ISO 8601 date) */ publishBy?: string; } /** * Options for schedule realignment. */ interface RealignOptions { /** Filter to specific platform */ platform?: string; /** Preview only, don't execute */ dryRun?: boolean; } /** * A single diagnostic check returned by the SDK doctor command. */ interface DiagnosticCheck { name: string; status: 'pass' | 'fail' | 'warn'; message: string; details?: string; } /** * Aggregate result returned by the SDK doctor command. */ interface DiagnosticResult { checks: DiagnosticCheck[]; allPassed: boolean; } /** * Union of clip result types produced by VidPipe. */ type GeneratedClip = ShortClip | MediumClip; /** * Options for starting an interactive interview session on an idea. */ interface StartInterviewOptions { /** Session mode (default: 'interview') */ mode?: StartMode; /** * Async function called when the agent asks a question. * The SDK consumer shows the question and returns the user's answer. */ answerProvider: AnswerProvider; /** Callback for real-time interview events (questions, thinking, tool calls, insights) */ onEvent?: (event: InterviewEvent) => void; } /** * Options for generating a recording agenda from multiple ideas. */ interface GenerateAgendaSDKOptions { /** Override the output file path for the agenda markdown */ outputPath?: string; } /** * Main VidPipe SDK interface. */ interface VidPipeSDK { /** Run the full video processing pipeline */ processVideo(videoPath: string, options?: ProcessOptions): Promise; /** Generate AI-powered content ideas */ ideate(options?: IdeateOptions): Promise; /** Start an interactive session to develop an idea (Socratic interview, etc.) */ startInterview(ideaNumber: number, options: StartInterviewOptions): Promise; /** Generate a structured recording agenda from multiple ideas */ generateAgenda(ideaNumbers: number[], options?: GenerateAgendaSDKOptions): Promise; /** Idea management */ ideas: { list(filters?: IdeaFilters): Promise; get(issueNumber: number): Promise; create(input: CreateIdeaInput): Promise; update(issueNumber: number, updates: Partial): Promise; }; /** Schedule management */ schedule: { findNextSlot(platform: string, clipType?: string, options?: SlotOptions): Promise; getCalendar(startDate?: Date, endDate?: Date): Promise; realign(options?: RealignOptions): Promise<{ moved: number; skipped: number; }>; loadConfig(): Promise; }; /** Video operations */ video: { extractClip(videoPath: string, start: number, end: number, output: string): Promise; burnCaptions(videoPath: string, captionsFile: string, output: string): Promise; detectSilence(videoPath: string, options?: { threshold?: string; minDuration?: number; }): Promise>; generateVariants(videoPath: string, platforms: Platform[], outputDir: string): Promise>; captureFrame(videoPath: string, timestamp: number, output: string): Promise; }; /** Social media operations */ social: { generatePosts(context: { title: string; description: string; tags: string[]; }, platforms: Platform[]): Promise; }; /** Run diagnostic checks */ doctor(): Promise; /** Configuration access */ config: { get(key: string): string | boolean | undefined; getAll(): AppEnvironment; getGlobal(): GlobalConfig; set(key: string, value: string | boolean): void; save(): Promise; path(): string; }; /** Cloud storage operations (Azure) */ cloud: { /** Upload a video to Azure Storage and trigger GitHub Actions pipeline */ process(videoPath: string, options?: { spec?: string; ideas?: string; publishBy?: string; repo?: string; }): Promise<{ runId: string; blobPath: string; workflowTriggered: boolean; }>; /** Upload config files (schedule.json, brand.json, assets/) to Azure */ pushConfig(): Promise<{ uploaded: number; }>; /** Download config files from Azure to local vidpipe directory */ pullConfig(): Promise<{ downloaded: number; }>; /** Upload existing local publish-queue/ and published/ to Azure */ migrate(): Promise<{ uploaded: number; errors: string[]; }>; /** Download a video from Azure blob (blob://) or HTTP URL */ download(videoUrl: string, outputPath: string): Promise; /** Check Azure connection status and stored content */ status(): Promise<{ configured: boolean; configFiles: number; contentItems: number; videos: number; }>; /** Check if Azure Storage credentials are configured */ isConfigured(): boolean; }; } declare function createVidPipe(sdkConfig?: VidPipeConfig): VidPipeSDK; type ProgressListener = (event: ProgressEvent) => void; type InterviewListener = (event: InterviewEvent) => void; export { type AgendaResult, type AgendaSection, type AgentResult, type AnswerProvider, type AnswerReceivedEvent, type AspectRatio, type CaptionStyle, type Chapter, type CreateIdeaInput, type DiagnosticCheck, type DiagnosticResult, type EmotionalTrigger, type EnhancementOpportunity, type GenerateAgendaOptions, type GeneratedClip, type GeneratedOverlay, type HookType, type Idea, type IdeaCommentData, type IdeaFilters, type IdeaPublishRecord, type IdeaStatus, type IdeateOptions, type InsightDiscoveredEvent, type InterviewCompleteEvent, type InterviewErrorEvent, type InterviewEvent, type InterviewInsights, type InterviewListener, type InterviewResult, type InterviewStartEvent, type MediumClip, type MediumClipType, type MediumNarrativeStructure, type MediumSegment, type OverlayPlacement, type OverlayRegion, PLATFORM_CHAR_LIMITS, type PipelineCompleteEvent, type PipelineResult, PipelineStage, type PipelineStartEvent, Platform, type ProcessOptions, type ProgressEvent, type ProgressListener, type QAPair, type QuestionAskedEvent, type QuestionContext, type RealignOptions, SUPPORTED_VIDEO_EXTENSIONS, type ScheduleSlot, type ScreenRegion, type Segment, type ShortClip, type ShortClipVariant, type ShortNarrativeStructure, type ShortSegment, type SilenceRemovalResult, type SlotOptions, type SocialPost, type StageCompleteEvent, type StageErrorEvent, type StageResult, type StageSkipEvent, type StageStartEvent, type StartInterviewOptions, type StartMode, type ThinkingEndEvent, type ThinkingStartEvent, type ToolCallEndEvent, type ToolCallStartEvent, type Transcript, type VidPipeConfig, type VidPipeSDK, type VideoFile, type VideoLayout, type VideoPlatform, type VideoSnapshot, type VideoSummary, type VisualEnhancementResult, type WebcamRegion, type Word, createVidPipe, fromLatePlatform, normalizePlatformString, toLatePlatform };