@agimon-ai/video-editor-mcp 0.7.0 → 0.8.2
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.
- package/README.md +117 -5
- package/dist/cli.cjs +9 -4
- package/dist/cli.mjs +9 -4
- package/dist/index.cjs +1 -2
- package/dist/index.mjs +1 -2
- package/dist/stdio-CH0Bk0m7.cjs +17 -0
- package/dist/stdio-KMqWPqUm.mjs +17 -0
- package/package.json +12 -4
- package/schemas/main-composition.schema.json +2283 -0
- package/src/remotion/Root.tsx +87 -0
- package/src/remotion/compositions/Main.tsx +51 -0
- package/src/remotion/compositions/Square.tsx +18 -0
- package/src/remotion/compositions/Vertical.tsx +18 -0
- package/src/remotion/compositions/audio/AudioLayer.tsx +130 -0
- package/src/remotion/compositions/captions/CaptionOverlay.tsx +250 -0
- package/src/remotion/compositions/captions/index.ts +1 -0
- package/src/remotion/compositions/clips/AudioClipRenderer.tsx +66 -0
- package/src/remotion/compositions/clips/GifClipRenderer.tsx +71 -0
- package/src/remotion/compositions/clips/ImageClipRenderer.tsx +103 -0
- package/src/remotion/compositions/clips/LottieClipRenderer.tsx +57 -0
- package/src/remotion/compositions/clips/SubtitleClipRenderer.tsx +85 -0
- package/src/remotion/compositions/clips/TextClipRenderer.tsx +131 -0
- package/src/remotion/compositions/clips/VideoClipRenderer.tsx +94 -0
- package/src/remotion/compositions/clips/index.tsx +51 -0
- package/src/remotion/index.ts +10 -0
- package/src/remotion/utils/calculateMainMetadata.ts +76 -0
- package/src/schemas/clips.ts +202 -0
- package/src/schemas/compositions.ts +160 -0
- package/src/schemas/index.ts +19 -0
- package/src/utils/assetPaths.ts +64 -0
- package/src/utils/index.ts +9 -0
- package/dist/cli.cjs.map +0 -1
- package/dist/cli.mjs.map +0 -1
- package/dist/index.cjs.map +0 -1
- package/dist/index.mjs.map +0 -1
- package/dist/stdio-B6Hg5voC.mjs +0 -4
- package/dist/stdio-B6Hg5voC.mjs.map +0 -1
- package/dist/stdio-Dwc6SWvA.cjs +0 -4
- package/dist/stdio-Dwc6SWvA.cjs.map +0 -1
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
export const NumberLikeSchema = z.coerce.number();
|
|
4
|
+
export const IntLikeSchema = z.coerce.number().int();
|
|
5
|
+
export const BooleanLikeSchema = z.preprocess((value) => {
|
|
6
|
+
if (typeof value !== 'string') {
|
|
7
|
+
return value;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const normalized = value.trim().toLowerCase();
|
|
11
|
+
if (normalized === 'true') {
|
|
12
|
+
return true;
|
|
13
|
+
}
|
|
14
|
+
if (normalized === 'false') {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return value;
|
|
19
|
+
}, z.boolean());
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Media `src` validator. Accepts absolute filesystem paths (so the MCP can
|
|
23
|
+
* remap them into its publicDir), `file://` URLs, remote `http(s):` URLs,
|
|
24
|
+
* `data:` URIs, and `blob:` URLs. Rejects bare relative paths because they
|
|
25
|
+
* silently resolve against the MCP's publicDir at render time and fail with
|
|
26
|
+
* `asset.missing`.
|
|
27
|
+
*/
|
|
28
|
+
export const MediaSrcSchema = z
|
|
29
|
+
.string()
|
|
30
|
+
.min(1)
|
|
31
|
+
.refine((value) => /^(\/|file:|https?:|data:|blob:)/i.test(value), {
|
|
32
|
+
message:
|
|
33
|
+
'src must be an absolute filesystem path or a file:// / http(s):// / data: / blob: URL — relative paths are not allowed.',
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
export const VolumeAutomationPointSchema = z.object({
|
|
37
|
+
frame: IntLikeSchema.nonnegative(),
|
|
38
|
+
volume: NumberLikeSchema.min(0).max(1),
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Animation configuration for clip entrance/exit effects
|
|
43
|
+
*/
|
|
44
|
+
export const AnimationConfigSchema = z.object({
|
|
45
|
+
type: z.enum(['interpolate', 'spring']).default('interpolate'),
|
|
46
|
+
easing: z.enum(['linear', 'ease-in', 'ease-out', 'ease-in-out']).optional(),
|
|
47
|
+
springConfig: z
|
|
48
|
+
.object({
|
|
49
|
+
mass: NumberLikeSchema.positive().default(1),
|
|
50
|
+
damping: NumberLikeSchema.positive().default(10),
|
|
51
|
+
stiffness: NumberLikeSchema.positive().default(100),
|
|
52
|
+
})
|
|
53
|
+
.optional(),
|
|
54
|
+
delay: IntLikeSchema.nonnegative().default(0),
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Transition configuration between clips
|
|
59
|
+
*/
|
|
60
|
+
export const TransitionConfigSchema = z.object({
|
|
61
|
+
type: z.enum(['fade', 'slide', 'wipe', 'flip', 'clockWipe', 'none']).default('fade'),
|
|
62
|
+
durationInFrames: IntLikeSchema.positive().default(15),
|
|
63
|
+
direction: z.enum(['from-left', 'from-right', 'from-top', 'from-bottom']).optional(),
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Base clip fields shared across all clip types
|
|
68
|
+
*/
|
|
69
|
+
const BaseClipFields = {
|
|
70
|
+
startFrame: IntLikeSchema.nonnegative(),
|
|
71
|
+
durationInFrames: IntLikeSchema.positive(),
|
|
72
|
+
premountFor: IntLikeSchema.nonnegative().default(30),
|
|
73
|
+
entrance: AnimationConfigSchema.optional(),
|
|
74
|
+
exit: AnimationConfigSchema.optional(),
|
|
75
|
+
transition: TransitionConfigSchema.optional(),
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Video clip — renders with OffthreadVideo
|
|
80
|
+
*/
|
|
81
|
+
export const VideoClipSchema = z.object({
|
|
82
|
+
type: z.literal('video'),
|
|
83
|
+
...BaseClipFields,
|
|
84
|
+
src: MediaSrcSchema,
|
|
85
|
+
volume: NumberLikeSchema.min(0).max(1).optional(),
|
|
86
|
+
playbackRate: NumberLikeSchema.positive().optional(),
|
|
87
|
+
muted: BooleanLikeSchema.optional(),
|
|
88
|
+
loop: BooleanLikeSchema.optional(),
|
|
89
|
+
trimBefore: NumberLikeSchema.nonnegative().optional(),
|
|
90
|
+
trimAfter: NumberLikeSchema.nonnegative().optional(),
|
|
91
|
+
transparent: BooleanLikeSchema.optional(),
|
|
92
|
+
noFadeIn: BooleanLikeSchema.optional(),
|
|
93
|
+
style: z.record(z.string(), z.unknown()).optional(),
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Image clip — renders with Img
|
|
98
|
+
*/
|
|
99
|
+
export const ImageClipSchema = z.object({
|
|
100
|
+
type: z.literal('image'),
|
|
101
|
+
...BaseClipFields,
|
|
102
|
+
src: MediaSrcSchema,
|
|
103
|
+
fit: z.enum(['contain', 'cover', 'fill']).optional(),
|
|
104
|
+
noFadeIn: BooleanLikeSchema.optional(),
|
|
105
|
+
baseScale: NumberLikeSchema.positive().optional(),
|
|
106
|
+
transformOriginX: z.string().optional(),
|
|
107
|
+
transformOriginY: z.string().optional(),
|
|
108
|
+
style: z.record(z.string(), z.unknown()).optional(),
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Text clip — animated text with multiple animation types
|
|
113
|
+
*/
|
|
114
|
+
export const TextClipSchema = z.object({
|
|
115
|
+
type: z.literal('text'),
|
|
116
|
+
...BaseClipFields,
|
|
117
|
+
text: z.string(),
|
|
118
|
+
fontSize: NumberLikeSchema.positive().default(80),
|
|
119
|
+
fontFamily: z.string().default('sans-serif'),
|
|
120
|
+
fontWeight: z.union([z.string(), NumberLikeSchema]).optional(),
|
|
121
|
+
color: z.string().default('#ffffff'),
|
|
122
|
+
backgroundColor: z.string().optional(),
|
|
123
|
+
position: z.enum(['top', 'center', 'bottom']).default('center'),
|
|
124
|
+
animation: z.enum(['none', 'fade', 'slide', 'typewriter', 'highlight']).default('none'),
|
|
125
|
+
highlightColor: z.string().optional(),
|
|
126
|
+
highlightWord: z.string().optional(),
|
|
127
|
+
style: z.record(z.string(), z.unknown()).optional(),
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Audio clip — renders with Audio component
|
|
132
|
+
*/
|
|
133
|
+
export const AudioClipSchema = z.object({
|
|
134
|
+
type: z.literal('audio'),
|
|
135
|
+
...BaseClipFields,
|
|
136
|
+
src: MediaSrcSchema,
|
|
137
|
+
volume: NumberLikeSchema.min(0).max(1).optional(),
|
|
138
|
+
volumeAutomation: z.array(VolumeAutomationPointSchema).optional(),
|
|
139
|
+
playbackRate: NumberLikeSchema.positive().optional(),
|
|
140
|
+
muted: BooleanLikeSchema.optional(),
|
|
141
|
+
loop: BooleanLikeSchema.optional(),
|
|
142
|
+
trimBefore: NumberLikeSchema.nonnegative().optional(),
|
|
143
|
+
trimAfter: NumberLikeSchema.nonnegative().optional(),
|
|
144
|
+
toneFrequency: NumberLikeSchema.positive().optional(),
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Subtitle clip — animated subtitle overlay
|
|
149
|
+
*/
|
|
150
|
+
export const SubtitleClipSchema = z.object({
|
|
151
|
+
type: z.literal('subtitle'),
|
|
152
|
+
...BaseClipFields,
|
|
153
|
+
text: z.string(),
|
|
154
|
+
position: z.enum(['top', 'center', 'bottom']).default('bottom'),
|
|
155
|
+
animation: z.enum(['none', 'fade', 'slide']).default('fade'),
|
|
156
|
+
fontSize: NumberLikeSchema.positive().default(36),
|
|
157
|
+
fontFamily: z.string().default('Arial, sans-serif'),
|
|
158
|
+
color: z.string().default('#ffffff'),
|
|
159
|
+
backgroundColor: z.string().default('rgba(0, 0, 0, 0.7)'),
|
|
160
|
+
style: z.record(z.string(), z.unknown()).optional(),
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* GIF clip — renders with Gif component
|
|
165
|
+
*/
|
|
166
|
+
export const GifClipSchema = z.object({
|
|
167
|
+
type: z.literal('gif'),
|
|
168
|
+
...BaseClipFields,
|
|
169
|
+
src: MediaSrcSchema,
|
|
170
|
+
width: NumberLikeSchema.positive().optional(),
|
|
171
|
+
height: NumberLikeSchema.positive().optional(),
|
|
172
|
+
fit: z.enum(['contain', 'cover', 'fill']).optional(),
|
|
173
|
+
playbackRate: NumberLikeSchema.positive().optional(),
|
|
174
|
+
loopBehavior: z.enum(['loop', 'pause-after-finish']).optional(),
|
|
175
|
+
style: z.record(z.string(), z.unknown()).optional(),
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Lottie clip — renders Lottie JSON animations
|
|
180
|
+
*/
|
|
181
|
+
export const LottieClipSchema = z.object({
|
|
182
|
+
type: z.literal('lottie'),
|
|
183
|
+
...BaseClipFields,
|
|
184
|
+
src: MediaSrcSchema,
|
|
185
|
+
width: NumberLikeSchema.positive().optional(),
|
|
186
|
+
height: NumberLikeSchema.positive().optional(),
|
|
187
|
+
loop: BooleanLikeSchema.optional(),
|
|
188
|
+
style: z.record(z.string(), z.unknown()).optional(),
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Discriminated union of all clip types
|
|
193
|
+
*/
|
|
194
|
+
export const ClipSchema = z.discriminatedUnion('type', [
|
|
195
|
+
VideoClipSchema,
|
|
196
|
+
ImageClipSchema,
|
|
197
|
+
TextClipSchema,
|
|
198
|
+
AudioClipSchema,
|
|
199
|
+
SubtitleClipSchema,
|
|
200
|
+
GifClipSchema,
|
|
201
|
+
LottieClipSchema,
|
|
202
|
+
]);
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import {
|
|
3
|
+
BooleanLikeSchema,
|
|
4
|
+
ClipSchema,
|
|
5
|
+
IntLikeSchema,
|
|
6
|
+
MediaSrcSchema,
|
|
7
|
+
NumberLikeSchema,
|
|
8
|
+
TransitionConfigSchema,
|
|
9
|
+
} from './clips.js';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Individual caption entry (word or segment level)
|
|
13
|
+
*/
|
|
14
|
+
export const CaptionSchema = z.object({
|
|
15
|
+
text: z.string(),
|
|
16
|
+
startMs: NumberLikeSchema.nonnegative(),
|
|
17
|
+
endMs: NumberLikeSchema.nonnegative(),
|
|
18
|
+
timestampMs: NumberLikeSchema.nonnegative().optional(),
|
|
19
|
+
confidence: NumberLikeSchema.min(0).max(1).optional(),
|
|
20
|
+
emphasis: z.enum(['none', 'keyword', 'stat', 'negation', 'cta']).optional(),
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
export const CaptionTokenSchema = CaptionSchema.extend({
|
|
24
|
+
emphasis: z.enum(['none', 'keyword', 'stat', 'negation', 'cta']).default('none'),
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
export const CaptionPlacementSchema = z.object({
|
|
28
|
+
x: NumberLikeSchema.min(0).max(1).optional(),
|
|
29
|
+
y: NumberLikeSchema.min(0).max(1).optional(),
|
|
30
|
+
position: z.enum(['top', 'center', 'bottom']).optional(),
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
export const CaptionPageSchema = z.object({
|
|
34
|
+
text: z.string().optional(),
|
|
35
|
+
startMs: NumberLikeSchema.nonnegative(),
|
|
36
|
+
endMs: NumberLikeSchema.nonnegative(),
|
|
37
|
+
tokens: z.array(CaptionTokenSchema).min(1),
|
|
38
|
+
placement: CaptionPlacementSchema.optional(),
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
export const CaptionSafeZoneSchema = z.object({
|
|
42
|
+
top: NumberLikeSchema.nonnegative().optional(),
|
|
43
|
+
right: NumberLikeSchema.nonnegative().optional(),
|
|
44
|
+
bottom: NumberLikeSchema.nonnegative().optional(),
|
|
45
|
+
left: NumberLikeSchema.nonnegative().optional(),
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
export const CaptionShadowSchema = z.object({
|
|
49
|
+
color: z.string().default('rgba(0, 0, 0, 0.85)'),
|
|
50
|
+
blur: NumberLikeSchema.nonnegative().default(8),
|
|
51
|
+
offsetX: NumberLikeSchema.default(0),
|
|
52
|
+
offsetY: NumberLikeSchema.default(3),
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Caption overlay configuration for TikTok-style captions
|
|
57
|
+
*/
|
|
58
|
+
export const CaptionConfigSchema = z
|
|
59
|
+
.object({
|
|
60
|
+
captions: z.array(CaptionSchema).default([]),
|
|
61
|
+
pages: z.array(CaptionPageSchema).optional(),
|
|
62
|
+
style: z.enum(['tiktok', 'standard', 'karaoke']).default('tiktok'),
|
|
63
|
+
preset: z.enum(['tiktok-bold', 'karaoke', 'premium-pill', 'minimal', 'ugc']).default('tiktok-bold'),
|
|
64
|
+
platform: z.enum(['tiktok', 'reels', 'shorts', 'universal']).default('tiktok'),
|
|
65
|
+
combineTokensWithinMilliseconds: NumberLikeSchema.nonnegative().default(800),
|
|
66
|
+
maxWordsPerPage: IntLikeSchema.positive().default(6),
|
|
67
|
+
maxCharsPerLine: IntLikeSchema.positive().default(22),
|
|
68
|
+
maxLines: IntLikeSchema.positive().default(2),
|
|
69
|
+
maxWidthPct: NumberLikeSchema.positive().max(1).default(0.86),
|
|
70
|
+
fontSize: NumberLikeSchema.positive().default(60),
|
|
71
|
+
minFontSize: NumberLikeSchema.positive().default(42),
|
|
72
|
+
fontFamily: z.string().default('Arial, sans-serif'),
|
|
73
|
+
fontWeight: z.union([IntLikeSchema.positive(), z.string()]).default(800),
|
|
74
|
+
lineHeight: NumberLikeSchema.positive().default(1.08),
|
|
75
|
+
color: z.string().default('#ffffff'),
|
|
76
|
+
inactiveColor: z.string().default('#ffffff'),
|
|
77
|
+
highlightColor: z.string().default('#FFD700'),
|
|
78
|
+
textColor: z.string().default('#ffffff'),
|
|
79
|
+
strokeColor: z.string().default('#000000'),
|
|
80
|
+
strokeWidth: NumberLikeSchema.nonnegative().default(5),
|
|
81
|
+
shadow: z.union([BooleanLikeSchema, CaptionShadowSchema]).default(true),
|
|
82
|
+
backgroundColor: z.string().default('rgba(0, 0, 0, 0)'),
|
|
83
|
+
backgroundRadius: NumberLikeSchema.nonnegative().default(8),
|
|
84
|
+
safeZone: CaptionSafeZoneSchema.optional(),
|
|
85
|
+
position: z.enum(['top', 'center', 'bottom']).default('bottom'),
|
|
86
|
+
})
|
|
87
|
+
.superRefine((config, ctx) => {
|
|
88
|
+
if (config.captions.length === 0 && (!config.pages || config.pages.length === 0)) {
|
|
89
|
+
ctx.addIssue({
|
|
90
|
+
code: 'custom',
|
|
91
|
+
message: 'Caption config must include captions or pages.',
|
|
92
|
+
path: ['captions'],
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Shared base for audio-layer tracks. Distinct from clip-level audio: layer
|
|
99
|
+
* tracks span the timeline (or sit at a single point in time for sfx) and do
|
|
100
|
+
* not need explicit frame math from the caller.
|
|
101
|
+
*/
|
|
102
|
+
const AudioTrackBaseShape = {
|
|
103
|
+
src: MediaSrcSchema,
|
|
104
|
+
volume: NumberLikeSchema.min(0).max(1).default(1),
|
|
105
|
+
fadeInMs: NumberLikeSchema.nonnegative().default(0),
|
|
106
|
+
fadeOutMs: NumberLikeSchema.nonnegative().default(0),
|
|
107
|
+
trimBeforeMs: NumberLikeSchema.nonnegative().default(0),
|
|
108
|
+
trimAfterMs: NumberLikeSchema.nonnegative().optional(),
|
|
109
|
+
playbackRate: NumberLikeSchema.positive().default(1),
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
export const VoiceoverTrackSchema = z.object({
|
|
113
|
+
...AudioTrackBaseShape,
|
|
114
|
+
definesTimeline: BooleanLikeSchema.default(true),
|
|
115
|
+
durationMs: NumberLikeSchema.positive().optional(),
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
export const MusicTrackSchema = z.object({
|
|
119
|
+
...AudioTrackBaseShape,
|
|
120
|
+
loop: BooleanLikeSchema.default(true),
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
export const SfxEntrySchema = z.object({
|
|
124
|
+
...AudioTrackBaseShape,
|
|
125
|
+
atMs: NumberLikeSchema.nonnegative(),
|
|
126
|
+
durationMs: NumberLikeSchema.positive().optional(),
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
export const AudioLayerSchema = z.object({
|
|
130
|
+
voiceover: VoiceoverTrackSchema.optional(),
|
|
131
|
+
music: MusicTrackSchema.optional(),
|
|
132
|
+
sfx: z.array(SfxEntrySchema).default([]),
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Font loading configuration
|
|
137
|
+
*/
|
|
138
|
+
export const FontConfigSchema = z.object({
|
|
139
|
+
family: z.string(),
|
|
140
|
+
source: z.enum(['google', 'local']).default('google'),
|
|
141
|
+
weights: z.array(IntLikeSchema.positive()).optional(),
|
|
142
|
+
url: z.string().optional(),
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Main composition props schema
|
|
147
|
+
*/
|
|
148
|
+
export const MainCompositionSchema = z
|
|
149
|
+
.object({
|
|
150
|
+
clips: z.array(ClipSchema).default([]),
|
|
151
|
+
backgroundColor: z.string().default('#000000'),
|
|
152
|
+
fps: IntLikeSchema.positive().default(30),
|
|
153
|
+
width: IntLikeSchema.positive().default(1920),
|
|
154
|
+
height: IntLikeSchema.positive().default(1080),
|
|
155
|
+
captions: CaptionConfigSchema.optional(),
|
|
156
|
+
globalTransition: TransitionConfigSchema.optional(),
|
|
157
|
+
fonts: z.array(FontConfigSchema).optional(),
|
|
158
|
+
audio: AudioLayerSchema.optional(),
|
|
159
|
+
})
|
|
160
|
+
.passthrough();
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export {
|
|
2
|
+
AnimationConfigSchema,
|
|
3
|
+
AudioClipSchema,
|
|
4
|
+
ClipSchema,
|
|
5
|
+
GifClipSchema,
|
|
6
|
+
ImageClipSchema,
|
|
7
|
+
LottieClipSchema,
|
|
8
|
+
SubtitleClipSchema,
|
|
9
|
+
TextClipSchema,
|
|
10
|
+
TransitionConfigSchema,
|
|
11
|
+
VideoClipSchema,
|
|
12
|
+
} from './clips.js';
|
|
13
|
+
|
|
14
|
+
export {
|
|
15
|
+
CaptionConfigSchema,
|
|
16
|
+
CaptionSchema,
|
|
17
|
+
FontConfigSchema,
|
|
18
|
+
MainCompositionSchema,
|
|
19
|
+
} from './compositions.js';
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* assetPaths Utilities
|
|
3
|
+
*
|
|
4
|
+
* DESIGN PATTERNS:
|
|
5
|
+
* - Pure functions with no side effects
|
|
6
|
+
* - Single responsibility per function
|
|
7
|
+
* - Functional programming approach
|
|
8
|
+
*
|
|
9
|
+
* CODING STANDARDS:
|
|
10
|
+
* - Export individual functions, not classes
|
|
11
|
+
* - Use descriptive function names with verbs
|
|
12
|
+
* - Add JSDoc comments for complex logic
|
|
13
|
+
* - Keep functions small and focused
|
|
14
|
+
*
|
|
15
|
+
* AVOID:
|
|
16
|
+
* - Side effects (mutating external state)
|
|
17
|
+
* - Stateful logic (use services for state)
|
|
18
|
+
* - External dependencies (keep utilities pure)
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import { staticFile } from 'remotion';
|
|
22
|
+
|
|
23
|
+
const REMOTE_URL_PATTERN = /^(https?:|data:|blob:|file:)/i;
|
|
24
|
+
const PUBLIC_SEGMENT_PATTERN = /(^|\/)public\//;
|
|
25
|
+
const FILESYSTEM_ABSOLUTE_PATTERN = /^(\/(Users|home|tmp|etc|opt|var)\/|[A-Za-z]:\/)/;
|
|
26
|
+
|
|
27
|
+
const trimLeadingSlashes = (value: string): string => value.replace(/^\/+/, '');
|
|
28
|
+
|
|
29
|
+
const normalizeSeparators = (value: string): string => value.replaceAll('\\', '/');
|
|
30
|
+
|
|
31
|
+
const stripPublicSegment = (value: string): string | null => {
|
|
32
|
+
const match = PUBLIC_SEGMENT_PATTERN.exec(value);
|
|
33
|
+
if (!match || match.index === undefined) {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return value.slice(match.index + match[0].length);
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Resolve a clip source into a Remotion-safe URL.
|
|
42
|
+
*
|
|
43
|
+
* Public-relative paths must go through staticFile() so Remotion prefixes the
|
|
44
|
+
* renderer's static asset base. Remote URLs and unsupported absolute paths are
|
|
45
|
+
* returned as-is.
|
|
46
|
+
*/
|
|
47
|
+
export const resolveRemotionAssetSrc = (src: string): string => {
|
|
48
|
+
const normalized = normalizeSeparators(src.trim());
|
|
49
|
+
|
|
50
|
+
if (!normalized || REMOTE_URL_PATTERN.test(normalized)) {
|
|
51
|
+
return normalized;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const publicRelativePath = stripPublicSegment(normalized);
|
|
55
|
+
if (publicRelativePath) {
|
|
56
|
+
return staticFile(publicRelativePath);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (FILESYSTEM_ABSOLUTE_PATTERN.test(normalized)) {
|
|
60
|
+
return normalized;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return staticFile(trimLeadingSlashes(normalized));
|
|
64
|
+
};
|
package/dist/cli.cjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cli.cjs","names":["WORKSPACE_MARKERS","resolveWorkspaceRoot","path","Command","DEFAULT_PORT_RANGE","PortRegistryService","path","Command","StdioTransportHandler","createServer","createContainer","Command","fs","createContainer","TYPES","Command","packageJson.version"],"sources":["../package.json","../src/commands/http-serve.ts","../src/commands/mcp-serve.ts","../src/commands/render.ts","../src/cli.ts"],"sourcesContent":["","/**\n * HTTP Serve Command\n *\n * Starts Remotion Studio for interactive video editing.\n */\n\nimport { spawn } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport path from 'node:path';\nimport { DEFAULT_PORT_RANGE, PortRegistryService } from '@agimon-ai/foundation-port-registry';\nimport { type ProcessLease, createProcessLease } from '@agimon-ai/foundation-process-registry';\nimport chalk from 'chalk';\nimport { Command } from 'commander';\n\nconst WORKSPACE_MARKERS = ['pnpm-workspace.yaml', 'nx.json', '.git'];\nconst SERVICE_NAME = 'video-editor-mcp-http';\nconst SERVICE_TYPE = 'tool' as const;\n\nfunction resolveWorkspaceRoot(startPath = process.cwd()): string {\n let current = path.resolve(startPath);\n while (true) {\n for (const marker of WORKSPACE_MARKERS) {\n if (existsSync(path.join(current, marker))) {\n return current;\n }\n }\n const parent = path.dirname(current);\n if (parent === current) {\n return process.cwd();\n }\n current = parent;\n }\n}\n\nexport const httpServeCommand = new Command('http-serve')\n .description('Start Remotion Studio for video editing')\n .option('-p, --port <port>', 'Port to run Remotion Studio on', String(DEFAULT_PORT_RANGE.min))\n .action(async (options: { port: string }) => {\n let processLease: ProcessLease | undefined;\n try {\n const requestedPort = Number.parseInt(options.port, 10);\n\n const portRegistry = new PortRegistryService(process.env.PORT_REGISTRY_PATH);\n const repositoryPath = resolveWorkspaceRoot();\n const portRange = requestedPort ? { min: requestedPort, max: requestedPort } : DEFAULT_PORT_RANGE;\n const reserveResult = await portRegistry.reservePort({\n repositoryPath,\n serviceName: SERVICE_NAME,\n serviceType: SERVICE_TYPE,\n preferredPort: requestedPort || DEFAULT_PORT_RANGE.min,\n portRange,\n pid: process.pid,\n host: '127.0.0.1',\n force: true,\n });\n\n if (!reserveResult.success || !reserveResult.record) {\n throw new Error(reserveResult.error || `Failed to reserve port ${requestedPort}`);\n }\n\n const port = reserveResult.record.port;\n\n processLease = await createProcessLease({\n repositoryPath,\n serviceName: SERVICE_NAME,\n serviceType: SERVICE_TYPE,\n pid: process.pid,\n port,\n host: '127.0.0.1',\n command: process.argv[1],\n args: process.argv.slice(2),\n });\n\n // Get the package directory (where remotion entry point is)\n // In compiled output, files are flat in dist/, so go up one level\n const packageDir = path.resolve(import.meta.dirname, '..');\n\n console.error(chalk.green(`Starting Remotion Studio on port ${port}...`));\n console.error(chalk.gray(` Working directory: ${packageDir}`));\n\n // Use the locally installed remotion CLI\n const remotionBin = path.join(packageDir, 'node_modules', '.bin', 'remotion');\n\n const studio = spawn(remotionBin, ['studio', '--port', String(port)], {\n stdio: 'inherit',\n cwd: packageDir,\n });\n\n studio.on('error', (error) => {\n console.error(chalk.red(`Failed to start Remotion Studio: ${error.message}`));\n process.exit(1);\n });\n\n const releaseAndExit = async (signal: NodeJS.Signals) => {\n studio.kill(signal);\n await processLease?.release();\n await portRegistry.releasePort({\n repositoryPath,\n serviceName: SERVICE_NAME,\n serviceType: SERVICE_TYPE,\n pid: process.pid,\n });\n process.exit(0);\n };\n\n process.on('SIGINT', () => releaseAndExit('SIGINT'));\n process.on('SIGTERM', () => releaseAndExit('SIGTERM'));\n } catch (error) {\n await processLease?.release();\n console.error('Error executing http-serve:', error);\n process.exit(1);\n }\n });\n","/**\n * MCP Serve Command\n *\n * DESIGN PATTERNS:\n * - Command pattern with Commander for CLI argument parsing\n * - Transport abstraction pattern for flexible deployment (stdio, HTTP, SSE)\n * - Factory pattern for creating transport handlers\n * - Graceful shutdown pattern with signal handling\n *\n * CODING STANDARDS:\n * - Use async/await for asynchronous operations\n * - Implement proper error handling with try-catch blocks\n * - Handle process signals for graceful shutdown\n * - Provide clear CLI options and help messages\n *\n * AVOID:\n * - Hardcoded configuration values (use CLI options or environment variables)\n * - Missing error handling for transport startup\n * - Not cleaning up resources on shutdown\n */\n\nimport { existsSync } from 'node:fs';\nimport path from 'node:path';\nimport { type ProcessLease, createProcessLease } from '@agimon-ai/foundation-process-registry';\nimport { Command } from 'commander';\nimport { createContainer } from '../container/index.js';\nimport { createServer } from '../server/index.js';\nimport { StdioTransportHandler } from '../transports/stdio.js';\n\nconst WORKSPACE_MARKERS = ['pnpm-workspace.yaml', 'nx.json', '.git'];\n\nfunction resolveWorkspaceRoot(startPath = process.cwd()): string {\n let current = path.resolve(startPath);\n while (true) {\n for (const marker of WORKSPACE_MARKERS) {\n if (existsSync(path.join(current, marker))) {\n return current;\n }\n }\n const parent = path.dirname(current);\n if (parent === current) {\n return process.cwd();\n }\n current = parent;\n }\n}\n\ninterface LifecycleHandler {\n start(): Promise<void>;\n stop(): Promise<void>;\n}\n\n/**\n * Start MCP server with given transport handler\n */\nasync function startServer(handler: LifecycleHandler, onShutdown?: () => Promise<void>) {\n await handler.start();\n\n // Handle graceful shutdown\n const shutdown = async (signal: string) => {\n console.error(`\\nReceived ${signal}, shutting down gracefully...`);\n try {\n await handler.stop();\n await onShutdown?.();\n process.exit(0);\n } catch (error) {\n console.error('Error during shutdown:', error);\n process.exit(1);\n }\n };\n\n process.on('SIGINT', () => shutdown('SIGINT'));\n process.on('SIGTERM', () => shutdown('SIGTERM'));\n}\n\n/**\n * MCP Serve command\n */\nexport const mcpServeCommand = new Command('mcp-serve')\n .description('Start MCP server with specified transport')\n .option('-t, --type <type>', 'Transport type: stdio', 'stdio')\n .action(async (options) => {\n let processLease: ProcessLease | undefined;\n try {\n const transportType = options.type.toLowerCase();\n const repositoryPath = resolveWorkspaceRoot();\n\n if (transportType === 'stdio') {\n const container = createContainer();\n const server = createServer(container);\n const handler = new StdioTransportHandler(server);\n processLease = await createProcessLease({\n repositoryPath,\n serviceName: 'video-editor-mcp-stdio',\n pid: process.pid,\n metadata: { transport: 'stdio' },\n });\n await startServer(handler, async () => {\n await processLease?.release();\n });\n } else {\n console.error(`Unknown transport type: ${transportType}. Use: stdio`);\n process.exit(1);\n }\n } catch (error) {\n await processLease?.release();\n console.error('Failed to start MCP server:', error);\n process.exit(1);\n }\n });\n","/**\n * Render Command\n *\n * Renders a video from JSON props using Remotion.\n */\n\nimport fs from 'node:fs';\nimport chalk from 'chalk';\nimport { Command } from 'commander';\nimport { createContainer } from '../container/index.js';\nimport { RenderService } from '../services/RenderService.js';\nimport { TYPES } from '../types/index.js';\n\ninterface RenderOptions {\n input: string;\n output: string;\n composition: string;\n codec: 'h264' | 'h265' | 'vp8' | 'vp9';\n}\n\nexport const renderCommand = new Command('render')\n .description('Render a video from JSON props file')\n .requiredOption('-i, --input <path>', 'Path to JSON props file')\n .requiredOption('-o, --output <path>', 'Output video file path')\n .option('-c, --composition <id>', 'Composition ID', 'Main')\n .option('--codec <codec>', 'Video codec (h264, h265, vp8, vp9)', 'h264')\n .action(async (options: RenderOptions) => {\n try {\n process.stderr.write(chalk.blue('🎬 Starting video render...\\n'));\n process.stderr.write(chalk.gray(` Input: ${options.input}\\n`));\n process.stderr.write(chalk.gray(` Output: ${options.output}\\n`));\n process.stderr.write(chalk.gray(` Composition: ${options.composition}\\n`));\n process.stderr.write(chalk.gray(` Codec: ${options.codec}\\n`));\n\n // Read JSON props file\n if (!fs.existsSync(options.input)) {\n process.stderr.write(chalk.red(`Error: Input file not found: ${options.input}\\n`));\n process.exit(1);\n }\n\n const propsContent = fs.readFileSync(options.input, 'utf-8');\n const inputProps = JSON.parse(propsContent) as Record<string, unknown>;\n\n // Create container and get RenderService\n const container = createContainer();\n const renderService = container.get<RenderService>(TYPES.RenderService);\n\n process.stderr.write(chalk.blue('📦 Bundling Remotion project...\\n'));\n\n const result = await renderService.render({\n compositionId: options.composition,\n inputProps,\n outputPath: options.output,\n codec: options.codec,\n });\n\n process.stderr.write(chalk.green(`✓ Video rendered successfully: ${result.outputPath}\\n`));\n } catch (error) {\n process.stderr.write(chalk.red(`Error rendering video: ${error}\\n`));\n process.exit(1);\n }\n });\n","#!/usr/bin/env node\n/**\n * MCP Server Entry Point\n *\n * DESIGN PATTERNS:\n * - CLI pattern with Commander for argument parsing\n * - Command pattern for organizing CLI commands\n * - Transport abstraction for multiple communication methods\n *\n * CODING STANDARDS:\n * - Use async/await for asynchronous operations\n * - Handle errors gracefully with try-catch\n * - Log important events for debugging\n * - Register all commands in main entry point\n *\n * AVOID:\n * - Hardcoding command logic in index.ts (use separate command files)\n * - Missing error handling for command execution\n */\nimport { Command } from 'commander';\nimport packageJson from '../package.json' with { type: 'json' };\nimport { httpServeCommand } from './commands/http-serve.js';\nimport { mcpServeCommand } from './commands/mcp-serve.js';\nimport { renderCommand } from './commands/render.js';\n\n/**\n * Main entry point\n */\nasync function main() {\n const program = new Command();\n\n program\n .name('video-editor-mcp')\n .description('MCP server for video editing with Remotion')\n .version(packageJson.version);\n\n // Add all commands\n program.addCommand(mcpServeCommand);\n program.addCommand(httpServeCommand);\n program.addCommand(renderCommand);\n\n // Parse arguments\n await program.parseAsync(process.argv);\n}\n\nmain();\n"],"mappings":"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"}
|
package/dist/cli.mjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cli.mjs","names":["WORKSPACE_MARKERS","resolveWorkspaceRoot","packageJson.version"],"sources":["../package.json","../src/commands/http-serve.ts","../src/commands/mcp-serve.ts","../src/commands/render.ts","../src/cli.ts"],"sourcesContent":["","/**\n * HTTP Serve Command\n *\n * Starts Remotion Studio for interactive video editing.\n */\n\nimport { spawn } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport path from 'node:path';\nimport { DEFAULT_PORT_RANGE, PortRegistryService } from '@agimon-ai/foundation-port-registry';\nimport { type ProcessLease, createProcessLease } from '@agimon-ai/foundation-process-registry';\nimport chalk from 'chalk';\nimport { Command } from 'commander';\n\nconst WORKSPACE_MARKERS = ['pnpm-workspace.yaml', 'nx.json', '.git'];\nconst SERVICE_NAME = 'video-editor-mcp-http';\nconst SERVICE_TYPE = 'tool' as const;\n\nfunction resolveWorkspaceRoot(startPath = process.cwd()): string {\n let current = path.resolve(startPath);\n while (true) {\n for (const marker of WORKSPACE_MARKERS) {\n if (existsSync(path.join(current, marker))) {\n return current;\n }\n }\n const parent = path.dirname(current);\n if (parent === current) {\n return process.cwd();\n }\n current = parent;\n }\n}\n\nexport const httpServeCommand = new Command('http-serve')\n .description('Start Remotion Studio for video editing')\n .option('-p, --port <port>', 'Port to run Remotion Studio on', String(DEFAULT_PORT_RANGE.min))\n .action(async (options: { port: string }) => {\n let processLease: ProcessLease | undefined;\n try {\n const requestedPort = Number.parseInt(options.port, 10);\n\n const portRegistry = new PortRegistryService(process.env.PORT_REGISTRY_PATH);\n const repositoryPath = resolveWorkspaceRoot();\n const portRange = requestedPort ? { min: requestedPort, max: requestedPort } : DEFAULT_PORT_RANGE;\n const reserveResult = await portRegistry.reservePort({\n repositoryPath,\n serviceName: SERVICE_NAME,\n serviceType: SERVICE_TYPE,\n preferredPort: requestedPort || DEFAULT_PORT_RANGE.min,\n portRange,\n pid: process.pid,\n host: '127.0.0.1',\n force: true,\n });\n\n if (!reserveResult.success || !reserveResult.record) {\n throw new Error(reserveResult.error || `Failed to reserve port ${requestedPort}`);\n }\n\n const port = reserveResult.record.port;\n\n processLease = await createProcessLease({\n repositoryPath,\n serviceName: SERVICE_NAME,\n serviceType: SERVICE_TYPE,\n pid: process.pid,\n port,\n host: '127.0.0.1',\n command: process.argv[1],\n args: process.argv.slice(2),\n });\n\n // Get the package directory (where remotion entry point is)\n // In compiled output, files are flat in dist/, so go up one level\n const packageDir = path.resolve(import.meta.dirname, '..');\n\n console.error(chalk.green(`Starting Remotion Studio on port ${port}...`));\n console.error(chalk.gray(` Working directory: ${packageDir}`));\n\n // Use the locally installed remotion CLI\n const remotionBin = path.join(packageDir, 'node_modules', '.bin', 'remotion');\n\n const studio = spawn(remotionBin, ['studio', '--port', String(port)], {\n stdio: 'inherit',\n cwd: packageDir,\n });\n\n studio.on('error', (error) => {\n console.error(chalk.red(`Failed to start Remotion Studio: ${error.message}`));\n process.exit(1);\n });\n\n const releaseAndExit = async (signal: NodeJS.Signals) => {\n studio.kill(signal);\n await processLease?.release();\n await portRegistry.releasePort({\n repositoryPath,\n serviceName: SERVICE_NAME,\n serviceType: SERVICE_TYPE,\n pid: process.pid,\n });\n process.exit(0);\n };\n\n process.on('SIGINT', () => releaseAndExit('SIGINT'));\n process.on('SIGTERM', () => releaseAndExit('SIGTERM'));\n } catch (error) {\n await processLease?.release();\n console.error('Error executing http-serve:', error);\n process.exit(1);\n }\n });\n","/**\n * MCP Serve Command\n *\n * DESIGN PATTERNS:\n * - Command pattern with Commander for CLI argument parsing\n * - Transport abstraction pattern for flexible deployment (stdio, HTTP, SSE)\n * - Factory pattern for creating transport handlers\n * - Graceful shutdown pattern with signal handling\n *\n * CODING STANDARDS:\n * - Use async/await for asynchronous operations\n * - Implement proper error handling with try-catch blocks\n * - Handle process signals for graceful shutdown\n * - Provide clear CLI options and help messages\n *\n * AVOID:\n * - Hardcoded configuration values (use CLI options or environment variables)\n * - Missing error handling for transport startup\n * - Not cleaning up resources on shutdown\n */\n\nimport { existsSync } from 'node:fs';\nimport path from 'node:path';\nimport { type ProcessLease, createProcessLease } from '@agimon-ai/foundation-process-registry';\nimport { Command } from 'commander';\nimport { createContainer } from '../container/index.js';\nimport { createServer } from '../server/index.js';\nimport { StdioTransportHandler } from '../transports/stdio.js';\n\nconst WORKSPACE_MARKERS = ['pnpm-workspace.yaml', 'nx.json', '.git'];\n\nfunction resolveWorkspaceRoot(startPath = process.cwd()): string {\n let current = path.resolve(startPath);\n while (true) {\n for (const marker of WORKSPACE_MARKERS) {\n if (existsSync(path.join(current, marker))) {\n return current;\n }\n }\n const parent = path.dirname(current);\n if (parent === current) {\n return process.cwd();\n }\n current = parent;\n }\n}\n\ninterface LifecycleHandler {\n start(): Promise<void>;\n stop(): Promise<void>;\n}\n\n/**\n * Start MCP server with given transport handler\n */\nasync function startServer(handler: LifecycleHandler, onShutdown?: () => Promise<void>) {\n await handler.start();\n\n // Handle graceful shutdown\n const shutdown = async (signal: string) => {\n console.error(`\\nReceived ${signal}, shutting down gracefully...`);\n try {\n await handler.stop();\n await onShutdown?.();\n process.exit(0);\n } catch (error) {\n console.error('Error during shutdown:', error);\n process.exit(1);\n }\n };\n\n process.on('SIGINT', () => shutdown('SIGINT'));\n process.on('SIGTERM', () => shutdown('SIGTERM'));\n}\n\n/**\n * MCP Serve command\n */\nexport const mcpServeCommand = new Command('mcp-serve')\n .description('Start MCP server with specified transport')\n .option('-t, --type <type>', 'Transport type: stdio', 'stdio')\n .action(async (options) => {\n let processLease: ProcessLease | undefined;\n try {\n const transportType = options.type.toLowerCase();\n const repositoryPath = resolveWorkspaceRoot();\n\n if (transportType === 'stdio') {\n const container = createContainer();\n const server = createServer(container);\n const handler = new StdioTransportHandler(server);\n processLease = await createProcessLease({\n repositoryPath,\n serviceName: 'video-editor-mcp-stdio',\n pid: process.pid,\n metadata: { transport: 'stdio' },\n });\n await startServer(handler, async () => {\n await processLease?.release();\n });\n } else {\n console.error(`Unknown transport type: ${transportType}. Use: stdio`);\n process.exit(1);\n }\n } catch (error) {\n await processLease?.release();\n console.error('Failed to start MCP server:', error);\n process.exit(1);\n }\n });\n","/**\n * Render Command\n *\n * Renders a video from JSON props using Remotion.\n */\n\nimport fs from 'node:fs';\nimport chalk from 'chalk';\nimport { Command } from 'commander';\nimport { createContainer } from '../container/index.js';\nimport { RenderService } from '../services/RenderService.js';\nimport { TYPES } from '../types/index.js';\n\ninterface RenderOptions {\n input: string;\n output: string;\n composition: string;\n codec: 'h264' | 'h265' | 'vp8' | 'vp9';\n}\n\nexport const renderCommand = new Command('render')\n .description('Render a video from JSON props file')\n .requiredOption('-i, --input <path>', 'Path to JSON props file')\n .requiredOption('-o, --output <path>', 'Output video file path')\n .option('-c, --composition <id>', 'Composition ID', 'Main')\n .option('--codec <codec>', 'Video codec (h264, h265, vp8, vp9)', 'h264')\n .action(async (options: RenderOptions) => {\n try {\n process.stderr.write(chalk.blue('🎬 Starting video render...\\n'));\n process.stderr.write(chalk.gray(` Input: ${options.input}\\n`));\n process.stderr.write(chalk.gray(` Output: ${options.output}\\n`));\n process.stderr.write(chalk.gray(` Composition: ${options.composition}\\n`));\n process.stderr.write(chalk.gray(` Codec: ${options.codec}\\n`));\n\n // Read JSON props file\n if (!fs.existsSync(options.input)) {\n process.stderr.write(chalk.red(`Error: Input file not found: ${options.input}\\n`));\n process.exit(1);\n }\n\n const propsContent = fs.readFileSync(options.input, 'utf-8');\n const inputProps = JSON.parse(propsContent) as Record<string, unknown>;\n\n // Create container and get RenderService\n const container = createContainer();\n const renderService = container.get<RenderService>(TYPES.RenderService);\n\n process.stderr.write(chalk.blue('📦 Bundling Remotion project...\\n'));\n\n const result = await renderService.render({\n compositionId: options.composition,\n inputProps,\n outputPath: options.output,\n codec: options.codec,\n });\n\n process.stderr.write(chalk.green(`✓ Video rendered successfully: ${result.outputPath}\\n`));\n } catch (error) {\n process.stderr.write(chalk.red(`Error rendering video: ${error}\\n`));\n process.exit(1);\n }\n });\n","#!/usr/bin/env node\n/**\n * MCP Server Entry Point\n *\n * DESIGN PATTERNS:\n * - CLI pattern with Commander for argument parsing\n * - Command pattern for organizing CLI commands\n * - Transport abstraction for multiple communication methods\n *\n * CODING STANDARDS:\n * - Use async/await for asynchronous operations\n * - Handle errors gracefully with try-catch\n * - Log important events for debugging\n * - Register all commands in main entry point\n *\n * AVOID:\n * - Hardcoding command logic in index.ts (use separate command files)\n * - Missing error handling for command execution\n */\nimport { Command } from 'commander';\nimport packageJson from '../package.json' with { type: 'json' };\nimport { httpServeCommand } from './commands/http-serve.js';\nimport { mcpServeCommand } from './commands/mcp-serve.js';\nimport { renderCommand } from './commands/render.js';\n\n/**\n * Main entry point\n */\nasync function main() {\n const program = new Command();\n\n program\n .name('video-editor-mcp')\n .description('MCP server for video editing with Remotion')\n .version(packageJson.version);\n\n // Add all commands\n program.addCommand(mcpServeCommand);\n program.addCommand(httpServeCommand);\n program.addCommand(renderCommand);\n\n // Parse arguments\n await program.parseAsync(process.argv);\n}\n\nmain();\n"],"mappings":"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"}
|
package/dist/index.cjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["z","z"],"sources":["../src/schemas/clips.ts","../src/schemas/compositions.ts"],"sourcesContent":["import { z } from 'zod';\n\n/**\n * Animation configuration for clip entrance/exit effects\n */\nexport const AnimationConfigSchema = z.object({\n type: z.enum(['interpolate', 'spring']).default('interpolate'),\n easing: z.enum(['linear', 'ease-in', 'ease-out', 'ease-in-out']).optional(),\n springConfig: z\n .object({\n mass: z.number().positive().default(1),\n damping: z.number().positive().default(10),\n stiffness: z.number().positive().default(100),\n })\n .optional(),\n delay: z.number().int().nonnegative().default(0),\n});\n\n/**\n * Transition configuration between clips\n */\nexport const TransitionConfigSchema = z.object({\n type: z.enum(['fade', 'slide', 'wipe', 'flip', 'clockWipe', 'none']).default('fade'),\n durationInFrames: z.number().int().positive().default(15),\n direction: z.enum(['from-left', 'from-right', 'from-top', 'from-bottom']).optional(),\n});\n\n/**\n * Base clip fields shared across all clip types\n */\nconst BaseClipFields = {\n startFrame: z.number().int().nonnegative(),\n durationInFrames: z.number().int().positive(),\n premountFor: z.number().int().nonnegative().default(30),\n entrance: AnimationConfigSchema.optional(),\n exit: AnimationConfigSchema.optional(),\n transition: TransitionConfigSchema.optional(),\n};\n\n/**\n * Video clip — renders with OffthreadVideo\n */\nexport const VideoClipSchema = z.object({\n type: z.literal('video'),\n ...BaseClipFields,\n src: z.string(),\n volume: z.number().min(0).max(1).optional(),\n playbackRate: z.number().positive().optional(),\n muted: z.boolean().optional(),\n loop: z.boolean().optional(),\n trimBefore: z.number().nonnegative().optional(),\n trimAfter: z.number().nonnegative().optional(),\n transparent: z.boolean().optional(),\n style: z.record(z.string(), z.unknown()).optional(),\n});\n\n/**\n * Image clip — renders with Img\n */\nexport const ImageClipSchema = z.object({\n type: z.literal('image'),\n ...BaseClipFields,\n src: z.string(),\n fit: z.enum(['contain', 'cover', 'fill']).optional(),\n style: z.record(z.string(), z.unknown()).optional(),\n});\n\n/**\n * Text clip — animated text with multiple animation types\n */\nexport const TextClipSchema = z.object({\n type: z.literal('text'),\n ...BaseClipFields,\n text: z.string(),\n fontSize: z.number().positive().default(80),\n fontFamily: z.string().default('sans-serif'),\n fontWeight: z.union([z.string(), z.number()]).optional(),\n color: z.string().default('#ffffff'),\n backgroundColor: z.string().optional(),\n position: z.enum(['top', 'center', 'bottom']).default('center'),\n animation: z.enum(['none', 'fade', 'slide', 'typewriter', 'highlight']).default('none'),\n highlightColor: z.string().optional(),\n highlightWord: z.string().optional(),\n style: z.record(z.string(), z.unknown()).optional(),\n});\n\n/**\n * Audio clip — renders with Audio component\n */\nexport const AudioClipSchema = z.object({\n type: z.literal('audio'),\n ...BaseClipFields,\n src: z.string(),\n volume: z.number().min(0).max(1).optional(),\n playbackRate: z.number().positive().optional(),\n muted: z.boolean().optional(),\n loop: z.boolean().optional(),\n trimBefore: z.number().nonnegative().optional(),\n trimAfter: z.number().nonnegative().optional(),\n toneFrequency: z.number().positive().optional(),\n});\n\n/**\n * Subtitle clip — animated subtitle overlay\n */\nexport const SubtitleClipSchema = z.object({\n type: z.literal('subtitle'),\n ...BaseClipFields,\n text: z.string(),\n position: z.enum(['top', 'center', 'bottom']).default('bottom'),\n animation: z.enum(['none', 'fade', 'slide']).default('fade'),\n fontSize: z.number().positive().default(36),\n fontFamily: z.string().default('Arial, sans-serif'),\n color: z.string().default('#ffffff'),\n backgroundColor: z.string().default('rgba(0, 0, 0, 0.7)'),\n style: z.record(z.string(), z.unknown()).optional(),\n});\n\n/**\n * GIF clip — renders with Gif component\n */\nexport const GifClipSchema = z.object({\n type: z.literal('gif'),\n ...BaseClipFields,\n src: z.string(),\n width: z.number().positive().optional(),\n height: z.number().positive().optional(),\n fit: z.enum(['contain', 'cover', 'fill']).optional(),\n playbackRate: z.number().positive().optional(),\n loopBehavior: z.enum(['loop', 'pause-after-finish']).optional(),\n style: z.record(z.string(), z.unknown()).optional(),\n});\n\n/**\n * Lottie clip — renders Lottie JSON animations\n */\nexport const LottieClipSchema = z.object({\n type: z.literal('lottie'),\n ...BaseClipFields,\n src: z.string(),\n width: z.number().positive().optional(),\n height: z.number().positive().optional(),\n loop: z.boolean().optional(),\n style: z.record(z.string(), z.unknown()).optional(),\n});\n\n/**\n * Discriminated union of all clip types\n */\nexport const ClipSchema = z.discriminatedUnion('type', [\n VideoClipSchema,\n ImageClipSchema,\n TextClipSchema,\n AudioClipSchema,\n SubtitleClipSchema,\n GifClipSchema,\n LottieClipSchema,\n]);\n","import { z } from 'zod';\nimport { ClipSchema, TransitionConfigSchema } from './clips.js';\n\n/**\n * Individual caption entry (word or segment level)\n */\nexport const CaptionSchema = z.object({\n text: z.string(),\n startMs: z.number().nonnegative(),\n endMs: z.number().nonnegative(),\n timestampMs: z.number().nonnegative().optional(),\n confidence: z.number().min(0).max(1).optional(),\n});\n\n/**\n * Caption overlay configuration for TikTok-style captions\n */\nexport const CaptionConfigSchema = z.object({\n captions: z.array(CaptionSchema),\n style: z.enum(['tiktok', 'standard', 'karaoke']).default('tiktok'),\n combineTokensWithinMilliseconds: z.number().nonnegative().default(800),\n fontSize: z.number().positive().default(60),\n fontFamily: z.string().default('Arial, sans-serif'),\n color: z.string().default('#ffffff'),\n highlightColor: z.string().default('#FFD700'),\n textColor: z.string().default('#ffffff'),\n backgroundColor: z.string().default('rgba(0, 0, 0, 0.8)'),\n position: z.enum(['top', 'center', 'bottom']).default('bottom'),\n});\n\n/**\n * Font loading configuration\n */\nexport const FontConfigSchema = z.object({\n family: z.string(),\n source: z.enum(['google', 'local']).default('google'),\n weights: z.array(z.number().int().positive()).optional(),\n url: z.string().optional(),\n});\n\n/**\n * Main composition props schema\n */\nexport const MainCompositionSchema = z.object({\n clips: z.array(ClipSchema).default([]),\n backgroundColor: z.string().default('#000000'),\n fps: z.number().int().positive().default(30),\n width: z.number().int().positive().default(1920),\n height: z.number().int().positive().default(1080),\n captions: CaptionConfigSchema.optional(),\n globalTransition: TransitionConfigSchema.optional(),\n fonts: z.array(FontConfigSchema).optional(),\n});\n"],"mappings":"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"}
|
package/dist/index.mjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../src/schemas/clips.ts","../src/schemas/compositions.ts"],"sourcesContent":["import { z } from 'zod';\n\n/**\n * Animation configuration for clip entrance/exit effects\n */\nexport const AnimationConfigSchema = z.object({\n type: z.enum(['interpolate', 'spring']).default('interpolate'),\n easing: z.enum(['linear', 'ease-in', 'ease-out', 'ease-in-out']).optional(),\n springConfig: z\n .object({\n mass: z.number().positive().default(1),\n damping: z.number().positive().default(10),\n stiffness: z.number().positive().default(100),\n })\n .optional(),\n delay: z.number().int().nonnegative().default(0),\n});\n\n/**\n * Transition configuration between clips\n */\nexport const TransitionConfigSchema = z.object({\n type: z.enum(['fade', 'slide', 'wipe', 'flip', 'clockWipe', 'none']).default('fade'),\n durationInFrames: z.number().int().positive().default(15),\n direction: z.enum(['from-left', 'from-right', 'from-top', 'from-bottom']).optional(),\n});\n\n/**\n * Base clip fields shared across all clip types\n */\nconst BaseClipFields = {\n startFrame: z.number().int().nonnegative(),\n durationInFrames: z.number().int().positive(),\n premountFor: z.number().int().nonnegative().default(30),\n entrance: AnimationConfigSchema.optional(),\n exit: AnimationConfigSchema.optional(),\n transition: TransitionConfigSchema.optional(),\n};\n\n/**\n * Video clip — renders with OffthreadVideo\n */\nexport const VideoClipSchema = z.object({\n type: z.literal('video'),\n ...BaseClipFields,\n src: z.string(),\n volume: z.number().min(0).max(1).optional(),\n playbackRate: z.number().positive().optional(),\n muted: z.boolean().optional(),\n loop: z.boolean().optional(),\n trimBefore: z.number().nonnegative().optional(),\n trimAfter: z.number().nonnegative().optional(),\n transparent: z.boolean().optional(),\n style: z.record(z.string(), z.unknown()).optional(),\n});\n\n/**\n * Image clip — renders with Img\n */\nexport const ImageClipSchema = z.object({\n type: z.literal('image'),\n ...BaseClipFields,\n src: z.string(),\n fit: z.enum(['contain', 'cover', 'fill']).optional(),\n style: z.record(z.string(), z.unknown()).optional(),\n});\n\n/**\n * Text clip — animated text with multiple animation types\n */\nexport const TextClipSchema = z.object({\n type: z.literal('text'),\n ...BaseClipFields,\n text: z.string(),\n fontSize: z.number().positive().default(80),\n fontFamily: z.string().default('sans-serif'),\n fontWeight: z.union([z.string(), z.number()]).optional(),\n color: z.string().default('#ffffff'),\n backgroundColor: z.string().optional(),\n position: z.enum(['top', 'center', 'bottom']).default('center'),\n animation: z.enum(['none', 'fade', 'slide', 'typewriter', 'highlight']).default('none'),\n highlightColor: z.string().optional(),\n highlightWord: z.string().optional(),\n style: z.record(z.string(), z.unknown()).optional(),\n});\n\n/**\n * Audio clip — renders with Audio component\n */\nexport const AudioClipSchema = z.object({\n type: z.literal('audio'),\n ...BaseClipFields,\n src: z.string(),\n volume: z.number().min(0).max(1).optional(),\n playbackRate: z.number().positive().optional(),\n muted: z.boolean().optional(),\n loop: z.boolean().optional(),\n trimBefore: z.number().nonnegative().optional(),\n trimAfter: z.number().nonnegative().optional(),\n toneFrequency: z.number().positive().optional(),\n});\n\n/**\n * Subtitle clip — animated subtitle overlay\n */\nexport const SubtitleClipSchema = z.object({\n type: z.literal('subtitle'),\n ...BaseClipFields,\n text: z.string(),\n position: z.enum(['top', 'center', 'bottom']).default('bottom'),\n animation: z.enum(['none', 'fade', 'slide']).default('fade'),\n fontSize: z.number().positive().default(36),\n fontFamily: z.string().default('Arial, sans-serif'),\n color: z.string().default('#ffffff'),\n backgroundColor: z.string().default('rgba(0, 0, 0, 0.7)'),\n style: z.record(z.string(), z.unknown()).optional(),\n});\n\n/**\n * GIF clip — renders with Gif component\n */\nexport const GifClipSchema = z.object({\n type: z.literal('gif'),\n ...BaseClipFields,\n src: z.string(),\n width: z.number().positive().optional(),\n height: z.number().positive().optional(),\n fit: z.enum(['contain', 'cover', 'fill']).optional(),\n playbackRate: z.number().positive().optional(),\n loopBehavior: z.enum(['loop', 'pause-after-finish']).optional(),\n style: z.record(z.string(), z.unknown()).optional(),\n});\n\n/**\n * Lottie clip — renders Lottie JSON animations\n */\nexport const LottieClipSchema = z.object({\n type: z.literal('lottie'),\n ...BaseClipFields,\n src: z.string(),\n width: z.number().positive().optional(),\n height: z.number().positive().optional(),\n loop: z.boolean().optional(),\n style: z.record(z.string(), z.unknown()).optional(),\n});\n\n/**\n * Discriminated union of all clip types\n */\nexport const ClipSchema = z.discriminatedUnion('type', [\n VideoClipSchema,\n ImageClipSchema,\n TextClipSchema,\n AudioClipSchema,\n SubtitleClipSchema,\n GifClipSchema,\n LottieClipSchema,\n]);\n","import { z } from 'zod';\nimport { ClipSchema, TransitionConfigSchema } from './clips.js';\n\n/**\n * Individual caption entry (word or segment level)\n */\nexport const CaptionSchema = z.object({\n text: z.string(),\n startMs: z.number().nonnegative(),\n endMs: z.number().nonnegative(),\n timestampMs: z.number().nonnegative().optional(),\n confidence: z.number().min(0).max(1).optional(),\n});\n\n/**\n * Caption overlay configuration for TikTok-style captions\n */\nexport const CaptionConfigSchema = z.object({\n captions: z.array(CaptionSchema),\n style: z.enum(['tiktok', 'standard', 'karaoke']).default('tiktok'),\n combineTokensWithinMilliseconds: z.number().nonnegative().default(800),\n fontSize: z.number().positive().default(60),\n fontFamily: z.string().default('Arial, sans-serif'),\n color: z.string().default('#ffffff'),\n highlightColor: z.string().default('#FFD700'),\n textColor: z.string().default('#ffffff'),\n backgroundColor: z.string().default('rgba(0, 0, 0, 0.8)'),\n position: z.enum(['top', 'center', 'bottom']).default('bottom'),\n});\n\n/**\n * Font loading configuration\n */\nexport const FontConfigSchema = z.object({\n family: z.string(),\n source: z.enum(['google', 'local']).default('google'),\n weights: z.array(z.number().int().positive()).optional(),\n url: z.string().optional(),\n});\n\n/**\n * Main composition props schema\n */\nexport const MainCompositionSchema = z.object({\n clips: z.array(ClipSchema).default([]),\n backgroundColor: z.string().default('#000000'),\n fps: z.number().int().positive().default(30),\n width: z.number().int().positive().default(1920),\n height: z.number().int().positive().default(1080),\n captions: CaptionConfigSchema.optional(),\n globalTransition: TransitionConfigSchema.optional(),\n fonts: z.array(FontConfigSchema).optional(),\n});\n"],"mappings":"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"}
|
package/dist/stdio-B6Hg5voC.mjs
DELETED
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import"reflect-metadata";import{Container as e,ContainerModule as t,inject as n,injectable as r}from"inversify";import{execFile as i}from"node:child_process";import{promisify as a}from"node:util";import o from"node:path";import{bundle as s}from"@remotion/bundler";import{renderMedia as c,renderStill as l,selectComposition as u}from"@remotion/renderer";import d from"node:fs/promises";import ee from"node:os";import{z as f}from"zod";import{coerceArgs as te,formatZodError as ne}from"@agimon-ai/foundation-validator";import{Server as re}from"@modelcontextprotocol/sdk/server/index.js";import{CallToolRequestSchema as ie,ListToolsRequestSchema as ae}from"@modelcontextprotocol/sdk/types.js";import{StdioServerTransport as oe}from"@modelcontextprotocol/sdk/server/stdio.js";function p(e,t,n,r){var i=arguments.length,a=i<3?t:r===null?r=Object.getOwnPropertyDescriptor(t,n):r,o;if(typeof Reflect==`object`&&typeof Reflect.decorate==`function`)a=Reflect.decorate(e,t,n,r);else for(var s=e.length-1;s>=0;s--)(o=e[s])&&(a=(i<3?o(a):i>3?o(t,n,a):o(t,n))||a);return i>3&&a&&Object.defineProperty(t,n,a),a}let m=class{parseSrt(e){let t=[],n=e.split(`
|
|
2
|
-
`),r=0;for(;r<n.length;){if(!n[r]?.trim()){r++;continue}r++;let e=n[r];if(!e?.includes(`-->`)){r++;continue}let[i,a]=e.split(`-->`).map(e=>e.trim());if(!i||!a){r++;continue}let o=this.parseTimestamp(i),s=this.parseTimestamp(a);r++;let c=[];for(;r<n.length&&n[r]?.trim();)c.push(n[r]??``),r++;let l=c.join(`
|
|
3
|
-
`);l&&t.push({text:l,startMs:o,endMs:s})}return t}parseTimestamp(e){let[t,n]=e.split(`,`);if(!t||!n)throw Error(`Invalid timestamp format: ${e}`);let[r,i,a]=t.split(`:`).map(Number);if(r===void 0||i===void 0||a===void 0)throw Error(`Invalid time format: ${t}`);return(r*3600+i*60+a)*1e3+Number(n)}createTikTokCaptions(e,t){let n=[];if(e.length===0)return{pages:n};let r={startMs:e[0]?.startMs??0,endMs:e[0]?.endMs??0,tokens:[e[0]]};for(let i=1;i<e.length;i++){let a=e[i];a&&(a.startMs-r.endMs<=t?(r.tokens.push(a),r.endMs=a.endMs):(n.push(r),r={startMs:a.startMs,endMs:a.endMs,tokens:[a]}))}return r.tokens.length>0&&n.push(r),{pages:n}}};m=p([r()],m);const h=[`Inter`,`Roboto`,`Open Sans`,`Montserrat`,`Lato`,`Poppins`,`Oswald`,`Raleway`,`Playfair Display`,`Merriweather`,`Source Sans Pro`,`PT Sans`,`Ubuntu`,`Nunito`,`Rubik`,`Work Sans`,`Karla`,`Noto Sans`,`Fira Sans`,`DM Sans`];let g=class{getAvailableGoogleFonts(){return[...h]}validateFontFamily(e){let t=e.toLowerCase();return h.some(e=>e.toLowerCase()===t)}};g=p([r()],g);const _=a(i);let v=class{async getVideoDuration(e){try{let{stdout:t}=await _(`ffprobe`,[`-v`,`error`,`-show_entries`,`format=duration`,`-of`,`json`,e]),n=JSON.parse(t),r=Number.parseFloat(n.format?.duration??`0`);if(Number.isNaN(r)||r<=0)throw Error(`Invalid duration for video: ${e}`);return r}catch(t){throw Error(`Failed to get video duration for ${e}: ${t instanceof Error?t.message:String(t)}`,{cause:t})}}async getAudioDuration(e){try{let{stdout:t}=await _(`ffprobe`,[`-v`,`error`,`-show_entries`,`format=duration`,`-of`,`json`,e]),n=JSON.parse(t),r=Number.parseFloat(n.format?.duration??`0`);if(Number.isNaN(r)||r<=0)throw Error(`Invalid duration for audio: ${e}`);return r}catch(t){throw Error(`Failed to get audio duration for ${e}: ${t instanceof Error?t.message:String(t)}`,{cause:t})}}async getVideoDimensions(e){try{let{stdout:t}=await _(`ffprobe`,[`-v`,`error`,`-select_streams`,`v:0`,`-show_entries`,`stream=width,height`,`-of`,`json`,e]),n=JSON.parse(t).streams?.[0];if(!n?.width||!n?.height)throw Error(`No video stream found in: ${e}`);return{width:Number(n.width),height:Number(n.height)}}catch(t){throw Error(`Failed to get video dimensions for ${e}: ${t instanceof Error?t.message:String(t)}`,{cause:t})}}async canDecode(e){try{return await _(`ffprobe`,[`-v`,`error`,`-show_entries`,`format=duration`,`-of`,`json`,e]),!0}catch{return!1}}};v=p([r()],v);let y=class{bundlePromise=null;async getServeUrl(){if(!this.bundlePromise){let e=o.resolve(import.meta.dirname,`../..`);this.bundlePromise=s({entryPoint:o.resolve(e,`src/remotion/index.ts`),publicDir:o.resolve(e,`public`),webpackOverride:e=>({...e,resolve:{...e.resolve,extensionAlias:{".js":[`.ts`,`.tsx`,`.js`,`.jsx`]}}})})}return this.bundlePromise}async render(e){let t=await this.getServeUrl();return await c({composition:await u({serveUrl:t,id:e.compositionId,inputProps:e.inputProps}),serveUrl:t,codec:e.codec??`h264`,outputLocation:e.outputPath,inputProps:e.inputProps}),{outputPath:e.outputPath}}async renderStill(e){let t=await this.getServeUrl();return await l({composition:await u({serveUrl:t,id:e.compositionId,inputProps:e.inputProps}),serveUrl:t,output:e.outputPath,frame:e.frame??0,imageFormat:e.imageFormat??`png`,inputProps:e.inputProps}),{outputPath:e.outputPath}}};y=p([r()],y);const b=a(i),x=[`af_sarah`,`af_nicole`,`af_bella`,`af_sky`,`am_adam`,`am_michael`,`bf_emma`,`bf_isabella`,`bm_george`,`bm_lewis`];let S=class{async isAvailable(){try{return await b(`kokoro-tts`,[`--version`]),!0}catch{return!1}}async generateVoiceover(e){let{text:t,voice:n=`af_sarah`,speed:r=1,outputPath:i}=e,a=await d.mkdtemp(o.join(ee.tmpdir(),`kokoro-`)),s=o.join(a,`input.txt`);try{return await d.writeFile(s,t,`utf-8`),await b(`kokoro-tts`,[s,i,`--voice`,n,`--speed`,r.toString()]),{outputPath:i}}catch(e){throw Error(`Failed to generate voiceover: ${e instanceof Error?e.message:String(e)}`,{cause:e})}finally{try{await d.rm(a,{recursive:!0,force:!0})}catch{}}}listVoices(){return[...x]}};S=p([r()],S);let C=class{success(e){return{content:[{type:`text`,text:e}]}}successJson(e){return{content:[{type:`text`,text:JSON.stringify(e,null,2)}]}}error(e){return{content:[{type:`text`,text:`Error: ${e}`}],isError:!0}}async safeExecute(e){try{return await e()}catch(e){return this.error(e instanceof Error?e.message:`Unknown error`)}}};C=p([r()],C);const w={RenderService:Symbol.for(`RenderService`),MediaInfoService:Symbol.for(`MediaInfoService`),CaptionService:Symbol.for(`CaptionService`),FontService:Symbol.for(`FontService`),VoiceoverService:Symbol.for(`VoiceoverService`),Tool:Symbol.for(`Tool`)};function T(e,t){if(typeof Reflect==`object`&&typeof Reflect.metadata==`function`)return Reflect.metadata(e,t)}function E(e,t){return function(n,r){t(n,r,e)}}var D,O;const k=f.object({captions:f.array(f.object({text:f.string(),startMs:f.number(),endMs:f.number()})).describe(`Array of caption objects with text, startMs, and endMs`),combineMs:f.number().optional().describe(`Milliseconds threshold for combining captions into pages (default: 100)`)});let A=class extends C{static{O=this}static TOOL_NAME=`generate_captions`;constructor(e){super(),this.captionService=e}getInputSchema(){return k}getDefinition(){return{name:O.TOOL_NAME,description:`Create TikTok-style caption pages from a caption array for video overlay`,inputSchema:f.toJSONSchema(k,{reused:`inline`})}}async execute(e){try{let{captions:t,combineMs:n=100}=k.parse(e),r=t.map(e=>({text:e.text,startMs:e.startMs,endMs:e.endMs})),i=this.captionService.createTikTokCaptions(r,n);return this.successJson(i)}catch(e){return this.error(e instanceof Error?e.message:`Unknown error`)}}};A=O=p([r(),E(0,n(w.CaptionService)),T(`design:paramtypes`,[typeof(D=m!==void 0&&m)==`function`?D:Object])],A);var j,M;const N=f.object({text:f.string().describe(`Text to convert to speech`),voice:f.string().optional().describe(`Voice ID (default: af_sarah). Options: af_sarah, af_nicole, af_bella, af_sky, am_adam, am_michael, bf_emma, bf_isabella, bm_george, bm_lewis`),speed:f.number().optional().describe(`Speech speed multiplier (default: 1.0)`),outputPath:f.string().describe(`Output file path for the generated audio`)});let P=class extends C{static{M=this}static TOOL_NAME=`generate_voiceover`;constructor(e){super(),this.voiceoverService=e}getInputSchema(){return N}getDefinition(){return{name:M.TOOL_NAME,description:`Generate voiceover audio from text using Kokoro TTS local engine`,inputSchema:f.toJSONSchema(N,{reused:`inline`})}}async execute(e){try{let t=N.parse(e);if(!await this.voiceoverService.isAvailable())return this.error(`Kokoro TTS is not installed. Install it with: pip install kokoro-tts`);let n=await this.voiceoverService.generateVoiceover({text:t.text,voice:t.voice,speed:t.speed,outputPath:t.outputPath});return this.successJson(n)}catch(e){return this.error(e instanceof Error?e.message:`Unknown error`)}}};P=M=p([r(),E(0,n(w.VoiceoverService)),T(`design:paramtypes`,[typeof(j=S!==void 0&&S)==`function`?j:Object])],P);var F,I;const L=f.object({src:f.string().describe(`Path to the media file`),type:f.enum([`video`,`audio`]).optional().describe(`Media type (default: video)`)});let R=class extends C{static{I=this}static TOOL_NAME=`get_media_info`;constructor(e){super(),this.mediaInfoService=e}getInputSchema(){return L}getDefinition(){return{name:I.TOOL_NAME,description:`Get duration, dimensions, and decodability info for video/audio files`,inputSchema:f.toJSONSchema(L,{reused:`inline`})}}async execute(e){try{let{src:t,type:n=`video`}=L.parse(e),r=await this.mediaInfoService.canDecode(t);if(n===`audio`){let e=await this.mediaInfoService.getAudioDuration(t);return this.successJson({src:t,type:`audio`,duration:e,canDecode:r})}let[i,a]=await Promise.all([this.mediaInfoService.getVideoDuration(t),this.mediaInfoService.getVideoDimensions(t)]);return this.successJson({src:t,type:`video`,duration:i,width:a.width,height:a.height,canDecode:r})}catch(e){return this.error(e instanceof Error?e.message:`Unknown error`)}}};R=I=p([r(),E(0,n(w.MediaInfoService)),T(`design:paramtypes`,[typeof(F=v!==void 0&&v)==`function`?F:Object])],R);var z,B;const V=f.object({srtContent:f.string().describe(`SRT file content as a string`)});let H=class extends C{static{B=this}static TOOL_NAME=`import_srt`;constructor(e){super(),this.captionService=e}getInputSchema(){return V}getDefinition(){return{name:B.TOOL_NAME,description:`Parse SRT subtitle file content into structured Caption format for video overlay`,inputSchema:f.toJSONSchema(V,{reused:`inline`})}}async execute(e){try{let t=V.parse(e),n=this.captionService.parseSrt(t.srtContent);return this.successJson({captionCount:n.length,captions:n})}catch(e){return this.error(e instanceof Error?e.message:`Unknown error`)}}};H=B=p([r(),E(0,n(w.CaptionService)),T(`design:paramtypes`,[typeof(z=m!==void 0&&m)==`function`?z:Object])],H);var U;const W=f.object({});let G=class extends C{static{U=this}static TOOL_NAME=`list_compositions`;getInputSchema(){return W}getDefinition(){return{name:U.TOOL_NAME,description:`List all available Remotion compositions with their schemas, dimensions, and format info`,inputSchema:f.toJSONSchema(W,{reused:`inline`})}}async execute(){let e=[{id:`Main`,description:`Main 16:9 landscape composition`,width:1920,height:1080,fps:30,durationInFrames:null,defaultProps:{clips:[],audioVolume:1,backgroundColor:`#000000`}},{id:`Vertical`,description:`Vertical 9:16 portrait composition (TikTok, Instagram Stories)`,width:1080,height:1920,fps:30,durationInFrames:null,defaultProps:{clips:[],audioVolume:1,backgroundColor:`#000000`}},{id:`Square`,description:`Square 1:1 composition (Instagram posts)`,width:1080,height:1080,fps:30,durationInFrames:null,defaultProps:{clips:[],audioVolume:1,backgroundColor:`#000000`}}];return this.successJson({compositionCount:e.length,compositions:e})}};G=U=p([r()],G);var K,q;const J=f.object({compositionId:f.string().describe(`Remotion composition ID (e.g., "Main", "Vertical", "Square")`),inputProps:f.record(f.string(),f.unknown()).describe(`JSON props to pass to the composition`),outputPath:f.string().describe(`Output file path for the rendered image`),frame:f.number().optional().describe(`Frame number to render (default: 0)`),imageFormat:f.enum([`png`,`jpeg`]).optional().describe(`Image format (default: png)`)});let Y=class extends C{static{q=this}static TOOL_NAME=`preview_frame`;constructor(e){super(),this.renderService=e}getInputSchema(){return J}getDefinition(){return{name:q.TOOL_NAME,description:`Render a single frame from a composition as a PNG or JPEG image for preview`,inputSchema:f.toJSONSchema(J,{reused:`inline`})}}async execute(e){try{let t=J.parse(e),n={compositionId:t.compositionId,inputProps:t.inputProps,outputPath:t.outputPath,frame:t.frame,imageFormat:t.imageFormat},r=await this.renderService.renderStill(n);return this.successJson(r)}catch(e){return this.error(e instanceof Error?e.message:`Unknown error`)}}};Y=q=p([r(),E(0,n(w.RenderService)),T(`design:paramtypes`,[typeof(K=y!==void 0&&y)==`function`?K:Object])],Y);var X,Z;const Q=f.object({compositionId:f.string().describe(`Remotion composition ID (e.g., "Main", "Vertical", "Square")`),inputProps:f.record(f.string(),f.unknown()).describe(`JSON props to pass to the composition`),outputPath:f.string().describe(`Output file path for the rendered video`),codec:f.enum([`h264`,`h265`,`vp8`,`vp9`]).optional().describe(`Video codec (default: h264)`)});let $=class extends C{static{Z=this}static TOOL_NAME=`render_video`;constructor(e){super(),this.renderService=e}getInputSchema(){return Q}getDefinition(){return{name:Z.TOOL_NAME,description:`Render a video from JSON props using Remotion`,inputSchema:f.toJSONSchema(Q,{reused:`inline`})}}async execute(e){try{let t=Q.parse(e),n={compositionId:t.compositionId,inputProps:t.inputProps,outputPath:t.outputPath,codec:t.codec},r=await this.renderService.render(n);return this.successJson(r)}catch(e){return this.error(e instanceof Error?e.message:`Unknown error`)}}};$=Z=p([r(),E(0,n(w.RenderService)),T(`design:paramtypes`,[typeof(X=y!==void 0&&y)==`function`?X:Object])],$);const se=new t(e=>{e.bind(w.RenderService).to(y).inSingletonScope(),e.bind(w.MediaInfoService).to(v).inSingletonScope(),e.bind(w.CaptionService).to(m).inSingletonScope(),e.bind(w.FontService).to(g).inSingletonScope(),e.bind(w.VoiceoverService).to(S).inSingletonScope()}),ce=new t(e=>{e.bind(w.Tool).to($).inSingletonScope(),e.bind(w.Tool).to(G).inSingletonScope(),e.bind(w.Tool).to(R).inSingletonScope(),e.bind(w.Tool).to(Y).inSingletonScope(),e.bind(w.Tool).to(A).inSingletonScope(),e.bind(w.Tool).to(H).inSingletonScope(),e.bind(w.Tool).to(P).inSingletonScope()});function le(){let t=new e;return t.load(se,ce),t}function ue(e){let t=new re({name:`video-editor-mcp`,version:`0.1.0`},{capabilities:{tools:{}}}),n=e.getAll(w.Tool),r=new Map;for(let e of n)r.set(e.getDefinition().name,e);return t.setRequestHandler(ae,async()=>({tools:n.map(e=>e.getDefinition())})),t.setRequestHandler(ie,async e=>{let{name:t,arguments:n}=e.params,i=r.get(t);if(!i)return{content:[{type:`text`,text:`Unknown tool: ${t}`}],isError:!0};let a=te(n??{},i.getInputSchema());try{return await i.execute(a)}catch(e){if(e instanceof f.ZodError)return{content:[{type:`text`,text:ne(e,{schemaName:t,schema:i.getInputSchema()})}],isError:!0};throw e}}),t}var de=class{server;transport=null;constructor(e){this.server=e}async start(){this.transport=new oe,await this.server.connect(this.transport),console.error(`video-editor MCP server started on stdio`)}async stop(){this.transport&&=(await this.transport.close(),null)}};export{Y as a,R as c,w as d,C as f,$ as i,P as l,ue as n,G as o,y as p,le as r,H as s,de as t,A as u};
|
|
4
|
-
//# sourceMappingURL=stdio-B6Hg5voC.mjs.map
|