makaron-cli 0.13.9 → 0.14.1
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/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/README.md +34 -14
- package/bin/makaron.mjs +146 -66
- package/package.json +1 -1
- package/skills/makaron/SKILL.md +21 -12
package/README.md
CHANGED
|
@@ -98,11 +98,12 @@ npx makaron-cli chat --project auto --image photo.jpg --json -b "make it cinemat
|
|
|
98
98
|
npx makaron-cli chat --project auto --image img1.jpg --image img2.jpg --json -b "combine these"
|
|
99
99
|
```
|
|
100
100
|
|
|
101
|
-
`chat` routes image and video models automatically, but you may select the Agent LLM with `--agent-model`. Accepted values are
|
|
101
|
+
`chat` routes image and video models automatically, but you may select the Agent LLM with `--agent-model`. Accepted values are `auto`, the base model IDs (`gpt-5.6-terra`, `gpt-5.6-sol`, `gpt-5.6-luna`, `grok-4.6`, `deepseek-v4-pro`), and the personal-plan routes (`gpt-5.6-terra-codex-subscription`, `gpt-5.6-sol-codex-subscription`, `gpt-5.6-luna-codex-subscription`). For the configured owner, `auto` resolves to GPT-5.6 Terra through the personal Codex plan. Base GPT-5.6 IDs select Azure API; the suffixed IDs select the personal plan explicitly. This flag changes only the reasoning/tool-calling Agent LLM.
|
|
102
102
|
|
|
103
103
|
```bash
|
|
104
104
|
# Explicit lower-cost Agent LLM for a controlled comparison
|
|
105
105
|
npx makaron-cli chat --project auto --agent-model deepseek-v4-pro --json -b "make a 20s badminton video"
|
|
106
|
+
npx makaron-cli chat --project auto --agent-model gpt-5.6-sol-codex-subscription --json -b "reply with the active model"
|
|
106
107
|
```
|
|
107
108
|
|
|
108
109
|
Returns immediately:
|
|
@@ -170,26 +171,37 @@ npx makaron-cli project media <projectId> --json
|
|
|
170
171
|
|
|
171
172
|
This is project-scoped. `responses get <runId> --pick output` only returns artifacts from one run; `project media` returns the whole project timeline: original uploads, references, generated images, video snapshots, and editable compositions.
|
|
172
173
|
|
|
173
|
-
|
|
174
|
+
Typed external images and video ranges can be added without uploading the original media:
|
|
174
175
|
|
|
175
176
|
```bash
|
|
176
177
|
npx makaron-cli project media add <projectId> \
|
|
178
|
+
--type image \
|
|
179
|
+
--source-url "https://cdn.example.com/product.jpg" \
|
|
180
|
+
--description "Hero product image"
|
|
181
|
+
|
|
182
|
+
npx makaron-cli project media add <projectId> \
|
|
183
|
+
--type video \
|
|
177
184
|
--source-url "https://cdn.example.com/source.mp4" \
|
|
178
185
|
--start 12.5 --end 19 \
|
|
179
186
|
--description "Racket frame molding"
|
|
180
187
|
|
|
181
188
|
# Batch form: a JSON array or {"clips": [...]}
|
|
182
|
-
npx makaron-cli project media add <projectId> --input
|
|
189
|
+
npx makaron-cli project media add <projectId> --input media.json --json
|
|
183
190
|
```
|
|
184
191
|
|
|
185
|
-
|
|
192
|
+
Every item must declare `type` as `image` or `video`. Images contain
|
|
193
|
+
`source_url + type + description` and do not have a time range. Videos contain
|
|
194
|
+
`source_url + type + start + end + description`; their ranges remain
|
|
195
|
+
non-destructive metadata, and Remotion must trim the original URL to those exact
|
|
196
|
+
source bounds. The returned `<<<media_N>>>` is immediately usable by a later
|
|
197
|
+
Agent run.
|
|
186
198
|
Use `description` as the provider-neutral media-understanding field. Put any
|
|
187
199
|
already-known summary, editorial purpose, concrete scene evidence, confidence,
|
|
188
200
|
and limitations there. Makaron exposes the full description in Media List
|
|
189
201
|
context so the Agent can edit from it without repeating image/video analysis
|
|
190
202
|
unless a required detail is missing or uncertain.
|
|
191
203
|
|
|
192
|
-
For an agent-to-agent handoff, create the project, import the external
|
|
204
|
+
For an agent-to-agent handoff, create the project, import the typed external media,
|
|
193
205
|
and start the Agent in one command:
|
|
194
206
|
|
|
195
207
|
```bash
|
|
@@ -200,9 +212,9 @@ npx makaron-cli chat --project auto \
|
|
|
200
212
|
```
|
|
201
213
|
|
|
202
214
|
The manifest is a JSON array or `{ "title": "...", "clips": [...] }`. Every
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
215
|
+
item declares `type`. Images omit `start` and `end`; videos require both values
|
|
216
|
+
in seconds. Array order is edit order. It is validated before project creation
|
|
217
|
+
and supports up to 20 media items for one Makaron task. Batch planning remains
|
|
206
218
|
the upstream orchestrator's responsibility: convert each plan into one manifest
|
|
207
219
|
and start one independent Makaron task.
|
|
208
220
|
|
|
@@ -341,9 +353,12 @@ npx makaron-cli edit --image photo.jpg --ref style.jpg "match this style"
|
|
|
341
353
|
|
|
342
354
|
# Output to file
|
|
343
355
|
npx makaron-cli edit --image photo.jpg --out result.jpg "make it dramatic"
|
|
356
|
+
|
|
357
|
+
# Strict transparent PNG/WebP output through GPT Image 2 (fails rather than returning opaque)
|
|
358
|
+
npx makaron-cli edit --image-model openai --background transparent --out sticker.png "a magenta star sticker"
|
|
344
359
|
```
|
|
345
360
|
|
|
346
|
-
Options: `--image`, `--image-model gemini|gemini-lite|qwen|openai|pony|wai`, `--ref <file>` (up to 3), `--aspect <ratio>`, `--out <path
|
|
361
|
+
Options: `--image`, `--image-model gemini|gemini-lite|qwen|openai|pony|wai`, `--ref <file>` (up to 3), `--aspect <ratio>`, `--background auto|opaque|transparent`, `--out <path>`. Transparent output routes strictly to GPT Image 2 and is returned only when the provider supplies real PNG/WebP alpha.
|
|
347
362
|
|
|
348
363
|
### `video` — Standalone video tools (no project timeline)
|
|
349
364
|
|
|
@@ -354,18 +369,21 @@ npx makaron-cli video script --image img1.jpg "cinematic story"
|
|
|
354
369
|
# 2. Analyze a video (standalone, no timeline write)
|
|
355
370
|
npx makaron-cli analyze --video input.mp4 "describe the key actions and pacing"
|
|
356
371
|
|
|
357
|
-
# 3a. Submit
|
|
372
|
+
# 3a. Submit reference-to-video rendering (images must be public URLs from step 1 or uploaded)
|
|
358
373
|
npx makaron-cli video create --script "Shot 1 (5s): <<<image_1>>> ..." --image https://...jpg --duration 5 --video-model kling
|
|
359
374
|
npx makaron-cli video create --script "Shot 1 (5s): <<<image_1>>> slow cinematic push-in with native ambience" --image https://...jpg --duration 5 --video-model grok
|
|
375
|
+
npx makaron-cli video create --script "Keep both subjects recognizable as they enter the same studio" --image https://...jpg --image https://...webp --duration 5 --video-model grok --video-resolution 720p
|
|
360
376
|
npx makaron-cli video create --script "Shot 1 (15s): <<<image_1>>> and <<<image_2>>> build a neon one-person studio" --image https://...jpg --image https://...webp --duration 15 --video-model seedance-mini --video-resolution 480p --aspect 9:16
|
|
361
377
|
|
|
362
|
-
# 3b. Native SeeDance or MiniMax H3 text-to-video (no image required)
|
|
378
|
+
# 3b. Native SeeDance, Wan 3.0, or MiniMax H3 text-to-video (no image required)
|
|
363
379
|
npx makaron-cli video create --script "Shot 1 (5s): A neon one-person studio wakes at dawn" --duration 5 --video-model seedance-fast --aspect 16:9
|
|
364
380
|
npx makaron-cli video create --script "Shot 1 (15s): A premium creative editor comes alive" --duration 15 --video-model minimax-h3 --aspect 16:9
|
|
365
381
|
|
|
366
382
|
# 3c. Edit a video from a local file or public URL
|
|
367
383
|
npx makaron-cli video create --script "make it funny" --video input.mp4 --duration 5 --video-model seedance-fast
|
|
368
384
|
npx makaron-cli video create --script "make it warmer and cinematic" --video https://example.com/input.mp4 --duration 5 --video-model seedance --video-resolution 1080p
|
|
385
|
+
npx makaron-cli video create --script "turn the light warm gold but preserve the action" --video input.mp4 --video-model grok --operation edit
|
|
386
|
+
npx makaron-cli video create --script "continue the camera move into the next beat" --video input.mp4 --video-model grok --operation extend --duration 4
|
|
369
387
|
|
|
370
388
|
# 4. Check status
|
|
371
389
|
npx makaron-cli video status <taskId>
|
|
@@ -377,11 +395,13 @@ For project/timeline video editing, use:
|
|
|
377
395
|
npx makaron-cli chat --project <id|auto> --video input.mp4 -b "make it funny"
|
|
378
396
|
```
|
|
379
397
|
|
|
380
|
-
Options for `video create`: `--script "..."`, `--script-file <path>`, `--image <url>` (repeatable, up to the selected model limit), `--video <file|url>` and `--audio <file|url>` (repeatable where supported), `--duration <seconds>`, `--aspect 9:16|16:9|1:1`, `--video-model seedance-fast|seedance-mini|seedance|seedance-2.5|kling|grok|google-omni|minimax-h3|sync-lipsync-v3`, `--video-resolution auto|480p|720p|768p|1080p|2k|4k`. Default model is `seedance-fast`. SeeDance accepts native text-to-video with no image and integer output duration 4-15s (default 5s); `seedance-mini` supports 480p/720p and is best for cheaper drafts/multi-size tests
|
|
398
|
+
Options for `video create`: `--script "..."`, `--script-file <path>`, `--image <url>` (repeatable, up to the selected model limit), `--video <file|url>` and `--audio <file|url>` (repeatable where supported), `--voice <xai-preset-id>` (repeatable, Grok only), `--duration <seconds>`, `--aspect 9:16|16:9|1:1`, `--video-model seedance-fast|seedance-mini|seedance|seedance-2.5|wan-3.0|wan-3.0-pro|kling|grok|google-omni|minimax-h3|sync-lipsync-v3`, `--video-resolution auto|480p|720p|768p|1080p|2k|4k`. Default model is `seedance-fast`. SeeDance accepts native text-to-video with no image and integer output duration 4-15s (default 5s); every Seedance image input is submitted through reference-to-video, including one image. `seedance-mini` supports 480p/720p and is best for cheaper drafts/multi-size tests. Wan 3.0 Standard supports 480p/720p/1080p and Wan 3.0 Pro supports 1080p/2K/4K through MuleRouter. MiniMax H3 accepts native text-to-video, 4-15s output, public 768p/2k resolution, and up to 9 image, up to 3 video, and up to 3 audio feature references through Makaron Agent/chat; a single image keeps the `reference_image` role. `sync-lipsync-v3` requires exactly one video plus one MP3/WAV and preserves that replacement audio while aligning the mouth. H3 defaults to 768p; request 2k explicitly for maximum/final quality. Kling supports 5-15s. Grok generation uses `grok-imagine-video-1.5`: text-only generation supports 480p/720p/1080p, while any 1-7 image or preset voice input uses reference-to-video and is capped at 720p. Grok edit/extend uses `grok-imagine-video` internally under the same `grok` selector. Gemini Omni supports 3-10s fast image/video generation and editing with native generated audio; every image-only generation request uses `reference_to_video`, including a single image, with up to 6 images when no video reference is provided.
|
|
381
399
|
|
|
382
400
|
Seedance 2.5: use `--video-model seedance-2.5` for 4-30 second output at 480p/720p. `--image` accepts local files or URLs (up to 30), while repeatable `--video` and `--audio` accept up to 10 each. Use `--video-operation generate|edit|extend`, `--extend-direction forward|backward`, `--output-format mp4|mov`, `--web-search`, `--generated-audio` / `--no-generated-audio`, and `--relaxed-content-filter`. Edit/extend require a video reference. The Evolink route does not currently expose 4K output.
|
|
383
401
|
|
|
384
|
-
|
|
402
|
+
Wan 3.0: use `--video-model wan-3.0` for MuleRouter Standard at 480p/720p/1080p, or `--video-model wan-3.0-pro` for MuleRouter Pro super-resolution at 1080p/2K/4K. Both support 2-30 second generation with up to 10 images, 5 videos, and 5 audio references. Use generation mode with feature references; typed edit/extend and `--relaxed-content-filter` are not supported.
|
|
403
|
+
|
|
404
|
+
Video edit model behavior: `--video-model kling --video` uses Kling base/direct edit internally; `--video-model seedance-fast --video`, `--video-model seedance-mini --video`, or `--video-model seedance --video` uses the SeeDance video-reference path and requires target <=15s, <=50MB, width/height 300-6000px, aspect ratio 0.4-2.5, and frame pixels 409,600-2,086,876. `--video-model minimax-h3 --video` uses H3 feature/reference mode: up to 3 video references totaling <=15s, each <=50MB with width/height 256-5760px and aspect ratio 0.4-2.5. `--video-model google-omni --video` uses Gemini Omni direct video editing and accepts one reference video in Makaron. Output duration is clamped to 3-10s. `--video-model grok --video --operation edit` accepts one MP4 up to 8.7s, retains duration/aspect, and caps output at 720p. `--operation extend` accepts one 2-15s MP4 and adds 2-10s (default 6s); the returned result includes the original plus extension.
|
|
385
405
|
|
|
386
406
|
### `music` — Music generation
|
|
387
407
|
|
|
@@ -497,7 +517,7 @@ send_message "All done!"
|
|
|
497
517
|
- One project = one conversation thread. All history is preserved.
|
|
498
518
|
- One active Agent Run at a time per project. A new message received while it is active is appended to that same Agent Run and processed at a durable work-unit boundary; it does not interrupt the execution or create a second owner for an in-progress Studio workflow.
|
|
499
519
|
- Multi-image: `create --image a.jpg --image b.jpg` or `chat --image ref.jpg`.
|
|
500
|
-
- Provider-generated videos can take 3-5 minutes; Grok
|
|
520
|
+
- Provider-generated videos can take 3-5 minutes; current Grok generation/edit probes are usually around 15-60 seconds; Gemini Omni is usually around 30-70 seconds plus Storage handoff. Remotion compositions should be converted with `materialize` / `responses get --materialize`, and timing should be read from `duration_seconds`, `render_seconds`, and `realtime_ratio`.
|
|
501
521
|
- Music takes ~60 seconds. Appears in output when done.
|
|
502
522
|
- Images are typically ready in 15-30 seconds.
|
|
503
523
|
- stdout is always machine-readable JSON/text. Human-friendly logs go to stderr.
|
package/bin/makaron.mjs
CHANGED
|
@@ -33,7 +33,10 @@ const CHAT_AGENT_MODELS = [
|
|
|
33
33
|
'gpt-5.6-terra',
|
|
34
34
|
'gpt-5.6-sol',
|
|
35
35
|
'gpt-5.6-luna',
|
|
36
|
-
'
|
|
36
|
+
'gpt-5.6-terra-codex-subscription',
|
|
37
|
+
'gpt-5.6-sol-codex-subscription',
|
|
38
|
+
'gpt-5.6-luna-codex-subscription',
|
|
39
|
+
'grok-4.6',
|
|
37
40
|
'deepseek-v4-pro',
|
|
38
41
|
];
|
|
39
42
|
|
|
@@ -62,6 +65,8 @@ const SEEDANCE_MIN_VIDEO_ASPECT = 0.4;
|
|
|
62
65
|
const SEEDANCE_MAX_VIDEO_ASPECT = 2.5;
|
|
63
66
|
const MINIMAX_H3_MIN_VIDEO_SIDE = 256;
|
|
64
67
|
const MINIMAX_H3_MAX_VIDEO_SIDE = 5760;
|
|
68
|
+
const MULEROUTER_WAN_MAX_VIDEO_SIDE = 4096;
|
|
69
|
+
const MULEROUTER_WAN_MAX_VIDEO_FILE_SIZE = 100 * 1024 * 1024;
|
|
65
70
|
|
|
66
71
|
function warnLegacyModelFlag(replacement) {
|
|
67
72
|
process.stderr.write(`⚠️ --model is deprecated here; use ${replacement}.\n`);
|
|
@@ -174,25 +179,19 @@ function readJsonInput(filePath) {
|
|
|
174
179
|
return JSON.parse(raw);
|
|
175
180
|
}
|
|
176
181
|
|
|
177
|
-
const
|
|
182
|
+
const MAX_MEDIA_MANIFEST_ITEMS = 20;
|
|
178
183
|
|
|
179
184
|
function normalizeMediaManifest(input) {
|
|
180
185
|
const manifest = Array.isArray(input) ? { clips: input } : input;
|
|
181
186
|
if (!manifest || typeof manifest !== 'object') {
|
|
182
|
-
throw new Error('Media manifest must be a JSON object or an array of
|
|
183
|
-
}
|
|
184
|
-
const rawRanges = Array.isArray(manifest.clips)
|
|
185
|
-
? manifest.clips
|
|
186
|
-
: Array.isArray(manifest.source_ranges)
|
|
187
|
-
? manifest.source_ranges
|
|
188
|
-
: Array.isArray(manifest.sourceRanges)
|
|
189
|
-
? manifest.sourceRanges
|
|
190
|
-
: null;
|
|
187
|
+
throw new Error('Media manifest must be a JSON object or an array of media items.');
|
|
188
|
+
}
|
|
189
|
+
const rawRanges = Array.isArray(manifest.clips) ? manifest.clips : null;
|
|
191
190
|
if (!rawRanges?.length) {
|
|
192
191
|
throw new Error('Media manifest must contain a non-empty clips array.');
|
|
193
192
|
}
|
|
194
|
-
if (rawRanges.length >
|
|
195
|
-
throw new Error(`Media manifest supports at most ${
|
|
193
|
+
if (rawRanges.length > MAX_MEDIA_MANIFEST_ITEMS) {
|
|
194
|
+
throw new Error(`Media manifest supports at most ${MAX_MEDIA_MANIFEST_ITEMS} media items per Makaron task.`);
|
|
196
195
|
}
|
|
197
196
|
|
|
198
197
|
const sourceRanges = rawRanges.map((raw, index) => {
|
|
@@ -207,8 +206,19 @@ function normalizeMediaManifest(input) {
|
|
|
207
206
|
if (!['http:', 'https:'].includes(parsed.protocol)) {
|
|
208
207
|
throw new Error(`clips[${index}].source_url must use HTTP or HTTPS.`);
|
|
209
208
|
}
|
|
210
|
-
const
|
|
211
|
-
|
|
209
|
+
const declaredType = raw.type;
|
|
210
|
+
if (declaredType !== 'image' && declaredType !== 'video') {
|
|
211
|
+
throw new Error(`clips[${index}].type must be image or video.`);
|
|
212
|
+
}
|
|
213
|
+
const description = typeof raw.description === 'string' ? raw.description.trim() : '';
|
|
214
|
+
if (declaredType === 'image') {
|
|
215
|
+
if (raw.start !== undefined || raw.end !== undefined || raw.start_sec !== undefined || raw.end_sec !== undefined) {
|
|
216
|
+
throw new Error(`clips[${index}] image items must not include start or end.`);
|
|
217
|
+
}
|
|
218
|
+
return { source_url: sourceUrl, type: 'image', description };
|
|
219
|
+
}
|
|
220
|
+
const start = Number(raw.start);
|
|
221
|
+
const end = Number(raw.end);
|
|
212
222
|
if (!Number.isFinite(start) || start < 0) {
|
|
213
223
|
throw new Error(`clips[${index}].start must be a finite number >= 0.`);
|
|
214
224
|
}
|
|
@@ -217,9 +227,10 @@ function normalizeMediaManifest(input) {
|
|
|
217
227
|
}
|
|
218
228
|
return {
|
|
219
229
|
source_url: sourceUrl,
|
|
230
|
+
type: declaredType,
|
|
220
231
|
start,
|
|
221
232
|
end,
|
|
222
|
-
description
|
|
233
|
+
description,
|
|
223
234
|
};
|
|
224
235
|
});
|
|
225
236
|
|
|
@@ -447,17 +458,19 @@ Options:
|
|
|
447
458
|
--image <file|url> Attach a reference image or screenshot. Repeatable.
|
|
448
459
|
--video <file|url> Attach a video to the project timeline. Repeatable.
|
|
449
460
|
--audio <file|url> Attach a song, beat, or voice reference. MP3/WAV, repeatable.
|
|
450
|
-
--media-manifest <file|-> Import
|
|
461
|
+
--media-manifest <file|-> Import typed image/video media before this run.
|
|
451
462
|
--skill <id|label|name> Use an installed skill or auto-install a matched marketplace skill.
|
|
452
463
|
--agent-model <id> Agent LLM only: auto, gpt-5.6-terra, gpt-5.6-sol,
|
|
453
|
-
gpt-5.6-luna, grok-4.
|
|
464
|
+
gpt-5.6-luna, grok-4.6, deepseek-v4-pro, or a
|
|
465
|
+
gpt-5.6-*-codex-subscription personal-plan route.
|
|
454
466
|
--background, -b Submit and print a runId.
|
|
455
467
|
--json Output structured JSON.
|
|
456
468
|
--stream Legacy live SSE stream.
|
|
457
469
|
--help, -h Show this help.
|
|
458
470
|
|
|
459
|
-
Agent LLM defaults to auto (
|
|
460
|
-
|
|
471
|
+
Agent LLM defaults to auto (GPT-5.6 Terra; the account owner uses the personal
|
|
472
|
+
Codex plan). Base GPT-5.6 ids select Azure API; append -codex-subscription to
|
|
473
|
+
select the personal plan explicitly. Image/video model routing stays automatic in chat.
|
|
461
474
|
|
|
462
475
|
What you can ask:
|
|
463
476
|
Image edit
|
|
@@ -489,6 +502,9 @@ What you can ask:
|
|
|
489
502
|
Compare Agent LLMs with identical inputs
|
|
490
503
|
makaron chat --project auto --agent-model deepseek-v4-pro -b --json "make a 20s badminton video"
|
|
491
504
|
|
|
505
|
+
Force the personal Codex plan
|
|
506
|
+
makaron chat --project auto --agent-model gpt-5.6-sol-codex-subscription -b --json "reply with the active model"
|
|
507
|
+
|
|
492
508
|
Music
|
|
493
509
|
makaron chat --project <id> "add calm piano background music"
|
|
494
510
|
|
|
@@ -1031,7 +1047,10 @@ async function addProjectMediaSourceRanges(baseUrl, headers, projectId, ranges,
|
|
|
1031
1047
|
}
|
|
1032
1048
|
if (!opts.silent) {
|
|
1033
1049
|
for (const item of data.media || []) {
|
|
1034
|
-
|
|
1050
|
+
const range = item.type === 'video' && Number.isFinite(item.start_sec) && Number.isFinite(item.end_sec)
|
|
1051
|
+
? ` ${formatSeconds(item.start_sec)}-${formatSeconds(item.end_sec)}s`
|
|
1052
|
+
: '';
|
|
1053
|
+
console.log(`${item.ref} [${item.type || 'media'}] ${item.source_url}${range}${item.created ? '' : ' (existing)'}`);
|
|
1035
1054
|
}
|
|
1036
1055
|
}
|
|
1037
1056
|
return data;
|
|
@@ -1787,7 +1806,22 @@ function saveMcpImage(result, outputPath) {
|
|
|
1787
1806
|
const imageBlock = content.find(c => c.type === 'image');
|
|
1788
1807
|
if (textBlock) process.stderr.write(`${textBlock.text}\n`);
|
|
1789
1808
|
if (imageBlock) {
|
|
1790
|
-
const
|
|
1809
|
+
const extension = imageBlock.mimeType === 'image/png'
|
|
1810
|
+
? 'png'
|
|
1811
|
+
: imageBlock.mimeType === 'image/webp'
|
|
1812
|
+
? 'webp'
|
|
1813
|
+
: 'jpg';
|
|
1814
|
+
let out = outputPath || `makaron-output-${Date.now()}.${extension}`;
|
|
1815
|
+
if (outputPath) {
|
|
1816
|
+
const requestedExtension = path.extname(outputPath).slice(1).toLowerCase();
|
|
1817
|
+
const compatible = extension === 'jpg'
|
|
1818
|
+
? ['jpg', 'jpeg'].includes(requestedExtension)
|
|
1819
|
+
: requestedExtension === extension;
|
|
1820
|
+
if (!compatible) {
|
|
1821
|
+
out = `${outputPath.slice(0, outputPath.length - path.extname(outputPath).length)}.${extension}`;
|
|
1822
|
+
process.stderr.write(`Output is ${imageBlock.mimeType}; saving as ${out} so bytes and filename agree.\n`);
|
|
1823
|
+
}
|
|
1824
|
+
}
|
|
1791
1825
|
fs.writeFileSync(out, Buffer.from(imageBlock.data, 'base64'));
|
|
1792
1826
|
console.log(out);
|
|
1793
1827
|
return out;
|
|
@@ -1838,8 +1872,10 @@ Commands:
|
|
|
1838
1872
|
credits Show current credit balance
|
|
1839
1873
|
list (ls) List all projects
|
|
1840
1874
|
project media <projectId> --json List timeline media for a project
|
|
1841
|
-
project media add <projectId> --source-url <url>
|
|
1842
|
-
Add an external
|
|
1875
|
+
project media add <projectId> --type image --source-url <url>
|
|
1876
|
+
Add an external image without uploading it
|
|
1877
|
+
project media add <projectId> --type video --source-url <url> --start <n> --end <n>
|
|
1878
|
+
Add an external video range without uploading it
|
|
1843
1879
|
create --image <file> Create project from local image
|
|
1844
1880
|
create --image-url <url> Create project from URL
|
|
1845
1881
|
create --title "name" Create empty project (text-to-image)
|
|
@@ -1851,7 +1887,7 @@ Commands:
|
|
|
1851
1887
|
chat --project <id> --video <file> Attach video to conversation
|
|
1852
1888
|
chat --project <id> --audio <file> Attach song/beat/voice reference
|
|
1853
1889
|
chat --project auto --media-manifest <file> "message"
|
|
1854
|
-
Create, import external
|
|
1890
|
+
Create, import typed external media, and run Agent
|
|
1855
1891
|
chat --project <id> -b "message" Background: submit and print runId
|
|
1856
1892
|
chat --project <id> --stream "msg" Legacy: stream SSE in real-time
|
|
1857
1893
|
chat --project <id> --json "msg" Output structured JSON result
|
|
@@ -1961,11 +1997,12 @@ function printHelp(topic, subtopic) {
|
|
|
1961
1997
|
console.log('Usage: makaron credits [--json]');
|
|
1962
1998
|
} else if (topic === 'project' || topic === 'projects') {
|
|
1963
1999
|
if (subtopic === 'media') console.log(`Usage: makaron project media <projectId> [--json]
|
|
1964
|
-
makaron project media add <projectId> --source-url <url>
|
|
1965
|
-
makaron project media add <projectId> --
|
|
2000
|
+
makaron project media add <projectId> --type image --source-url <url> [--description <text>] [--json]
|
|
2001
|
+
makaron project media add <projectId> --type video --source-url <url> --start <n> --end <n> [--description <text>] [--json]
|
|
2002
|
+
makaron project media add <projectId> --input <media.json> [--json]`);
|
|
1966
2003
|
else console.log(`Project commands:
|
|
1967
2004
|
project media <projectId> --json List timeline media for a project
|
|
1968
|
-
project media add <projectId> ... Add external
|
|
2005
|
+
project media add <projectId> ... Add typed external image/video media
|
|
1969
2006
|
`);
|
|
1970
2007
|
} else if (topic === 'abort') {
|
|
1971
2008
|
console.log('Usage: makaron abort <runId>');
|
|
@@ -2005,19 +2042,21 @@ Not sure which built-in skill to use? Start with:
|
|
|
2005
2042
|
composition status <jobId> [--wait] [--json]
|
|
2006
2043
|
`);
|
|
2007
2044
|
} else if (topic === 'edit') {
|
|
2008
|
-
console.log('Usage: makaron edit [--image <file|url>] [--image-model gemini|gemini-lite|qwen|openai|pony|wai] [--skill enhance|creative|wild|captions] [--ref <file>] [--out <file>] "prompt"');
|
|
2045
|
+
console.log('Usage: makaron edit [--image <file|url>] [--image-model gemini|gemini-lite|qwen|openai|pony|wai] [--skill enhance|creative|wild|captions] [--ref <file>] [--aspect <ratio>] [--background auto|opaque|transparent] [--out <file>] "prompt"');
|
|
2009
2046
|
} else if (topic === 'analyze') {
|
|
2010
2047
|
console.log('Usage: makaron analyze --video <file|url> ["question"]');
|
|
2011
2048
|
} else if (topic === 'video') {
|
|
2012
2049
|
if (subtopic === 'script') console.log('Usage: makaron video script --image <file> [--image <file>] [--lang en|zh] "direction"');
|
|
2013
|
-
else if (subtopic === 'create') console.log('Usage: makaron video create --script "..." [--image <url> ...] [--video <url> ...] [--audio <url> ...] [--duration 10] [--aspect 9:16] [--video-model seedance-fast|seedance-mini|seedance|seedance-2.5|kling|grok|google-omni|minimax-h3|sync-lipsync-v3] [--operation generate|edit|extend] [--video-resolution auto|480p|720p|768p|1080p|2k|4k] [--keep-original-sound]');
|
|
2050
|
+
else if (subtopic === 'create') console.log('Usage: makaron video create --script "..." [--image <url> ...] [--video <url> ...] [--audio <url> ...] [--voice <xai-preset-id> ...] [--duration 10] [--aspect 9:16] [--video-model seedance-fast|seedance-mini|seedance|seedance-2.5|wan-3.0|wan-3.0-pro|kling|grok|google-omni|minimax-h3|sync-lipsync-v3] [--operation generate|edit|extend] [--video-resolution auto|480p|720p|768p|1080p|2k|4k] [--keep-original-sound]');
|
|
2014
2051
|
else if (subtopic === 'status') console.log('Usage: makaron video status <taskId> | --snapshot <snapshotId> [--wait]');
|
|
2015
2052
|
else console.log(`Video commands:
|
|
2016
2053
|
video script --image <file> [--image <file>] "direction" Write video script
|
|
2017
2054
|
video create --script "..." --video-model seedance-fast Native text-to-video (no image required)
|
|
2055
|
+
video create --script "..." --video-model wan-3.0 Wan 3.0 Standard via MuleRouter
|
|
2056
|
+
video create --script "..." --video-model wan-3.0-pro Wan 3.0 Pro super-resolution via MuleRouter
|
|
2018
2057
|
video create --script "..." --video-model minimax-h3 MiniMax H3 text-to-video (default 768P)
|
|
2019
2058
|
video create --script "..." --image <url> [--duration 10] Submit video task
|
|
2020
|
-
video create --script "..." --video <
|
|
2059
|
+
video create --script "..." --video <file|url> --video-model grok [--operation edit|extend] Edit or extend one MP4 with Grok
|
|
2021
2060
|
video create --script "Use the supplied audio" --video <url> --audio <url> --video-model sync-lipsync-v3 Lip-sync exact replacement audio
|
|
2022
2061
|
video status <taskId> Check video status
|
|
2023
2062
|
video status --snapshot <snapshotId> [--wait] Check v2 video snapshot
|
|
@@ -2269,12 +2308,12 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
|
|
|
2269
2308
|
);
|
|
2270
2309
|
importedManifestMedia = imported.media || [];
|
|
2271
2310
|
if (importedManifestMedia.length !== mediaManifest.sourceRanges.length) {
|
|
2272
|
-
process.stderr.write(`❌ Imported ${importedManifestMedia.length}/${mediaManifest.sourceRanges.length}
|
|
2311
|
+
process.stderr.write(`❌ Imported ${importedManifestMedia.length}/${mediaManifest.sourceRanges.length} media item(s); aborting run.\n`);
|
|
2273
2312
|
process.exit(1);
|
|
2274
2313
|
}
|
|
2275
2314
|
uploadedTurnMediaCount += importedManifestMedia.length;
|
|
2276
|
-
uploadedTurnVideoCount += importedManifestMedia.length;
|
|
2277
|
-
process.stderr.write(`📎 Imported ${importedManifestMedia.length} external
|
|
2315
|
+
uploadedTurnVideoCount += importedManifestMedia.filter(item => item.type === 'video').length;
|
|
2316
|
+
process.stderr.write(`📎 Imported ${importedManifestMedia.length} typed external media item(s) from media manifest\n`);
|
|
2278
2317
|
}
|
|
2279
2318
|
// Upload additional images to existing project
|
|
2280
2319
|
if (imageFileList.length > 0 || imageUrlList.length > 0) {
|
|
@@ -2432,9 +2471,12 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
|
|
|
2432
2471
|
...(importedManifestMedia.length ? {
|
|
2433
2472
|
importedMedia: importedManifestMedia.map(item => ({
|
|
2434
2473
|
ref: item.ref,
|
|
2474
|
+
type: item.type,
|
|
2435
2475
|
source_url: item.source_url,
|
|
2436
|
-
|
|
2437
|
-
|
|
2476
|
+
...(item.type === 'video' ? {
|
|
2477
|
+
start_sec: item.start_sec,
|
|
2478
|
+
end_sec: item.end_sec,
|
|
2479
|
+
} : {}),
|
|
2438
2480
|
})),
|
|
2439
2481
|
} : {}),
|
|
2440
2482
|
}));
|
|
@@ -2699,7 +2741,7 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
|
|
|
2699
2741
|
const jsonOutput = args.includes('--json');
|
|
2700
2742
|
if (args[2] === 'add') {
|
|
2701
2743
|
const projectId = args[3];
|
|
2702
|
-
if (!projectId) { console.error('Usage: makaron project media add <projectId> --source-url <url> --start <n> --end <n>'); process.exit(1); }
|
|
2744
|
+
if (!projectId) { console.error('Usage: makaron project media add <projectId> --type <image|video> --source-url <url> [--start <n> --end <n>]'); process.exit(1); }
|
|
2703
2745
|
const readOption = (name) => {
|
|
2704
2746
|
const index = args.indexOf(name);
|
|
2705
2747
|
return index >= 0 ? args[index + 1] : undefined;
|
|
@@ -2707,26 +2749,25 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
|
|
|
2707
2749
|
const inputPath = readOption('--input');
|
|
2708
2750
|
let ranges;
|
|
2709
2751
|
if (inputPath) {
|
|
2710
|
-
const
|
|
2711
|
-
ranges =
|
|
2752
|
+
const normalized = normalizeMediaManifest(readJsonInput(inputPath));
|
|
2753
|
+
ranges = normalized.sourceRanges;
|
|
2712
2754
|
} else {
|
|
2713
2755
|
const sourceUrl = readOption('--source-url');
|
|
2714
|
-
const
|
|
2715
|
-
const
|
|
2716
|
-
|
|
2717
|
-
|
|
2756
|
+
const type = readOption('--type');
|
|
2757
|
+
const start = readOption('--start');
|
|
2758
|
+
const end = readOption('--end');
|
|
2759
|
+
if (!sourceUrl || (type !== 'image' && type !== 'video')) {
|
|
2760
|
+
console.error('Provide --type <image|video> and --source-url <url>, or --input <manifest.json>.');
|
|
2718
2761
|
process.exit(1);
|
|
2719
2762
|
}
|
|
2720
|
-
|
|
2763
|
+
const normalized = normalizeMediaManifest([{
|
|
2721
2764
|
source_url: sourceUrl,
|
|
2722
|
-
|
|
2723
|
-
|
|
2765
|
+
type,
|
|
2766
|
+
...(start !== undefined ? { start } : {}),
|
|
2767
|
+
...(end !== undefined ? { end } : {}),
|
|
2724
2768
|
...(readOption('--description') ? { description: readOption('--description') } : {}),
|
|
2725
|
-
}];
|
|
2726
|
-
|
|
2727
|
-
if (!Array.isArray(ranges) || !ranges.length) {
|
|
2728
|
-
console.error('Input must contain a non-empty clips array.');
|
|
2729
|
-
process.exit(1);
|
|
2769
|
+
}]);
|
|
2770
|
+
ranges = normalized.sourceRanges;
|
|
2730
2771
|
}
|
|
2731
2772
|
await addProjectMediaSourceRanges(baseUrl, headers, projectId, ranges, { json: jsonOutput });
|
|
2732
2773
|
} else {
|
|
@@ -2737,7 +2778,7 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
|
|
|
2737
2778
|
} else {
|
|
2738
2779
|
console.log(`Project commands:
|
|
2739
2780
|
project media <projectId> --json List timeline media for a project
|
|
2740
|
-
project media add <projectId> ... Add external
|
|
2781
|
+
project media add <projectId> ... Add typed external image/video media
|
|
2741
2782
|
`);
|
|
2742
2783
|
}
|
|
2743
2784
|
} else if (command === 'abort') {
|
|
@@ -2775,11 +2816,19 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
|
|
|
2775
2816
|
editArgs.referenceImages.push(imageToArg(args[++i]));
|
|
2776
2817
|
}
|
|
2777
2818
|
else if (args[i] === '--aspect' && args[i + 1]) editArgs.aspectRatio = args[++i];
|
|
2819
|
+
else if (args[i] === '--background' && args[i + 1]) {
|
|
2820
|
+
const background = args[++i];
|
|
2821
|
+
if (!['auto', 'opaque', 'transparent'].includes(background)) {
|
|
2822
|
+
console.error('Invalid --background. Use auto, opaque, or transparent.');
|
|
2823
|
+
process.exit(1);
|
|
2824
|
+
}
|
|
2825
|
+
editArgs.background = background;
|
|
2826
|
+
}
|
|
2778
2827
|
else if (args[i] === '--out' && args[i + 1]) outputPath = args[++i];
|
|
2779
2828
|
else promptParts.push(args[i]);
|
|
2780
2829
|
}
|
|
2781
2830
|
editArgs.editPrompt = promptParts.join(' ');
|
|
2782
|
-
if (!editArgs.editPrompt) { console.error('Usage: makaron edit [--image <file|url>] [--image-model gemini|gemini-lite|qwen|openai|pony|wai] [--ref <file>] [--out <file>] "prompt"'); process.exit(1); }
|
|
2831
|
+
if (!editArgs.editPrompt) { console.error('Usage: makaron edit [--image <file|url>] [--image-model gemini|gemini-lite|qwen|openai|pony|wai] [--ref <file>] [--aspect <ratio>] [--background auto|opaque|transparent] [--out <file>] "prompt"'); process.exit(1); }
|
|
2783
2832
|
process.stderr.write('🎨 Generating...\n');
|
|
2784
2833
|
const result = await callMcpTool(baseUrl, headers, 'makaron_edit_image', editArgs);
|
|
2785
2834
|
saveMcpImage(result, outputPath);
|
|
@@ -2814,9 +2863,10 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
|
|
|
2814
2863
|
if (text) console.log(text);
|
|
2815
2864
|
|
|
2816
2865
|
} else if (sub === 'create') {
|
|
2817
|
-
|
|
2866
|
+
let images = [];
|
|
2818
2867
|
const videos = [];
|
|
2819
2868
|
const audios = [];
|
|
2869
|
+
const referenceVoices = [];
|
|
2820
2870
|
let script = '', duration = undefined, aspectRatio = undefined, videoModel = undefined, videoResolution = undefined, wait = false;
|
|
2821
2871
|
let keepOriginalSound = false, videoOperation = undefined, extendDirection = undefined, outputFormat = undefined;
|
|
2822
2872
|
let generateAudio = undefined, contentFilter = undefined, webSearch = false;
|
|
@@ -2824,6 +2874,7 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
|
|
|
2824
2874
|
if (args[i] === '--image' && args[i + 1]) images.push(args[++i]);
|
|
2825
2875
|
else if (args[i] === '--video' && args[i + 1]) videos.push(args[++i]);
|
|
2826
2876
|
else if (args[i] === '--audio' && args[i + 1]) audios.push(args[++i]);
|
|
2877
|
+
else if (args[i] === '--voice' && args[i + 1]) referenceVoices.push(args[++i]);
|
|
2827
2878
|
else if (args[i] === '--script' && args[i + 1]) script = args[++i];
|
|
2828
2879
|
else if (args[i] === '--script-file' && args[i + 1]) script = fs.readFileSync(args[++i], 'utf-8');
|
|
2829
2880
|
else if (args[i] === '--duration' && args[i + 1]) duration = Number(args[++i]);
|
|
@@ -2849,27 +2900,43 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
|
|
|
2849
2900
|
}
|
|
2850
2901
|
else if (args[i] === '--wait') wait = true;
|
|
2851
2902
|
}
|
|
2852
|
-
const selectedVideoModel =
|
|
2903
|
+
const selectedVideoModel = ['wan3', 'wan3.0', 'wan30', 'wan-3'].includes(videoModel)
|
|
2904
|
+
? 'wan-3.0'
|
|
2905
|
+
: ['wan3-pro', 'wan3.0-pro', 'wan30-pro', 'wan-3-pro', 'berry-1.0-pro'].includes(videoModel)
|
|
2906
|
+
? 'wan-3.0-pro'
|
|
2907
|
+
: (videoModel || 'seedance-fast');
|
|
2853
2908
|
const isSeedance25 = selectedVideoModel === 'seedance-2.5';
|
|
2909
|
+
const isWan30 = selectedVideoModel === 'wan-3.0' || selectedVideoModel === 'wan-3.0-pro';
|
|
2854
2910
|
const isSeedanceModel = selectedVideoModel === 'seedance-fast' || selectedVideoModel === 'seedance-mini' || selectedVideoModel === 'seedance' || isSeedance25;
|
|
2855
2911
|
const isMinimaxH3 = selectedVideoModel === 'minimax-h3';
|
|
2912
|
+
const isGrok = selectedVideoModel === 'grok';
|
|
2913
|
+
const isGoogleOmni = selectedVideoModel === 'google-omni';
|
|
2856
2914
|
const isSyncLipsync = selectedVideoModel === 'sync-lipsync-v3';
|
|
2857
|
-
const supportsNativeTextToVideo = isSeedanceModel || isMinimaxH3;
|
|
2858
|
-
if (!script || (!images.length && !videos.length && !audios.length && !supportsNativeTextToVideo)) {
|
|
2859
|
-
console.error('Usage: makaron video create --script "..." [--image <url>] [--video <file|url>] [--audio <file|url>] [--duration 30] [--video-model seedance-2.5|minimax-h3]');
|
|
2915
|
+
const supportsNativeTextToVideo = isSeedanceModel || isWan30 || isMinimaxH3 || isGrok || isGoogleOmni;
|
|
2916
|
+
if (!script || (!images.length && !videos.length && !audios.length && !referenceVoices.length && !supportsNativeTextToVideo)) {
|
|
2917
|
+
console.error('Usage: makaron video create --script "..." [--image <url>] [--video <file|url>] [--audio <file|url>] [--duration 30] [--video-model seedance-2.5|wan-3.0|wan-3.0-pro|minimax-h3]');
|
|
2860
2918
|
process.exit(1);
|
|
2861
2919
|
}
|
|
2862
2920
|
if (isSeedance25 && images.length > 30) { console.error('Seedance 2.5 supports at most 30 image references.'); process.exit(1); }
|
|
2863
2921
|
if (isSeedance25 && videos.length > 10) { console.error('Seedance 2.5 supports at most 10 video references.'); process.exit(1); }
|
|
2864
2922
|
if (isSeedance25 && audios.length > 10) { console.error('Seedance 2.5 supports at most 10 audio references.'); process.exit(1); }
|
|
2923
|
+
if (isWan30 && images.length > 10) { console.error('Wan 3.0 supports at most 10 image references.'); process.exit(1); }
|
|
2924
|
+
if (isWan30 && videos.length > 5) { console.error('Wan 3.0 supports at most 5 video references.'); process.exit(1); }
|
|
2925
|
+
if (isWan30 && audios.length > 5) { console.error('Wan 3.0 supports at most 5 audio references.'); process.exit(1); }
|
|
2865
2926
|
if (isMinimaxH3 && images.length > 9) { console.error('MiniMax H3 supports at most 9 image references.'); process.exit(1); }
|
|
2866
2927
|
if (isMinimaxH3 && videos.length > 3) { console.error('MiniMax H3 supports at most 3 video references.'); process.exit(1); }
|
|
2867
2928
|
if (isMinimaxH3 && audios.length > 3) { console.error('MiniMax H3 supports at most 3 audio references.'); process.exit(1); }
|
|
2929
|
+
if (isGrok && images.length > 7) { console.error('Grok Imagine Video 1.5 supports at most 7 image references.'); process.exit(1); }
|
|
2930
|
+
if (isGrok && videos.length > 1) { console.error('Grok video edit/extend accepts exactly one source video.'); process.exit(1); }
|
|
2931
|
+
if (isGrok && referenceVoices.length > 3) { console.error('Grok Imagine Video 1.5 supports at most 3 preset voices.'); process.exit(1); }
|
|
2932
|
+
if (!isGrok && referenceVoices.length) { console.error('--voice is currently supported only with --video-model grok.'); process.exit(1); }
|
|
2868
2933
|
if (isSyncLipsync && (images.length !== 0 || videos.length !== 1 || audios.length !== 1)) { console.error('Sync Lipsync v3 requires exactly one --video and one --audio, with no --image.'); process.exit(1); }
|
|
2869
2934
|
if (isSyncLipsync && !/<<<audio_1>>>/i.test(script)) {
|
|
2870
2935
|
script += '\nUse <<<audio_1>>> as the exact replacement soundtrack.';
|
|
2871
2936
|
}
|
|
2872
2937
|
if (videoOperation && !['generate', 'edit', 'extend'].includes(videoOperation)) { console.error('--video-operation must be generate, edit, or extend.'); process.exit(1); }
|
|
2938
|
+
if (isWan30 && videoOperation && videoOperation !== 'generate') { console.error('Wan 3.0 supports generation with feature references, not typed edit or extend.'); process.exit(1); }
|
|
2939
|
+
if (!isSeedance25 && contentFilter === false) { console.error('--relaxed-content-filter is only supported with --video-model seedance-2.5.'); process.exit(1); }
|
|
2873
2940
|
if (extendDirection && !['forward', 'backward'].includes(extendDirection)) { console.error('--extend-direction must be forward or backward.'); process.exit(1); }
|
|
2874
2941
|
if (outputFormat && !['mp4', 'mov'].includes(outputFormat)) { console.error('--output-format must be mp4 or mov.'); process.exit(1); }
|
|
2875
2942
|
|
|
@@ -2878,9 +2945,11 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
|
|
|
2878
2945
|
process.exit(1);
|
|
2879
2946
|
}
|
|
2880
2947
|
|
|
2948
|
+
const inferredOperation = videoOperation || ((isSeedance25 || isGrok) && videos.length ? 'edit' : 'generate');
|
|
2881
2949
|
let providerMaxDuration = isSeedance25 ? SEEDANCE25_MAX_VIDEO_REFERENCE_DURATION : MAX_VIDEO_PROVIDER_REFERENCE_DURATION;
|
|
2950
|
+
if (isGrok) providerMaxDuration = inferredOperation === 'edit' ? 8.7 : 15;
|
|
2882
2951
|
if (isSyncLipsync) providerMaxDuration = 60;
|
|
2883
|
-
const providerMaxPixels = isSyncLipsync || isMinimaxH3 ? Infinity : isSeedance25 ? SEEDANCE25_MAX_VIDEO_FRAME_PIXELS : MAX_VIDEO_FRAME_PIXELS;
|
|
2952
|
+
const providerMaxPixels = isSyncLipsync || isMinimaxH3 || isWan30 ? Infinity : isSeedance25 ? SEEDANCE25_MAX_VIDEO_FRAME_PIXELS : MAX_VIDEO_FRAME_PIXELS;
|
|
2884
2953
|
const localImages = images.filter(image => !isHttpUrl(image));
|
|
2885
2954
|
if (localImages.length) {
|
|
2886
2955
|
const uploadedImages = await uploadImageFilesViaSignedUrl(baseUrl, headers, undefined, localImages);
|
|
@@ -2895,13 +2964,21 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
|
|
|
2895
2964
|
maxDuration: providerMaxDuration,
|
|
2896
2965
|
durationTolerance: MAX_VIDEO_PROVIDER_REFERENCE_DURATION_TOLERANCE,
|
|
2897
2966
|
maxFramePixels: providerMaxPixels,
|
|
2898
|
-
maxFileSize: isSeedance25 || isSyncLipsync ? 200 * 1024 * 1024 : MAX_VIDEO_UPLOAD_FILE_SIZE,
|
|
2899
|
-
...(
|
|
2967
|
+
maxFileSize: isWan30 ? MULEROUTER_WAN_MAX_VIDEO_FILE_SIZE : isSeedance25 || isSyncLipsync ? 200 * 1024 * 1024 : MAX_VIDEO_UPLOAD_FILE_SIZE,
|
|
2968
|
+
...(isGrok ? {
|
|
2969
|
+
allowedExtensions: ['mp4'],
|
|
2970
|
+
} : selectedVideoModel === 'minimax-h3' ? {
|
|
2900
2971
|
allowedExtensions: ['mp4', 'mov'],
|
|
2901
2972
|
minSide: MINIMAX_H3_MIN_VIDEO_SIDE,
|
|
2902
2973
|
maxSide: MINIMAX_H3_MAX_VIDEO_SIDE,
|
|
2903
2974
|
minAspect: SEEDANCE_MIN_VIDEO_ASPECT,
|
|
2904
2975
|
maxAspect: SEEDANCE_MAX_VIDEO_ASPECT,
|
|
2976
|
+
} : isWan30 ? {
|
|
2977
|
+
minSide: 240,
|
|
2978
|
+
maxSide: MULEROUTER_WAN_MAX_VIDEO_SIDE,
|
|
2979
|
+
minAspect: 0.125,
|
|
2980
|
+
maxAspect: 8,
|
|
2981
|
+
allowedExtensions: ['mp4', 'mov'],
|
|
2905
2982
|
} : isSeedanceModel ? {
|
|
2906
2983
|
minFramePixels: SEEDANCE_MIN_VIDEO_FRAME_PIXELS,
|
|
2907
2984
|
minSide: SEEDANCE_MIN_VIDEO_SIDE,
|
|
@@ -2930,21 +3007,22 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
|
|
|
2930
3007
|
}
|
|
2931
3008
|
// Standalone MCP tool (no project timeline write)
|
|
2932
3009
|
process.stderr.write('🎬 Submitting video...\n');
|
|
2933
|
-
const resolvedOperation =
|
|
3010
|
+
const resolvedOperation = inferredOperation;
|
|
2934
3011
|
const vArgs = isSyncLipsync
|
|
2935
3012
|
? { script, images, videoUrls, audioUrls, videoModel: selectedVideoModel, videoResolution }
|
|
2936
|
-
: isSeedance25
|
|
2937
|
-
? { script, images, videoUrls, audioUrls, videoModel: selectedVideoModel, videoResolution, operation: resolvedOperation, extendDirection, outputFormat, generateAudio, contentFilter, webSearch }
|
|
3013
|
+
: isSeedance25 || isWan30 || isGrok
|
|
3014
|
+
? { script, images, videoUrls, audioUrls, referenceVoiceIds: referenceVoices, videoModel: selectedVideoModel, videoResolution, operation: resolvedOperation, extendDirection, outputFormat, generateAudio, contentFilter, webSearch }
|
|
2938
3015
|
: isMinimaxH3
|
|
2939
3016
|
? { script, images, videoUrls, audioUrls, videoModel: selectedVideoModel, videoResolution }
|
|
2940
3017
|
: videoUrls[0]
|
|
2941
3018
|
? { videoUrl: videoUrls[0], editPrompt: script, images, videoModel: selectedVideoModel, videoResolution, referType: isSeedanceModel ? 'feature' : 'base' }
|
|
2942
3019
|
: { script, images, videoModel: selectedVideoModel, videoResolution };
|
|
3020
|
+
if (inputVideoMeta?.duration) vArgs.referenceVideoDuration = inputVideoMeta.duration;
|
|
2943
3021
|
const effectiveDuration = resolvedOperation === 'edit' ? undefined : duration || (inputVideoMeta?.duration ? Math.min(providerMaxDuration, Math.round(inputVideoMeta.duration)) : undefined);
|
|
2944
3022
|
if (effectiveDuration) vArgs.duration = effectiveDuration;
|
|
2945
3023
|
if (aspectRatio) vArgs.aspectRatio = aspectRatio;
|
|
2946
3024
|
if (keepOriginalSound && videoUrls.length && !isSeedance25) vArgs.keepOriginalSound = true;
|
|
2947
|
-
const result = await callMcpTool(baseUrl, headers, videoUrls.length && !isSeedance25 && !isMinimaxH3 && !isSyncLipsync ? 'makaron_edit_video' : 'makaron_create_video', vArgs);
|
|
3025
|
+
const result = await callMcpTool(baseUrl, headers, videoUrls.length && !isSeedance25 && !isWan30 && !isGrok && !isMinimaxH3 && !isSyncLipsync ? 'makaron_edit_video' : 'makaron_create_video', vArgs);
|
|
2948
3026
|
const text = result?.content?.find(c => c.type === 'text')?.text;
|
|
2949
3027
|
if (text) {
|
|
2950
3028
|
console.log(text);
|
|
@@ -2988,9 +3066,11 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
|
|
|
2988
3066
|
console.log(`Video commands:
|
|
2989
3067
|
video script --image <file> [--image <file>] "direction" Write video script
|
|
2990
3068
|
video create --script "..." --video-model seedance-fast Native text-to-video (no image required)
|
|
3069
|
+
video create --script "..." --video-model wan-3.0 Wan 3.0 Standard via MuleRouter
|
|
3070
|
+
video create --script "..." --video-model wan-3.0-pro Wan 3.0 Pro super-resolution via MuleRouter
|
|
2991
3071
|
video create --script "..." --video-model minimax-h3 MiniMax H3 text-to-video (default 768P)
|
|
2992
3072
|
video create --script "..." --image <url> [--duration 10] Submit video task
|
|
2993
|
-
video create --script "..." --video <
|
|
3073
|
+
video create --script "..." --video <file|url> --video-model grok [--operation edit|extend] Edit or extend one MP4 with Grok
|
|
2994
3074
|
video create --script "Use the supplied audio" --video <url> --audio <url> --video-model sync-lipsync-v3 Lip-sync exact replacement audio
|
|
2995
3075
|
video status <taskId> Check video status
|
|
2996
3076
|
video status --snapshot <snapshotId> [--wait] Check v2 video snapshot
|
package/package.json
CHANGED
package/skills/makaron/SKILL.md
CHANGED
|
@@ -85,10 +85,11 @@ npx makaron-cli chat --project auto --image photo.jpg --json -b "make it cinemat
|
|
|
85
85
|
npx makaron-cli chat --project auto --image img1.jpg --image img2.jpg --json -b "combine these"
|
|
86
86
|
```
|
|
87
87
|
|
|
88
|
-
`chat` routes image and video models automatically. Use `--agent-model` only when the user explicitly asks to select or compare the reasoning/tool-calling Agent LLM. Accepted values are
|
|
88
|
+
`chat` routes image and video models automatically. Use `--agent-model` only when the user explicitly asks to select or compare the reasoning/tool-calling Agent LLM. Accepted values are `auto`, the base model IDs (`gpt-5.6-terra`, `gpt-5.6-sol`, `gpt-5.6-luna`, `grok-4.6`, `deepseek-v4-pro`), and the personal-plan routes (`gpt-5.6-terra-codex-subscription`, `gpt-5.6-sol-codex-subscription`, `gpt-5.6-luna-codex-subscription`). For the configured owner, `auto` uses GPT-5.6 Terra through the personal Codex plan; base GPT-5.6 IDs select Azure API, while suffixed IDs explicitly select the personal plan. Never put an image or video model ID in `--agent-model`.
|
|
89
89
|
|
|
90
90
|
```bash
|
|
91
91
|
npx makaron-cli chat --project auto --agent-model deepseek-v4-pro --json -b "make a 20s badminton video"
|
|
92
|
+
npx makaron-cli chat --project auto --agent-model gpt-5.6-sol-codex-subscription --json -b "reply with the active model"
|
|
92
93
|
```
|
|
93
94
|
|
|
94
95
|
Returns immediately:
|
|
@@ -180,16 +181,17 @@ npx makaron-cli project media <projectId> --json
|
|
|
180
181
|
|
|
181
182
|
This is project-scoped. `responses get <runId> --pick output` only returns artifacts from one run; `project media` returns the whole project timeline: original uploads, references, generated images, video snapshots, and editable compositions.
|
|
182
183
|
|
|
183
|
-
Publish
|
|
184
|
+
Publish typed external images and video intervals directly into that Media List without uploading the original media:
|
|
184
185
|
|
|
185
186
|
```bash
|
|
186
|
-
npx makaron-cli project media add <projectId> --source-url "https://cdn.example.com/
|
|
187
|
-
npx makaron-cli project media add <projectId> --
|
|
187
|
+
npx makaron-cli project media add <projectId> --type image --source-url "https://cdn.example.com/product.jpg" --description "Hero product image"
|
|
188
|
+
npx makaron-cli project media add <projectId> --type video --source-url "https://cdn.example.com/source.mp4" --start 12.5 --end 19 --description "Racket frame molding"
|
|
189
|
+
npx makaron-cli project media add <projectId> --input media.json --json
|
|
188
190
|
```
|
|
189
191
|
|
|
190
|
-
The JSON input may be an array or `{ "clips": [...] }`.
|
|
192
|
+
The JSON input may be an array or `{ "clips": [...] }`. Every item declares `type` as `image` or `video`. Images have `source_url + type + description` and no time range. Videos have `source_url + type + start + end + description`; `start` and `end` are seconds. Array order is edit order and `source_url` is opaque. Do not add or request provider-specific identity fields. Put existing media understanding (summary, editorial purpose, scene evidence, confidence, and limitations) in `description`. Makaron reads that provider-neutral Media List field before deciding whether any additional image/video analysis is needed.
|
|
191
193
|
|
|
192
|
-
For one-call orchestration, use `chat --project auto --media-manifest plan.json`. Makaron validates the manifest, creates the project, imports its
|
|
194
|
+
For one-call orchestration, use `chat --project auto --media-manifest plan.json`. Makaron validates the manifest, creates the project, imports its media, and starts the Agent. If an upstream service returns multiple plans, the caller should start one independent Makaron task per plan instead of passing the provider-specific batch response into Makaron.
|
|
193
195
|
|
|
194
196
|
```bash
|
|
195
197
|
npx makaron-cli chat --project auto --media-manifest set-01.json --json -b "Make a 30-second 9:16 TikTok with English VO and captions"
|
|
@@ -292,9 +294,12 @@ npx makaron-cli edit --image photo.jpg --ref style.jpg "match this style"
|
|
|
292
294
|
|
|
293
295
|
# Output to file
|
|
294
296
|
npx makaron-cli edit --image photo.jpg --out result.jpg "make it dramatic"
|
|
297
|
+
|
|
298
|
+
# Strict transparent output through GPT Image 2
|
|
299
|
+
npx makaron-cli edit --image-model openai --background transparent --out sticker.png "a magenta star sticker"
|
|
295
300
|
```
|
|
296
301
|
|
|
297
|
-
Options: `--image`, `--image-model gemini|gemini-lite|qwen|openai|pony|wai`, `--ref <file>` (up to 3), `--aspect <ratio>`, `--out <path
|
|
302
|
+
Options: `--image`, `--image-model gemini|gemini-lite|qwen|openai|pony|wai`, `--ref <file>` (up to 3), `--aspect <ratio>`, `--background auto|opaque|transparent`, `--out <path>`. Transparent output routes strictly to GPT Image 2 and fails instead of returning an opaque fallback.
|
|
298
303
|
|
|
299
304
|
### `video` — Standalone video tools (no project timeline)
|
|
300
305
|
|
|
@@ -305,11 +310,11 @@ npx makaron-cli video script --image img1.jpg "cinematic story"
|
|
|
305
310
|
# 2. Analyze a video (standalone, no timeline write)
|
|
306
311
|
npx makaron-cli analyze --video input.mp4 "describe the key actions and pacing"
|
|
307
312
|
|
|
308
|
-
# 3a. Submit
|
|
313
|
+
# 3a. Submit reference-to-video rendering (images must be public URLs from step 1 or uploaded)
|
|
309
314
|
npx makaron-cli video create --script "Shot 1 (5s): <<<image_1>>> ..." --image https://...jpg --duration 5 --video-model kling
|
|
310
315
|
npx makaron-cli video create --script "Shot 1 (15s): <<<image_1>>> and <<<image_2>>> build a neon one-person studio" --image https://...jpg --image https://...webp --duration 15 --video-model seedance-mini --video-resolution 480p --aspect 9:16
|
|
311
316
|
|
|
312
|
-
# 3b. Native SeeDance or MiniMax H3 text-to-video (no image required)
|
|
317
|
+
# 3b. Native SeeDance, Wan 3.0, or MiniMax H3 text-to-video (no image required)
|
|
313
318
|
npx makaron-cli video create --script "Shot 1 (5s): A neon one-person studio wakes at dawn" --duration 5 --video-model seedance-fast --aspect 16:9
|
|
314
319
|
npx makaron-cli video create --script "Shot 1 (15s): A premium creative editor comes alive" --duration 15 --video-model minimax-h3 --aspect 16:9
|
|
315
320
|
|
|
@@ -327,11 +332,15 @@ npx makaron-cli video status <taskId>
|
|
|
327
332
|
npx makaron-cli chat --project <id|auto> --video input.mp4 -b "make it funny"
|
|
328
333
|
```
|
|
329
334
|
|
|
330
|
-
Options for `video create`: `--script "..."`, `--script-file <path>`, `--image <url>` (repeatable, up to the selected model limit), `--video <file|url>` and `--audio <file|url>` (repeatable where supported), `--duration <seconds>`, `--aspect 9:16|16:9|1:1`, `--video-model seedance-fast|seedance-mini|seedance|seedance-2.5|kling|grok|google-omni|minimax-h3|sync-lipsync-v3`, `--video-resolution auto|480p|720p|768p|1080p|2k|4k`. Default model is `seedance-fast`. SeeDance accepts native text-to-video with no image and integer output duration 4-15s (default 5s); `seedance-mini` supports 480p/720p and is best for cheaper drafts/multi-size tests
|
|
335
|
+
Options for `video create`: `--script "..."`, `--script-file <path>`, `--image <url>` (repeatable, up to the selected model limit), `--video <file|url>` and `--audio <file|url>` (repeatable where supported), `--voice <xai-preset-id>` (repeatable, Grok only), `--duration <seconds>`, `--aspect 9:16|16:9|1:1`, `--video-model seedance-fast|seedance-mini|seedance|seedance-2.5|wan-3.0|wan-3.0-pro|kling|grok|google-omni|minimax-h3|sync-lipsync-v3`, `--video-resolution auto|480p|720p|768p|1080p|2k|4k`. Default model is `seedance-fast`. SeeDance accepts native text-to-video with no image and integer output duration 4-15s (default 5s); every Seedance image input uses reference-to-video, including one image. `seedance-mini` supports 480p/720p and is best for cheaper drafts/multi-size tests. Wan 3.0 Standard supports 480p/720p/1080p and Wan 3.0 Pro supports 1080p/2K/4K through MuleRouter. MiniMax H3 accepts native text-to-video, 4-15s output, public 768p/2k resolution, and up to 9 image, up to 3 video, and up to 3 audio feature references through Makaron Agent/chat; a single image keeps the `reference_image` role. `sync-lipsync-v3` requires exactly one video plus one MP3/WAV and preserves that replacement audio while aligning the mouth. H3 defaults to 768p; request 2k explicitly for maximum/final quality. Kling supports 5-15s. Grok text-only generation supports 480p/720p/1080p; any 1-7 image or preset voice input uses reference-to-video and is capped at 720p. Grok edit/extend uses `grok-imagine-video` internally. Gemini Omni image-only generation always uses `reference_to_video`, including one image, with up to 6 images when no video reference is provided.
|
|
336
|
+
|
|
337
|
+
Provider integration contract: every image passed to video generation is a feature reference by default, even when there is exactly one image. Never infer image-to-video/first-frame mode from image count. A first-frame workflow may be added only as a separately declared model capability and an explicit caller request.
|
|
331
338
|
|
|
332
339
|
Seedance 2.5 uses `--video-model seedance-2.5` and supports 4-30s at 480p/720p, up to 30 images + 10 videos + 10 audios, repeatable local/URL references, `--video-operation generate|edit|extend`, `--extend-direction`, `--output-format mp4|mov`, and `--web-search`. The Evolink route does not currently expose 4K output.
|
|
333
340
|
|
|
334
|
-
|
|
341
|
+
Wan 3.0 uses `--video-model wan-3.0` for MuleRouter Standard at 480p/720p/1080p, or `--video-model wan-3.0-pro` for MuleRouter Pro super-resolution at 1080p/2K/4K. Both support 2-30s generation, up to 10 images + 5 videos + 5 audios, and native audio. Use generation mode with feature references; typed edit/extend and the relaxed content-filter flag are not supported.
|
|
342
|
+
|
|
343
|
+
Video edit model behavior: `--video-model kling --video` uses Kling base/direct edit internally; `--video-model seedance-fast --video`, `--video-model seedance-mini --video`, or `--video-model seedance --video` uses the SeeDance video-reference path and requires target <=15s, <=50MB, width/height 300-6000px, aspect ratio 0.4-2.5, and frame pixels 409,600-2,086,876. `--video-model minimax-h3 --video` uses H3 feature/reference mode: up to 3 video references totaling <=15s, each <=50MB with width/height 256-5760px and aspect ratio 0.4-2.5. `--video-model google-omni --video` uses Gemini Omni direct video editing and accepts one reference video in Makaron. `--video-model grok --video --operation edit` accepts one MP4 up to 8.7s and caps output at 720p; `--operation extend` accepts one 2-15s MP4 and adds 2-10s.
|
|
335
344
|
|
|
336
345
|
### `music` — Music generation
|
|
337
346
|
|
|
@@ -465,7 +474,7 @@ send_message "All done!"
|
|
|
465
474
|
- One project = one conversation thread. All history is preserved.
|
|
466
475
|
- One active Agent Run at a time per project. A new message received while it is active is appended to that same Agent Run and processed at a durable work-unit boundary; it does not interrupt the execution or create a second owner for an in-progress Studio workflow.
|
|
467
476
|
- Multi-image: `create --image a.jpg --image b.jpg` or `chat --image ref.jpg`.
|
|
468
|
-
- Provider-generated videos can take 3-5 minutes; Grok
|
|
477
|
+
- Provider-generated videos can take 3-5 minutes; current Grok generation/edit probes are usually around 15-60 seconds; Gemini Omni is usually around 30-70 seconds plus Storage handoff. Remotion compositions should be converted with `materialize` / `responses get --materialize`, and timing should be read from `duration_seconds`, `render_seconds`, and `realtime_ratio`.
|
|
469
478
|
- Music takes ~60 seconds. Appears in output when done.
|
|
470
479
|
- Images are typically ready in 15-30 seconds.
|
|
471
480
|
- stdout is always machine-readable JSON/text. Human-friendly logs go to stderr.
|