makaron-cli 0.13.9 → 0.14.0
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 +22 -8
- package/bin/makaron.mjs +84 -47
- package/package.json +1 -1
- package/skills/makaron/SKILL.md +10 -6
package/README.md
CHANGED
|
@@ -170,26 +170,37 @@ npx makaron-cli project media <projectId> --json
|
|
|
170
170
|
|
|
171
171
|
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
172
|
|
|
173
|
-
|
|
173
|
+
Typed external images and video ranges can be added without uploading the original media:
|
|
174
174
|
|
|
175
175
|
```bash
|
|
176
176
|
npx makaron-cli project media add <projectId> \
|
|
177
|
+
--type image \
|
|
178
|
+
--source-url "https://cdn.example.com/product.jpg" \
|
|
179
|
+
--description "Hero product image"
|
|
180
|
+
|
|
181
|
+
npx makaron-cli project media add <projectId> \
|
|
182
|
+
--type video \
|
|
177
183
|
--source-url "https://cdn.example.com/source.mp4" \
|
|
178
184
|
--start 12.5 --end 19 \
|
|
179
185
|
--description "Racket frame molding"
|
|
180
186
|
|
|
181
187
|
# Batch form: a JSON array or {"clips": [...]}
|
|
182
|
-
npx makaron-cli project media add <projectId> --input
|
|
188
|
+
npx makaron-cli project media add <projectId> --input media.json --json
|
|
183
189
|
```
|
|
184
190
|
|
|
185
|
-
|
|
191
|
+
Every item must declare `type` as `image` or `video`. Images contain
|
|
192
|
+
`source_url + type + description` and do not have a time range. Videos contain
|
|
193
|
+
`source_url + type + start + end + description`; their ranges remain
|
|
194
|
+
non-destructive metadata, and Remotion must trim the original URL to those exact
|
|
195
|
+
source bounds. The returned `<<<media_N>>>` is immediately usable by a later
|
|
196
|
+
Agent run.
|
|
186
197
|
Use `description` as the provider-neutral media-understanding field. Put any
|
|
187
198
|
already-known summary, editorial purpose, concrete scene evidence, confidence,
|
|
188
199
|
and limitations there. Makaron exposes the full description in Media List
|
|
189
200
|
context so the Agent can edit from it without repeating image/video analysis
|
|
190
201
|
unless a required detail is missing or uncertain.
|
|
191
202
|
|
|
192
|
-
For an agent-to-agent handoff, create the project, import the external
|
|
203
|
+
For an agent-to-agent handoff, create the project, import the typed external media,
|
|
193
204
|
and start the Agent in one command:
|
|
194
205
|
|
|
195
206
|
```bash
|
|
@@ -200,9 +211,9 @@ npx makaron-cli chat --project auto \
|
|
|
200
211
|
```
|
|
201
212
|
|
|
202
213
|
The manifest is a JSON array or `{ "title": "...", "clips": [...] }`. Every
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
214
|
+
item declares `type`. Images omit `start` and `end`; videos require both values
|
|
215
|
+
in seconds. Array order is edit order. It is validated before project creation
|
|
216
|
+
and supports up to 20 media items for one Makaron task. Batch planning remains
|
|
206
217
|
the upstream orchestrator's responsibility: convert each plan into one manifest
|
|
207
218
|
and start one independent Makaron task.
|
|
208
219
|
|
|
@@ -341,9 +352,12 @@ npx makaron-cli edit --image photo.jpg --ref style.jpg "match this style"
|
|
|
341
352
|
|
|
342
353
|
# Output to file
|
|
343
354
|
npx makaron-cli edit --image photo.jpg --out result.jpg "make it dramatic"
|
|
355
|
+
|
|
356
|
+
# Strict transparent PNG/WebP output through GPT Image 2 (fails rather than returning opaque)
|
|
357
|
+
npx makaron-cli edit --image-model openai --background transparent --out sticker.png "a magenta star sticker"
|
|
344
358
|
```
|
|
345
359
|
|
|
346
|
-
Options: `--image`, `--image-model gemini|gemini-lite|qwen|openai|pony|wai`, `--ref <file>` (up to 3), `--aspect <ratio>`, `--out <path
|
|
360
|
+
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
361
|
|
|
348
362
|
### `video` — Standalone video tools (no project timeline)
|
|
349
363
|
|
package/bin/makaron.mjs
CHANGED
|
@@ -174,25 +174,19 @@ function readJsonInput(filePath) {
|
|
|
174
174
|
return JSON.parse(raw);
|
|
175
175
|
}
|
|
176
176
|
|
|
177
|
-
const
|
|
177
|
+
const MAX_MEDIA_MANIFEST_ITEMS = 20;
|
|
178
178
|
|
|
179
179
|
function normalizeMediaManifest(input) {
|
|
180
180
|
const manifest = Array.isArray(input) ? { clips: input } : input;
|
|
181
181
|
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;
|
|
182
|
+
throw new Error('Media manifest must be a JSON object or an array of media items.');
|
|
183
|
+
}
|
|
184
|
+
const rawRanges = Array.isArray(manifest.clips) ? manifest.clips : null;
|
|
191
185
|
if (!rawRanges?.length) {
|
|
192
186
|
throw new Error('Media manifest must contain a non-empty clips array.');
|
|
193
187
|
}
|
|
194
|
-
if (rawRanges.length >
|
|
195
|
-
throw new Error(`Media manifest supports at most ${
|
|
188
|
+
if (rawRanges.length > MAX_MEDIA_MANIFEST_ITEMS) {
|
|
189
|
+
throw new Error(`Media manifest supports at most ${MAX_MEDIA_MANIFEST_ITEMS} media items per Makaron task.`);
|
|
196
190
|
}
|
|
197
191
|
|
|
198
192
|
const sourceRanges = rawRanges.map((raw, index) => {
|
|
@@ -207,8 +201,19 @@ function normalizeMediaManifest(input) {
|
|
|
207
201
|
if (!['http:', 'https:'].includes(parsed.protocol)) {
|
|
208
202
|
throw new Error(`clips[${index}].source_url must use HTTP or HTTPS.`);
|
|
209
203
|
}
|
|
210
|
-
const
|
|
211
|
-
|
|
204
|
+
const declaredType = raw.type;
|
|
205
|
+
if (declaredType !== 'image' && declaredType !== 'video') {
|
|
206
|
+
throw new Error(`clips[${index}].type must be image or video.`);
|
|
207
|
+
}
|
|
208
|
+
const description = typeof raw.description === 'string' ? raw.description.trim() : '';
|
|
209
|
+
if (declaredType === 'image') {
|
|
210
|
+
if (raw.start !== undefined || raw.end !== undefined || raw.start_sec !== undefined || raw.end_sec !== undefined) {
|
|
211
|
+
throw new Error(`clips[${index}] image items must not include start or end.`);
|
|
212
|
+
}
|
|
213
|
+
return { source_url: sourceUrl, type: 'image', description };
|
|
214
|
+
}
|
|
215
|
+
const start = Number(raw.start);
|
|
216
|
+
const end = Number(raw.end);
|
|
212
217
|
if (!Number.isFinite(start) || start < 0) {
|
|
213
218
|
throw new Error(`clips[${index}].start must be a finite number >= 0.`);
|
|
214
219
|
}
|
|
@@ -217,9 +222,10 @@ function normalizeMediaManifest(input) {
|
|
|
217
222
|
}
|
|
218
223
|
return {
|
|
219
224
|
source_url: sourceUrl,
|
|
225
|
+
type: declaredType,
|
|
220
226
|
start,
|
|
221
227
|
end,
|
|
222
|
-
description
|
|
228
|
+
description,
|
|
223
229
|
};
|
|
224
230
|
});
|
|
225
231
|
|
|
@@ -447,7 +453,7 @@ Options:
|
|
|
447
453
|
--image <file|url> Attach a reference image or screenshot. Repeatable.
|
|
448
454
|
--video <file|url> Attach a video to the project timeline. Repeatable.
|
|
449
455
|
--audio <file|url> Attach a song, beat, or voice reference. MP3/WAV, repeatable.
|
|
450
|
-
--media-manifest <file|-> Import
|
|
456
|
+
--media-manifest <file|-> Import typed image/video media before this run.
|
|
451
457
|
--skill <id|label|name> Use an installed skill or auto-install a matched marketplace skill.
|
|
452
458
|
--agent-model <id> Agent LLM only: auto, gpt-5.6-terra, gpt-5.6-sol,
|
|
453
459
|
gpt-5.6-luna, grok-4.5, or deepseek-v4-pro.
|
|
@@ -1031,7 +1037,10 @@ async function addProjectMediaSourceRanges(baseUrl, headers, projectId, ranges,
|
|
|
1031
1037
|
}
|
|
1032
1038
|
if (!opts.silent) {
|
|
1033
1039
|
for (const item of data.media || []) {
|
|
1034
|
-
|
|
1040
|
+
const range = item.type === 'video' && Number.isFinite(item.start_sec) && Number.isFinite(item.end_sec)
|
|
1041
|
+
? ` ${formatSeconds(item.start_sec)}-${formatSeconds(item.end_sec)}s`
|
|
1042
|
+
: '';
|
|
1043
|
+
console.log(`${item.ref} [${item.type || 'media'}] ${item.source_url}${range}${item.created ? '' : ' (existing)'}`);
|
|
1035
1044
|
}
|
|
1036
1045
|
}
|
|
1037
1046
|
return data;
|
|
@@ -1787,7 +1796,22 @@ function saveMcpImage(result, outputPath) {
|
|
|
1787
1796
|
const imageBlock = content.find(c => c.type === 'image');
|
|
1788
1797
|
if (textBlock) process.stderr.write(`${textBlock.text}\n`);
|
|
1789
1798
|
if (imageBlock) {
|
|
1790
|
-
const
|
|
1799
|
+
const extension = imageBlock.mimeType === 'image/png'
|
|
1800
|
+
? 'png'
|
|
1801
|
+
: imageBlock.mimeType === 'image/webp'
|
|
1802
|
+
? 'webp'
|
|
1803
|
+
: 'jpg';
|
|
1804
|
+
let out = outputPath || `makaron-output-${Date.now()}.${extension}`;
|
|
1805
|
+
if (outputPath) {
|
|
1806
|
+
const requestedExtension = path.extname(outputPath).slice(1).toLowerCase();
|
|
1807
|
+
const compatible = extension === 'jpg'
|
|
1808
|
+
? ['jpg', 'jpeg'].includes(requestedExtension)
|
|
1809
|
+
: requestedExtension === extension;
|
|
1810
|
+
if (!compatible) {
|
|
1811
|
+
out = `${outputPath.slice(0, outputPath.length - path.extname(outputPath).length)}.${extension}`;
|
|
1812
|
+
process.stderr.write(`Output is ${imageBlock.mimeType}; saving as ${out} so bytes and filename agree.\n`);
|
|
1813
|
+
}
|
|
1814
|
+
}
|
|
1791
1815
|
fs.writeFileSync(out, Buffer.from(imageBlock.data, 'base64'));
|
|
1792
1816
|
console.log(out);
|
|
1793
1817
|
return out;
|
|
@@ -1838,8 +1862,10 @@ Commands:
|
|
|
1838
1862
|
credits Show current credit balance
|
|
1839
1863
|
list (ls) List all projects
|
|
1840
1864
|
project media <projectId> --json List timeline media for a project
|
|
1841
|
-
project media add <projectId> --source-url <url>
|
|
1842
|
-
Add an external
|
|
1865
|
+
project media add <projectId> --type image --source-url <url>
|
|
1866
|
+
Add an external image without uploading it
|
|
1867
|
+
project media add <projectId> --type video --source-url <url> --start <n> --end <n>
|
|
1868
|
+
Add an external video range without uploading it
|
|
1843
1869
|
create --image <file> Create project from local image
|
|
1844
1870
|
create --image-url <url> Create project from URL
|
|
1845
1871
|
create --title "name" Create empty project (text-to-image)
|
|
@@ -1851,7 +1877,7 @@ Commands:
|
|
|
1851
1877
|
chat --project <id> --video <file> Attach video to conversation
|
|
1852
1878
|
chat --project <id> --audio <file> Attach song/beat/voice reference
|
|
1853
1879
|
chat --project auto --media-manifest <file> "message"
|
|
1854
|
-
Create, import external
|
|
1880
|
+
Create, import typed external media, and run Agent
|
|
1855
1881
|
chat --project <id> -b "message" Background: submit and print runId
|
|
1856
1882
|
chat --project <id> --stream "msg" Legacy: stream SSE in real-time
|
|
1857
1883
|
chat --project <id> --json "msg" Output structured JSON result
|
|
@@ -1961,11 +1987,12 @@ function printHelp(topic, subtopic) {
|
|
|
1961
1987
|
console.log('Usage: makaron credits [--json]');
|
|
1962
1988
|
} else if (topic === 'project' || topic === 'projects') {
|
|
1963
1989
|
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> --
|
|
1990
|
+
makaron project media add <projectId> --type image --source-url <url> [--description <text>] [--json]
|
|
1991
|
+
makaron project media add <projectId> --type video --source-url <url> --start <n> --end <n> [--description <text>] [--json]
|
|
1992
|
+
makaron project media add <projectId> --input <media.json> [--json]`);
|
|
1966
1993
|
else console.log(`Project commands:
|
|
1967
1994
|
project media <projectId> --json List timeline media for a project
|
|
1968
|
-
project media add <projectId> ... Add external
|
|
1995
|
+
project media add <projectId> ... Add typed external image/video media
|
|
1969
1996
|
`);
|
|
1970
1997
|
} else if (topic === 'abort') {
|
|
1971
1998
|
console.log('Usage: makaron abort <runId>');
|
|
@@ -2005,7 +2032,7 @@ Not sure which built-in skill to use? Start with:
|
|
|
2005
2032
|
composition status <jobId> [--wait] [--json]
|
|
2006
2033
|
`);
|
|
2007
2034
|
} 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"');
|
|
2035
|
+
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
2036
|
} else if (topic === 'analyze') {
|
|
2010
2037
|
console.log('Usage: makaron analyze --video <file|url> ["question"]');
|
|
2011
2038
|
} else if (topic === 'video') {
|
|
@@ -2269,12 +2296,12 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
|
|
|
2269
2296
|
);
|
|
2270
2297
|
importedManifestMedia = imported.media || [];
|
|
2271
2298
|
if (importedManifestMedia.length !== mediaManifest.sourceRanges.length) {
|
|
2272
|
-
process.stderr.write(`❌ Imported ${importedManifestMedia.length}/${mediaManifest.sourceRanges.length}
|
|
2299
|
+
process.stderr.write(`❌ Imported ${importedManifestMedia.length}/${mediaManifest.sourceRanges.length} media item(s); aborting run.\n`);
|
|
2273
2300
|
process.exit(1);
|
|
2274
2301
|
}
|
|
2275
2302
|
uploadedTurnMediaCount += importedManifestMedia.length;
|
|
2276
|
-
uploadedTurnVideoCount += importedManifestMedia.length;
|
|
2277
|
-
process.stderr.write(`📎 Imported ${importedManifestMedia.length} external
|
|
2303
|
+
uploadedTurnVideoCount += importedManifestMedia.filter(item => item.type === 'video').length;
|
|
2304
|
+
process.stderr.write(`📎 Imported ${importedManifestMedia.length} typed external media item(s) from media manifest\n`);
|
|
2278
2305
|
}
|
|
2279
2306
|
// Upload additional images to existing project
|
|
2280
2307
|
if (imageFileList.length > 0 || imageUrlList.length > 0) {
|
|
@@ -2432,9 +2459,12 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
|
|
|
2432
2459
|
...(importedManifestMedia.length ? {
|
|
2433
2460
|
importedMedia: importedManifestMedia.map(item => ({
|
|
2434
2461
|
ref: item.ref,
|
|
2462
|
+
type: item.type,
|
|
2435
2463
|
source_url: item.source_url,
|
|
2436
|
-
|
|
2437
|
-
|
|
2464
|
+
...(item.type === 'video' ? {
|
|
2465
|
+
start_sec: item.start_sec,
|
|
2466
|
+
end_sec: item.end_sec,
|
|
2467
|
+
} : {}),
|
|
2438
2468
|
})),
|
|
2439
2469
|
} : {}),
|
|
2440
2470
|
}));
|
|
@@ -2699,7 +2729,7 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
|
|
|
2699
2729
|
const jsonOutput = args.includes('--json');
|
|
2700
2730
|
if (args[2] === 'add') {
|
|
2701
2731
|
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); }
|
|
2732
|
+
if (!projectId) { console.error('Usage: makaron project media add <projectId> --type <image|video> --source-url <url> [--start <n> --end <n>]'); process.exit(1); }
|
|
2703
2733
|
const readOption = (name) => {
|
|
2704
2734
|
const index = args.indexOf(name);
|
|
2705
2735
|
return index >= 0 ? args[index + 1] : undefined;
|
|
@@ -2707,26 +2737,25 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
|
|
|
2707
2737
|
const inputPath = readOption('--input');
|
|
2708
2738
|
let ranges;
|
|
2709
2739
|
if (inputPath) {
|
|
2710
|
-
const
|
|
2711
|
-
ranges =
|
|
2740
|
+
const normalized = normalizeMediaManifest(readJsonInput(inputPath));
|
|
2741
|
+
ranges = normalized.sourceRanges;
|
|
2712
2742
|
} else {
|
|
2713
2743
|
const sourceUrl = readOption('--source-url');
|
|
2714
|
-
const
|
|
2715
|
-
const
|
|
2716
|
-
|
|
2717
|
-
|
|
2744
|
+
const type = readOption('--type');
|
|
2745
|
+
const start = readOption('--start');
|
|
2746
|
+
const end = readOption('--end');
|
|
2747
|
+
if (!sourceUrl || (type !== 'image' && type !== 'video')) {
|
|
2748
|
+
console.error('Provide --type <image|video> and --source-url <url>, or --input <manifest.json>.');
|
|
2718
2749
|
process.exit(1);
|
|
2719
2750
|
}
|
|
2720
|
-
|
|
2751
|
+
const normalized = normalizeMediaManifest([{
|
|
2721
2752
|
source_url: sourceUrl,
|
|
2722
|
-
|
|
2723
|
-
|
|
2753
|
+
type,
|
|
2754
|
+
...(start !== undefined ? { start } : {}),
|
|
2755
|
+
...(end !== undefined ? { end } : {}),
|
|
2724
2756
|
...(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);
|
|
2757
|
+
}]);
|
|
2758
|
+
ranges = normalized.sourceRanges;
|
|
2730
2759
|
}
|
|
2731
2760
|
await addProjectMediaSourceRanges(baseUrl, headers, projectId, ranges, { json: jsonOutput });
|
|
2732
2761
|
} else {
|
|
@@ -2737,7 +2766,7 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
|
|
|
2737
2766
|
} else {
|
|
2738
2767
|
console.log(`Project commands:
|
|
2739
2768
|
project media <projectId> --json List timeline media for a project
|
|
2740
|
-
project media add <projectId> ... Add external
|
|
2769
|
+
project media add <projectId> ... Add typed external image/video media
|
|
2741
2770
|
`);
|
|
2742
2771
|
}
|
|
2743
2772
|
} else if (command === 'abort') {
|
|
@@ -2775,11 +2804,19 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
|
|
|
2775
2804
|
editArgs.referenceImages.push(imageToArg(args[++i]));
|
|
2776
2805
|
}
|
|
2777
2806
|
else if (args[i] === '--aspect' && args[i + 1]) editArgs.aspectRatio = args[++i];
|
|
2807
|
+
else if (args[i] === '--background' && args[i + 1]) {
|
|
2808
|
+
const background = args[++i];
|
|
2809
|
+
if (!['auto', 'opaque', 'transparent'].includes(background)) {
|
|
2810
|
+
console.error('Invalid --background. Use auto, opaque, or transparent.');
|
|
2811
|
+
process.exit(1);
|
|
2812
|
+
}
|
|
2813
|
+
editArgs.background = background;
|
|
2814
|
+
}
|
|
2778
2815
|
else if (args[i] === '--out' && args[i + 1]) outputPath = args[++i];
|
|
2779
2816
|
else promptParts.push(args[i]);
|
|
2780
2817
|
}
|
|
2781
2818
|
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); }
|
|
2819
|
+
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
2820
|
process.stderr.write('🎨 Generating...\n');
|
|
2784
2821
|
const result = await callMcpTool(baseUrl, headers, 'makaron_edit_image', editArgs);
|
|
2785
2822
|
saveMcpImage(result, outputPath);
|
package/package.json
CHANGED
package/skills/makaron/SKILL.md
CHANGED
|
@@ -180,16 +180,17 @@ npx makaron-cli project media <projectId> --json
|
|
|
180
180
|
|
|
181
181
|
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
182
|
|
|
183
|
-
Publish
|
|
183
|
+
Publish typed external images and video intervals directly into that Media List without uploading the original media:
|
|
184
184
|
|
|
185
185
|
```bash
|
|
186
|
-
npx makaron-cli project media add <projectId> --source-url "https://cdn.example.com/
|
|
187
|
-
npx makaron-cli project media add <projectId> --
|
|
186
|
+
npx makaron-cli project media add <projectId> --type image --source-url "https://cdn.example.com/product.jpg" --description "Hero product image"
|
|
187
|
+
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"
|
|
188
|
+
npx makaron-cli project media add <projectId> --input media.json --json
|
|
188
189
|
```
|
|
189
190
|
|
|
190
|
-
The JSON input may be an array or `{ "clips": [...] }`.
|
|
191
|
+
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
192
|
|
|
192
|
-
For one-call orchestration, use `chat --project auto --media-manifest plan.json`. Makaron validates the manifest, creates the project, imports its
|
|
193
|
+
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
194
|
|
|
194
195
|
```bash
|
|
195
196
|
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 +293,12 @@ npx makaron-cli edit --image photo.jpg --ref style.jpg "match this style"
|
|
|
292
293
|
|
|
293
294
|
# Output to file
|
|
294
295
|
npx makaron-cli edit --image photo.jpg --out result.jpg "make it dramatic"
|
|
296
|
+
|
|
297
|
+
# Strict transparent output through GPT Image 2
|
|
298
|
+
npx makaron-cli edit --image-model openai --background transparent --out sticker.png "a magenta star sticker"
|
|
295
299
|
```
|
|
296
300
|
|
|
297
|
-
Options: `--image`, `--image-model gemini|gemini-lite|qwen|openai|pony|wai`, `--ref <file>` (up to 3), `--aspect <ratio>`, `--out <path
|
|
301
|
+
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
302
|
|
|
299
303
|
### `video` — Standalone video tools (no project timeline)
|
|
300
304
|
|