vidpipe 1.3.8 → 1.3.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,816 @@
1
+ /**
2
+ * Type definitions for vidpipe CLI pipeline.
3
+ *
4
+ * Domain types covering transcription, video metadata, short-clip planning,
5
+ * social-media post generation, and end-to-end pipeline orchestration.
6
+ *
7
+ * ### Timestamp convention
8
+ * All `start` and `end` fields are in **seconds from the beginning of the video**
9
+ * (floating-point, e.g. 12.345). This matches Whisper's output format and
10
+ * FFmpeg's `-ss` / `-to` parameters.
11
+ */
12
+ /** Social-media platforms supported for post generation. */
13
+ declare enum Platform {
14
+ TikTok = "tiktok",
15
+ YouTube = "youtube",
16
+ Instagram = "instagram",
17
+ LinkedIn = "linkedin",
18
+ X = "x"
19
+ }
20
+ /**
21
+ * A single word with precise start/end timestamps from Whisper.
22
+ *
23
+ * Word-level timestamps are the foundation of the karaoke caption system —
24
+ * each word knows exactly when it's spoken, enabling per-word highlighting.
25
+ * Whisper produces these via its `--word_timestamps` flag.
26
+ *
27
+ * @property word - The spoken word (may include leading/trailing whitespace)
28
+ * @property start - When this word begins, in seconds from video start
29
+ * @property end - When this word ends, in seconds from video start
30
+ */
31
+ interface Word {
32
+ word: string;
33
+ start: number;
34
+ end: number;
35
+ }
36
+ /**
37
+ * A sentence/phrase-level segment from Whisper transcription.
38
+ *
39
+ * Segments are Whisper's natural grouping of words into sentences or clauses.
40
+ * They're used for SRT/VTT subtitle generation (one cue per segment) and for
41
+ * silence removal (segments that fall entirely within a removed region are dropped).
42
+ *
43
+ * @property id - Sequential segment index (0-based)
44
+ * @property text - Full text of the segment
45
+ * @property start - Segment start time in seconds
46
+ * @property end - Segment end time in seconds
47
+ * @property words - The individual words with their own timestamps
48
+ */
49
+ interface Segment {
50
+ id: number;
51
+ text: string;
52
+ start: number;
53
+ end: number;
54
+ words: Word[];
55
+ }
56
+ /**
57
+ * Complete transcript result from Whisper.
58
+ *
59
+ * Contains both segment-level and word-level data. The top-level `words` array
60
+ * is a flat list of all words across all segments — this is the primary input
61
+ * for the ASS caption generator's karaoke highlighting.
62
+ *
63
+ * @property text - Full transcript as a single string
64
+ * @property segments - Sentence/phrase-level segments
65
+ * @property words - Flat array of all words with timestamps (used by ASS captions)
66
+ * @property language - Detected language code (e.g. "en")
67
+ * @property duration - Total video duration in seconds
68
+ */
69
+ interface Transcript {
70
+ text: string;
71
+ segments: Segment[];
72
+ words: Word[];
73
+ language: string;
74
+ duration: number;
75
+ }
76
+ /**
77
+ * Metadata for a video file after ingestion into the repo structure.
78
+ *
79
+ * @property originalPath - Where the file was picked up from (e.g. recordings/ folder)
80
+ * @property repoPath - Canonical path within the repo's asset directory
81
+ * @property videoDir - Directory containing all generated assets for this video
82
+ * @property slug - URL/filesystem-safe name derived from the filename (e.g. "my-video-2024-01-15")
83
+ * @property filename - Original filename with extension
84
+ * @property duration - Video duration in seconds (from ffprobe)
85
+ * @property size - File size in bytes
86
+ * @property createdAt - File creation timestamp
87
+ * @property layout - Detected layout metadata (webcam region, etc.)
88
+ */
89
+ interface VideoFile {
90
+ originalPath: string;
91
+ repoPath: string;
92
+ videoDir: string;
93
+ slug: string;
94
+ filename: string;
95
+ duration: number;
96
+ size: number;
97
+ createdAt: Date;
98
+ layout?: VideoLayout;
99
+ }
100
+ /**
101
+ * Detected layout metadata for a video.
102
+ * Captures webcam and screen region positions for use in aspect ratio conversion
103
+ * and production effects.
104
+ */
105
+ interface VideoLayout {
106
+ /** Video dimensions */
107
+ width: number;
108
+ height: number;
109
+ /** Detected webcam overlay region (null if no webcam detected) */
110
+ webcam: WebcamRegion | null;
111
+ /** Main screen content region (computed as inverse of webcam) */
112
+ screen: ScreenRegion | null;
113
+ }
114
+ /**
115
+ * Webcam overlay region in a screen recording.
116
+ */
117
+ interface WebcamRegion {
118
+ x: number;
119
+ y: number;
120
+ width: number;
121
+ height: number;
122
+ position: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
123
+ confidence: number;
124
+ }
125
+ /**
126
+ * Main screen content region (area not occupied by webcam).
127
+ */
128
+ interface ScreenRegion {
129
+ x: number;
130
+ y: number;
131
+ width: number;
132
+ height: number;
133
+ }
134
+ type AspectRatio = '16:9' | '9:16' | '1:1' | '4:5';
135
+ type VideoPlatform = 'tiktok' | 'youtube-shorts' | 'instagram-reels' | 'instagram-feed' | 'linkedin' | 'youtube' | 'twitter';
136
+ /**
137
+ * Caption rendering style.
138
+ * - `'shorts'` — large centered pop captions for short-form clips (landscape 16:9)
139
+ * - `'medium'` — smaller bottom-positioned captions for longer content
140
+ * - `'portrait'` — Opus Clips style for 9:16 vertical video (green highlight,
141
+ * scale-pop animation, larger fonts for small-screen viewing)
142
+ */
143
+ type CaptionStyle = 'shorts' | 'medium' | 'portrait';
144
+ interface ShortClipVariant {
145
+ path: string;
146
+ aspectRatio: AspectRatio;
147
+ platform: VideoPlatform;
148
+ width: number;
149
+ height: number;
150
+ }
151
+ /**
152
+ * A single time range within a short clip.
153
+ *
154
+ * Short clips can be **composite** — made of multiple non-contiguous segments
155
+ * from the original video, concatenated together. Each segment describes one
156
+ * contiguous range.
157
+ *
158
+ * @property start - Start time in the original video (seconds)
159
+ * @property end - End time in the original video (seconds)
160
+ * @property description - Human-readable description of what happens in this segment
161
+ */
162
+ interface ShortSegment {
163
+ start: number;
164
+ end: number;
165
+ description: string;
166
+ }
167
+ /**
168
+ * A planned short clip (15–60s) extracted from the full video.
169
+ *
170
+ * May be a single contiguous segment or a **composite** of multiple segments
171
+ * concatenated together (e.g. an intro + punchline from different parts of
172
+ * the video). The `segments` array defines the source time ranges; `totalDuration`
173
+ * is the sum of all segment durations.
174
+ *
175
+ * @property id - Unique identifier (e.g. "short-1")
176
+ * @property title - Human-readable title for the clip
177
+ * @property slug - Filesystem-safe slug (e.g. "typescript-tip-generics")
178
+ * @property segments - One or more time ranges from the original video
179
+ * @property totalDuration - Sum of all segment durations in seconds
180
+ * @property outputPath - Path to the extracted video file
181
+ * @property captionedPath - Path to the captioned version (if generated)
182
+ * @property description - Short description for social media
183
+ * @property tags - Hashtags / topic tags
184
+ * @property variants - Platform-specific aspect-ratio variants (portrait, square, etc.)
185
+ */
186
+ /** Hook pattern used to capture viewer attention in the first 1-3 seconds */
187
+ type HookType = 'cold-open' | 'curiosity-gap' | 'contradiction' | 'result-first' | 'bold-claim' | 'question';
188
+ /** Primary emotional trigger that drives engagement (shares, saves, comments) */
189
+ type EmotionalTrigger = 'awe' | 'humor' | 'surprise' | 'empathy' | 'outrage' | 'practical-value';
190
+ /** Narrative arc structure used in short clips */
191
+ type ShortNarrativeStructure = 'result-method-proof' | 'doing-x-wrong' | 'expectation-vs-reality' | 'mini-list' | 'tension-release' | 'loop';
192
+ interface ShortClip {
193
+ id: string;
194
+ title: string;
195
+ slug: string;
196
+ segments: ShortSegment[];
197
+ totalDuration: number;
198
+ outputPath: string;
199
+ captionedPath?: string;
200
+ description: string;
201
+ tags: string[];
202
+ hook?: string;
203
+ variants?: ShortClipVariant[];
204
+ /** Hook pattern classification — how the opening captures attention */
205
+ hookType?: HookType;
206
+ /** Primary emotional driver that makes this clip engaging */
207
+ emotionalTrigger?: EmotionalTrigger;
208
+ /** Viral potential score (1-20) based on hook strength, emotion, shareability, completion, replay */
209
+ viralScore?: number;
210
+ /** Narrative arc pattern used in this clip */
211
+ narrativeStructure?: ShortNarrativeStructure;
212
+ /** Why would someone share this with a friend? */
213
+ shareReason?: string;
214
+ /** Whether the content naturally loops back to the beginning */
215
+ isLoopCandidate?: boolean;
216
+ }
217
+ /** A planned medium clip segment */
218
+ interface MediumSegment {
219
+ start: number;
220
+ end: number;
221
+ description: string;
222
+ }
223
+ /** Narrative arc structure used in medium clips */
224
+ type MediumNarrativeStructure = 'open-loop-steps-payoff' | 'problem-deepdive-solution' | 'story-arc' | 'debate-comparison' | 'tutorial-micropayoffs';
225
+ /** Classification of medium clip content type */
226
+ type MediumClipType = 'deep-dive' | 'tutorial' | 'story-arc' | 'debate' | 'problem-solution';
227
+ interface MediumClip {
228
+ id: string;
229
+ title: string;
230
+ slug: string;
231
+ segments: MediumSegment[];
232
+ totalDuration: number;
233
+ outputPath: string;
234
+ captionedPath?: string;
235
+ description: string;
236
+ tags: string[];
237
+ hook: string;
238
+ topic: string;
239
+ /** Hook pattern classification — how the opening captures attention */
240
+ hookType?: HookType;
241
+ /** Primary emotional driver that makes this clip engaging */
242
+ emotionalTrigger?: EmotionalTrigger;
243
+ /** Viral potential score (1-20) based on hook strength, emotion, shareability, completion, replay */
244
+ viralScore?: number;
245
+ /** Narrative arc pattern used in this clip */
246
+ narrativeStructure?: MediumNarrativeStructure;
247
+ /** Content type classification */
248
+ clipType?: MediumClipType;
249
+ /** Why would someone save this to reference later? */
250
+ saveReason?: string;
251
+ /** Retention hooks planned at ~15-20 second intervals within the clip */
252
+ microHooks?: string[];
253
+ }
254
+ interface SocialPost {
255
+ platform: Platform;
256
+ content: string;
257
+ hashtags: string[];
258
+ links: string[];
259
+ characterCount: number;
260
+ outputPath: string;
261
+ }
262
+ /**
263
+ * A chapter marker for YouTube's chapters feature.
264
+ *
265
+ * @property timestamp - Start time in seconds (YouTube shows these as clickable markers)
266
+ * @property title - Short chapter title (shown in the progress bar)
267
+ * @property description - Longer description for the README/summary
268
+ */
269
+ interface Chapter {
270
+ timestamp: number;
271
+ title: string;
272
+ description: string;
273
+ }
274
+ interface VideoSnapshot {
275
+ timestamp: number;
276
+ description: string;
277
+ outputPath: string;
278
+ }
279
+ interface VideoSummary {
280
+ title: string;
281
+ overview: string;
282
+ keyTopics: string[];
283
+ snapshots: VideoSnapshot[];
284
+ markdownPath: string;
285
+ }
286
+ /** Placement region for an image overlay on video */
287
+ type OverlayRegion = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right' | 'center-right' | 'center-left';
288
+ /** Where on screen to place an overlay image */
289
+ interface OverlayPlacement {
290
+ region: OverlayRegion;
291
+ avoidAreas: string[];
292
+ sizePercent: number;
293
+ }
294
+ /** A moment in the video identified by Gemini as needing a visual aid */
295
+ interface EnhancementOpportunity {
296
+ timestampStart: number;
297
+ timestampEnd: number;
298
+ topic: string;
299
+ imagePrompt: string;
300
+ reason: string;
301
+ placement: OverlayPlacement;
302
+ confidence: number;
303
+ }
304
+ /** A generated image overlay ready for FFmpeg compositing */
305
+ interface GeneratedOverlay {
306
+ opportunity: EnhancementOpportunity;
307
+ imagePath: string;
308
+ width: number;
309
+ height: number;
310
+ }
311
+ /** Result of the visual enhancement stage */
312
+ interface VisualEnhancementResult {
313
+ enhancedVideoPath: string;
314
+ overlays: GeneratedOverlay[];
315
+ analysisTokens: number;
316
+ imageGenCost: number;
317
+ }
318
+ declare enum PipelineStage {
319
+ Ingestion = "ingestion",
320
+ Transcription = "transcription",
321
+ SilenceRemoval = "silence-removal",
322
+ VisualEnhancement = "visual-enhancement",
323
+ Chapters = "chapters",
324
+ Captions = "captions",
325
+ CaptionBurn = "caption-burn",
326
+ Summary = "summary",
327
+ Shorts = "shorts",
328
+ MediumClips = "medium-clips",
329
+ SocialMedia = "social-media",
330
+ ShortPosts = "short-posts",
331
+ MediumClipPosts = "medium-clip-posts",
332
+ Blog = "blog",
333
+ QueueBuild = "queue-build",
334
+ GitPush = "git-push"
335
+ }
336
+ /**
337
+ * Per-stage outcome record for pipeline observability.
338
+ *
339
+ * @property stage - Which pipeline stage this result is for
340
+ * @property success - Whether the stage completed without throwing
341
+ * @property error - Error message if the stage failed
342
+ * @property duration - Wall-clock time in milliseconds
343
+ */
344
+ interface StageResult {
345
+ stage: PipelineStage;
346
+ success: boolean;
347
+ error?: string;
348
+ duration: number;
349
+ }
350
+ /**
351
+ * Complete output of a pipeline run.
352
+ *
353
+ * Fields are optional because stages can fail independently — a failed
354
+ * transcription means no summary, but the video metadata is still available.
355
+ *
356
+ * @property totalDuration - Total pipeline wall-clock time in milliseconds
357
+ */
358
+ interface PipelineResult {
359
+ video: VideoFile;
360
+ transcript?: Transcript;
361
+ editedVideoPath?: string;
362
+ captions?: string[];
363
+ captionedVideoPath?: string;
364
+ enhancedVideoPath?: string;
365
+ summary?: VideoSummary;
366
+ chapters?: Chapter[];
367
+ shorts: ShortClip[];
368
+ mediumClips: MediumClip[];
369
+ socialPosts: SocialPost[];
370
+ blogPost?: string;
371
+ stageResults: StageResult[];
372
+ totalDuration: number;
373
+ }
374
+ /**
375
+ * Result of the silence removal stage.
376
+ *
377
+ * @property editedPath - Path to the video with silence regions cut out
378
+ * @property removals - Time ranges that were removed (in original video time).
379
+ * Used by {@link adjustTranscript} to shift transcript timestamps.
380
+ * @property keepSegments - Inverse of removals — the time ranges that were kept.
381
+ * Used by the single-pass caption burn to re-create the edit from the original.
382
+ * @property wasEdited - False if no silence was found and the video is unchanged
383
+ */
384
+ interface SilenceRemovalResult {
385
+ editedPath: string;
386
+ removals: {
387
+ start: number;
388
+ end: number;
389
+ }[];
390
+ keepSegments: {
391
+ start: number;
392
+ end: number;
393
+ }[];
394
+ wasEdited: boolean;
395
+ }
396
+ /**
397
+ * Standard result wrapper for all Copilot SDK agent calls.
398
+ *
399
+ * @property success - Whether the agent completed its task
400
+ * @property data - The parsed result (type varies by agent)
401
+ * @property error - Error message if the agent failed
402
+ * @property usage - Token counts for cost tracking
403
+ */
404
+ interface AgentResult<T = unknown> {
405
+ success: boolean;
406
+ data?: T;
407
+ error?: string;
408
+ usage?: {
409
+ promptTokens: number;
410
+ completionTokens: number;
411
+ };
412
+ }
413
+ /** Character limits per social media platform */
414
+ declare const PLATFORM_CHAR_LIMITS: Record<string, number>;
415
+ /**
416
+ * Maps vidpipe Platform enum values to Late API platform strings.
417
+ * Platform.X = 'x' but Late API expects 'twitter'.
418
+ */
419
+ declare function toLatePlatform(platform: Platform): string;
420
+ /**
421
+ * Maps a Late API platform string back to vidpipe Platform enum.
422
+ *
423
+ * Validates the input against known Platform values to avoid admitting
424
+ * unknown/unsupported platforms via an unchecked cast.
425
+ *
426
+ * @throws {Error} If the platform is not supported
427
+ */
428
+ declare function fromLatePlatform(latePlatform: string): Platform;
429
+ /**
430
+ * Normalizes raw platform strings (e.g., from user input or API responses)
431
+ * to Late API platform names. Handles X/Twitter variants and case-insensitivity.
432
+ *
433
+ * @example
434
+ * normalizePlatformString('X') // 'twitter'
435
+ * normalizePlatformString('x (twitter)') // 'twitter'
436
+ * normalizePlatformString('YouTube') // 'youtube'
437
+ */
438
+ declare function normalizePlatformString(raw: string): string;
439
+ /** Status lifecycle for content ideas */
440
+ type IdeaStatus = 'draft' | 'ready' | 'recorded' | 'published';
441
+ /**
442
+ * Record of a piece of content published from an idea.
443
+ * Appended to `Idea.publishedContent` when queue items are approved/published.
444
+ */
445
+ interface IdeaPublishRecord {
446
+ /** Content type that was published */
447
+ clipType: 'video' | 'short' | 'medium-clip';
448
+ /** Platform where content was published */
449
+ platform: Platform;
450
+ /** Links back to QueueItemMetadata.id */
451
+ queueItemId: string;
452
+ /** When the content was published (ISO 8601) */
453
+ publishedAt: string;
454
+ /** Late API post ID for tracking/managing the scheduled post */
455
+ latePostId: string;
456
+ /** Late API dashboard URL for viewing the post */
457
+ lateUrl: string;
458
+ /** Final published URL if available */
459
+ publishedUrl?: string;
460
+ }
461
+ /**
462
+ * A content idea generated by the IdeationAgent or created manually.
463
+ *
464
+ * Ideas flow through the pipeline: they are created during ideation,
465
+ * linked to recordings during processing, and tracked through publishing.
466
+ * The `status` field tracks the lifecycle: draft → ready → recorded → published.
467
+ */
468
+ interface Idea {
469
+ /** GitHub Issue number — the primary identifier */
470
+ issueNumber: number;
471
+ /** GitHub Issue URL (e.g., https://github.com/htekdev/content-management/issues/1) */
472
+ issueUrl: string;
473
+ /** Repository full name (e.g., htekdev/content-management) */
474
+ repoFullName: string;
475
+ /** Legacy slug ID for migration compatibility (e.g., "idea-copilot-debugging") */
476
+ id: string;
477
+ /** Main topic/title of the idea (= issue title) */
478
+ topic: string;
479
+ /** The attention-grabbing angle (≤80 chars) */
480
+ hook: string;
481
+ /** Who this content is for */
482
+ audience: string;
483
+ /** The one thing the viewer should remember */
484
+ keyTakeaway: string;
485
+ /** Bullet points to cover in the recording */
486
+ talkingPoints: string[];
487
+ /** Target platforms for this content (derived from platform:* labels) */
488
+ platforms: Platform[];
489
+ /** Lifecycle status (derived from status:* label) */
490
+ status: IdeaStatus;
491
+ /** Tags for categorization and matching (derived from freeform labels) */
492
+ tags: string[];
493
+ /** When the idea was created (from issue created_at) */
494
+ createdAt: string;
495
+ /** When the idea was last updated (from issue updated_at) */
496
+ updatedAt: string;
497
+ /** Deadline for publishing this idea's content (ISO 8601 date). Agent sets based on timeliness:
498
+ * - Hot trend: 3-5 days out
499
+ * - Timely event: 1-2 weeks out
500
+ * - Evergreen: 3-6 months out */
501
+ publishBy: string;
502
+ /** Video slug linked after recording — parsed from video-link issue comments */
503
+ sourceVideoSlug?: string;
504
+ /** Why this is timely — context from trend research */
505
+ trendContext?: string;
506
+ /** Tracks every piece of content published for this idea — parsed from issue comments */
507
+ publishedContent?: IdeaPublishRecord[];
508
+ }
509
+ /** Input for creating a new idea — omits fields derived from GitHub Issue metadata */
510
+ interface CreateIdeaInput {
511
+ /** Main topic/title (becomes issue title) */
512
+ topic: string;
513
+ /** The attention-grabbing angle (≤80 chars) */
514
+ hook: string;
515
+ /** Who this content is for */
516
+ audience: string;
517
+ /** The one thing the viewer should remember */
518
+ keyTakeaway: string;
519
+ /** Bullet points to cover in the recording */
520
+ talkingPoints: string[];
521
+ /** Target platforms for this content */
522
+ platforms: Platform[];
523
+ /** Tags for categorization and matching */
524
+ tags: string[];
525
+ /** Deadline for publishing (ISO 8601 date) */
526
+ publishBy: string;
527
+ /** Why this is timely — context from trend research */
528
+ trendContext?: string;
529
+ }
530
+ /** Filters for querying ideas from GitHub Issues */
531
+ interface IdeaFilters {
532
+ /** Filter by lifecycle status */
533
+ status?: IdeaStatus;
534
+ /** Filter by target platform */
535
+ platform?: Platform;
536
+ /** Filter by tag label */
537
+ tag?: string;
538
+ /** Filter by priority label */
539
+ priority?: 'hot-trend' | 'timely' | 'evergreen';
540
+ /** Maximum number of results */
541
+ limit?: number;
542
+ }
543
+ /** Discriminated type for structured issue comments */
544
+ type IdeaCommentData = {
545
+ type: 'publish-record';
546
+ record: IdeaPublishRecord;
547
+ } | {
548
+ type: 'video-link';
549
+ videoSlug: string;
550
+ linkedAt: string;
551
+ };
552
+ /** Schedule time slot for a platform */
553
+ interface ScheduleSlot {
554
+ platform: string;
555
+ scheduledFor: string;
556
+ postId?: string;
557
+ itemId?: string;
558
+ label?: string;
559
+ }
560
+ /** File extensions accepted as pipeline input. */
561
+ declare const SUPPORTED_VIDEO_EXTENSIONS: readonly [".mp4", ".webm"];
562
+
563
+ interface AppEnvironment {
564
+ OPENAI_API_KEY: string;
565
+ WATCH_FOLDER: string;
566
+ REPO_ROOT: string;
567
+ FFMPEG_PATH: string;
568
+ FFPROBE_PATH: string;
569
+ EXA_API_KEY: string;
570
+ EXA_MCP_URL: string;
571
+ YOUTUBE_API_KEY: string;
572
+ PERPLEXITY_API_KEY: string;
573
+ LLM_PROVIDER: string;
574
+ LLM_MODEL: string;
575
+ ANTHROPIC_API_KEY: string;
576
+ OUTPUT_DIR: string;
577
+ BRAND_PATH: string;
578
+ VERBOSE: boolean;
579
+ SKIP_GIT: boolean;
580
+ SKIP_SILENCE_REMOVAL: boolean;
581
+ SKIP_SHORTS: boolean;
582
+ SKIP_MEDIUM_CLIPS: boolean;
583
+ SKIP_SOCIAL: boolean;
584
+ SKIP_CAPTIONS: boolean;
585
+ SKIP_VISUAL_ENHANCEMENT: boolean;
586
+ LATE_API_KEY: string;
587
+ LATE_PROFILE_ID: string;
588
+ SKIP_SOCIAL_PUBLISH: boolean;
589
+ GEMINI_API_KEY: string;
590
+ GEMINI_MODEL: string;
591
+ /** GitHub repository for idea tracking (format: owner/repo) */
592
+ IDEAS_REPO: string;
593
+ /** GitHub Personal Access Token with repo + project scopes */
594
+ GITHUB_TOKEN: string;
595
+ }
596
+
597
+ interface GlobalCredentials {
598
+ openaiApiKey?: string;
599
+ anthropicApiKey?: string;
600
+ exaApiKey?: string;
601
+ youtubeApiKey?: string;
602
+ perplexityApiKey?: string;
603
+ lateApiKey?: string;
604
+ githubToken?: string;
605
+ geminiApiKey?: string;
606
+ }
607
+ interface GlobalDefaults {
608
+ llmProvider?: string;
609
+ llmModel?: string;
610
+ outputDir?: string;
611
+ watchFolder?: string;
612
+ brandPath?: string;
613
+ ideasRepo?: string;
614
+ lateProfileId?: string;
615
+ geminiModel?: string;
616
+ }
617
+ interface GlobalConfig {
618
+ credentials: GlobalCredentials;
619
+ defaults: GlobalDefaults;
620
+ }
621
+
622
+ type DayOfWeek = 'mon' | 'tue' | 'wed' | 'thu' | 'fri' | 'sat' | 'sun';
623
+ interface TimeSlot {
624
+ days: DayOfWeek[];
625
+ time: string;
626
+ label: string;
627
+ }
628
+ interface ClipTypeSchedule {
629
+ slots: TimeSlot[];
630
+ avoidDays: DayOfWeek[];
631
+ }
632
+ interface PlatformSchedule {
633
+ slots: TimeSlot[];
634
+ avoidDays: DayOfWeek[];
635
+ byClipType?: Record<string, ClipTypeSchedule>;
636
+ }
637
+ interface IdeaSpacingConfig {
638
+ samePlatformHours: number;
639
+ crossPlatformHours: number;
640
+ }
641
+ interface DisplacementConfig {
642
+ enabled: boolean;
643
+ canDisplace: 'non-idea-only';
644
+ }
645
+ interface ScheduleConfig {
646
+ timezone: string;
647
+ platforms: Record<string, PlatformSchedule>;
648
+ ideaSpacing?: IdeaSpacingConfig;
649
+ displacement?: DisplacementConfig;
650
+ }
651
+
652
+ /**
653
+ * Configuration options for the VidPipe SDK factory.
654
+ *
655
+ * All properties are optional so the SDK can be created with zero configuration.
656
+ */
657
+ interface VidPipeConfig {
658
+ openaiApiKey?: string;
659
+ anthropicApiKey?: string;
660
+ exaApiKey?: string;
661
+ youtubeApiKey?: string;
662
+ perplexityApiKey?: string;
663
+ lateApiKey?: string;
664
+ lateProfileId?: string;
665
+ githubToken?: string;
666
+ geminiApiKey?: string;
667
+ llmProvider?: 'copilot' | 'openai' | 'claude';
668
+ llmModel?: string;
669
+ outputDir?: string;
670
+ watchFolder?: string;
671
+ brandPath?: string;
672
+ repoRoot?: string;
673
+ verbose?: boolean;
674
+ ideasRepo?: string;
675
+ geminiModel?: string;
676
+ }
677
+ /**
678
+ * Options for processing a video through the VidPipe pipeline.
679
+ */
680
+ interface ProcessOptions {
681
+ /** Comma-separated idea issue numbers to link to this video */
682
+ ideas?: number[];
683
+ /** Skip specific pipeline stages */
684
+ skipGit?: boolean;
685
+ /** Skip the silence removal stage */
686
+ skipSilenceRemoval?: boolean;
687
+ /** Skip short clip generation */
688
+ skipShorts?: boolean;
689
+ /** Skip medium clip generation */
690
+ skipMediumClips?: boolean;
691
+ /** Skip social content generation */
692
+ skipSocial?: boolean;
693
+ /** Skip caption generation and caption burn steps */
694
+ skipCaptions?: boolean;
695
+ /** Skip visual enhancement processing */
696
+ skipVisualEnhancement?: boolean;
697
+ /** Skip publishing generated social content */
698
+ skipSocialPublish?: boolean;
699
+ }
700
+ /**
701
+ * Options for AI-assisted idea generation.
702
+ */
703
+ interface IdeateOptions {
704
+ /** Seed topics for idea generation */
705
+ topics?: string[];
706
+ /** Number of ideas to generate */
707
+ count?: number;
708
+ /** Path to brand.json config */
709
+ brandPath?: string;
710
+ /** When true, allows count=1 (bypasses minimum idea count). Used for single-topic idea creation. */
711
+ singleTopic?: boolean;
712
+ }
713
+ /**
714
+ * Options for finding the next scheduling slot.
715
+ */
716
+ interface SlotOptions {
717
+ /** Idea issue numbers for spacing rules */
718
+ ideaIds?: number[];
719
+ /** Urgency deadline (ISO 8601 date) */
720
+ publishBy?: string;
721
+ }
722
+ /**
723
+ * Options for schedule realignment.
724
+ */
725
+ interface RealignOptions {
726
+ /** Filter to specific platform */
727
+ platform?: string;
728
+ /** Preview only, don't execute */
729
+ dryRun?: boolean;
730
+ }
731
+ /**
732
+ * A single diagnostic check returned by the SDK doctor command.
733
+ */
734
+ interface DiagnosticCheck {
735
+ name: string;
736
+ status: 'pass' | 'fail' | 'warn';
737
+ message: string;
738
+ details?: string;
739
+ }
740
+ /**
741
+ * Aggregate result returned by the SDK doctor command.
742
+ */
743
+ interface DiagnosticResult {
744
+ checks: DiagnosticCheck[];
745
+ allPassed: boolean;
746
+ }
747
+ /**
748
+ * Union of clip result types produced by VidPipe.
749
+ */
750
+ type GeneratedClip = ShortClip | MediumClip;
751
+ /**
752
+ * Main VidPipe SDK interface.
753
+ */
754
+ interface VidPipeSDK {
755
+ /** Run the full video processing pipeline */
756
+ processVideo(videoPath: string, options?: ProcessOptions): Promise<PipelineResult>;
757
+ /** Generate AI-powered content ideas */
758
+ ideate(options?: IdeateOptions): Promise<Idea[]>;
759
+ /** Idea management */
760
+ ideas: {
761
+ list(filters?: IdeaFilters): Promise<Idea[]>;
762
+ get(issueNumber: number): Promise<Idea | null>;
763
+ create(input: CreateIdeaInput): Promise<Idea>;
764
+ update(issueNumber: number, updates: Partial<CreateIdeaInput>): Promise<Idea>;
765
+ };
766
+ /** Schedule management */
767
+ schedule: {
768
+ findNextSlot(platform: string, clipType?: string, options?: SlotOptions): Promise<string | null>;
769
+ getCalendar(startDate?: Date, endDate?: Date): Promise<ScheduleSlot[]>;
770
+ realign(options?: RealignOptions): Promise<{
771
+ moved: number;
772
+ skipped: number;
773
+ }>;
774
+ loadConfig(): Promise<ScheduleConfig>;
775
+ };
776
+ /** Video operations */
777
+ video: {
778
+ extractClip(videoPath: string, start: number, end: number, output: string): Promise<string>;
779
+ burnCaptions(videoPath: string, captionsFile: string, output: string): Promise<string>;
780
+ detectSilence(videoPath: string, options?: {
781
+ threshold?: string;
782
+ minDuration?: number;
783
+ }): Promise<Array<{
784
+ start: number;
785
+ end: number;
786
+ }>>;
787
+ generateVariants(videoPath: string, platforms: Platform[], outputDir: string): Promise<Array<{
788
+ platform: Platform;
789
+ path: string;
790
+ }>>;
791
+ captureFrame(videoPath: string, timestamp: number, output: string): Promise<string>;
792
+ };
793
+ /** Social media operations */
794
+ social: {
795
+ generatePosts(context: {
796
+ title: string;
797
+ description: string;
798
+ tags: string[];
799
+ }, platforms: Platform[]): Promise<SocialPost[]>;
800
+ };
801
+ /** Run diagnostic checks */
802
+ doctor(): Promise<DiagnosticResult>;
803
+ /** Configuration access */
804
+ config: {
805
+ get(key: string): string | boolean | undefined;
806
+ getAll(): AppEnvironment;
807
+ getGlobal(): GlobalConfig;
808
+ set(key: string, value: string | boolean): void;
809
+ save(): Promise<void>;
810
+ path(): string;
811
+ };
812
+ }
813
+
814
+ declare function createVidPipe(sdkConfig?: VidPipeConfig): VidPipeSDK;
815
+
816
+ export { type AgentResult, type AspectRatio, type CaptionStyle, type Chapter, type CreateIdeaInput, type DiagnosticCheck, type DiagnosticResult, type EmotionalTrigger, type EnhancementOpportunity, type GeneratedClip, type GeneratedOverlay, type HookType, type Idea, type IdeaCommentData, type IdeaFilters, type IdeaPublishRecord, type IdeaStatus, type IdeateOptions, type MediumClip, type MediumClipType, type MediumNarrativeStructure, type MediumSegment, type OverlayPlacement, type OverlayRegion, PLATFORM_CHAR_LIMITS, type PipelineResult, PipelineStage, Platform, type ProcessOptions, 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 StageResult, 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 };