makaron-cli 0.13.5 → 0.13.6
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 +8 -7
- package/bin/makaron.mjs +39 -44
- package/package.json +1 -1
- package/skills/makaron/SKILL.md +2 -2
package/README.md
CHANGED
|
@@ -156,11 +156,10 @@ External source ranges can be added without uploading either the original video
|
|
|
156
156
|
```bash
|
|
157
157
|
npx makaron-cli project media add <projectId> \
|
|
158
158
|
--source-url "https://cdn.example.com/source.mp4" \
|
|
159
|
-
--start
|
|
160
|
-
--source-uri "dam://project/asset" \
|
|
159
|
+
--start 12.5 --end 19 \
|
|
161
160
|
--description "Racket frame molding"
|
|
162
161
|
|
|
163
|
-
# Batch form: a JSON array or {"
|
|
162
|
+
# Batch form: a JSON array or {"clips": [...]}
|
|
164
163
|
npx makaron-cli project media add <projectId> --input ranges.json --json
|
|
165
164
|
```
|
|
166
165
|
|
|
@@ -181,10 +180,12 @@ npx makaron-cli chat --project auto \
|
|
|
181
180
|
"Make a 30-second 9:16 TikTok with English VO and burned-in captions"
|
|
182
181
|
```
|
|
183
182
|
|
|
184
|
-
The manifest is a JSON array or `{ "title": "...", "
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
183
|
+
The manifest is a JSON array or `{ "title": "...", "clips": [...] }`. Every
|
|
184
|
+
clip contains exactly `source_url`, `start`, `end`, and `description`; the time
|
|
185
|
+
values are seconds and array order is edit order. It is validated before project
|
|
186
|
+
creation and supports up to 20 clips for one Makaron task. Batch planning remains
|
|
187
|
+
the upstream orchestrator's responsibility: convert each plan into one manifest
|
|
188
|
+
and start one independent Makaron task.
|
|
188
189
|
|
|
189
190
|
### Export editable Remotion compositions
|
|
190
191
|
|
package/bin/makaron.mjs
CHANGED
|
@@ -159,51 +159,50 @@ function readJsonInput(filePath) {
|
|
|
159
159
|
const MAX_MEDIA_MANIFEST_RANGES = 20;
|
|
160
160
|
|
|
161
161
|
function normalizeMediaManifest(input) {
|
|
162
|
-
const manifest = Array.isArray(input) ? {
|
|
162
|
+
const manifest = Array.isArray(input) ? { clips: input } : input;
|
|
163
163
|
if (!manifest || typeof manifest !== 'object') {
|
|
164
164
|
throw new Error('Media manifest must be a JSON object or an array of source ranges.');
|
|
165
165
|
}
|
|
166
|
-
const rawRanges = Array.isArray(manifest.
|
|
167
|
-
? manifest.
|
|
168
|
-
: Array.isArray(manifest.
|
|
169
|
-
? manifest.
|
|
170
|
-
:
|
|
166
|
+
const rawRanges = Array.isArray(manifest.clips)
|
|
167
|
+
? manifest.clips
|
|
168
|
+
: Array.isArray(manifest.source_ranges)
|
|
169
|
+
? manifest.source_ranges
|
|
170
|
+
: Array.isArray(manifest.sourceRanges)
|
|
171
|
+
? manifest.sourceRanges
|
|
172
|
+
: null;
|
|
171
173
|
if (!rawRanges?.length) {
|
|
172
|
-
throw new Error('Media manifest must contain a non-empty
|
|
174
|
+
throw new Error('Media manifest must contain a non-empty clips array.');
|
|
173
175
|
}
|
|
174
176
|
if (rawRanges.length > MAX_MEDIA_MANIFEST_RANGES) {
|
|
175
177
|
throw new Error(`Media manifest supports at most ${MAX_MEDIA_MANIFEST_RANGES} source ranges per Makaron task.`);
|
|
176
178
|
}
|
|
177
179
|
|
|
178
180
|
const sourceRanges = rawRanges.map((raw, index) => {
|
|
179
|
-
if (!raw || typeof raw !== 'object') throw new Error(`
|
|
181
|
+
if (!raw || typeof raw !== 'object') throw new Error(`clips[${index}] must be an object.`);
|
|
180
182
|
const sourceUrl = typeof raw.source_url === 'string' ? raw.source_url.trim() : '';
|
|
181
183
|
let parsed;
|
|
182
184
|
try {
|
|
183
185
|
parsed = new URL(sourceUrl);
|
|
184
186
|
} catch {
|
|
185
|
-
throw new Error(`
|
|
187
|
+
throw new Error(`clips[${index}].source_url must be a valid HTTP(S) URL.`);
|
|
186
188
|
}
|
|
187
189
|
if (!['http:', 'https:'].includes(parsed.protocol)) {
|
|
188
|
-
throw new Error(`
|
|
190
|
+
throw new Error(`clips[${index}].source_url must use HTTP or HTTPS.`);
|
|
189
191
|
}
|
|
190
|
-
const
|
|
191
|
-
const
|
|
192
|
-
if (!Number.isFinite(
|
|
193
|
-
throw new Error(`
|
|
192
|
+
const start = Number(raw.start ?? raw.start_sec);
|
|
193
|
+
const end = Number(raw.end ?? raw.end_sec);
|
|
194
|
+
if (!Number.isFinite(start) || start < 0) {
|
|
195
|
+
throw new Error(`clips[${index}].start must be a finite number >= 0.`);
|
|
194
196
|
}
|
|
195
|
-
if (!Number.isFinite(
|
|
196
|
-
throw new Error(`
|
|
197
|
+
if (!Number.isFinite(end) || end <= start) {
|
|
198
|
+
throw new Error(`clips[${index}].end must be greater than start.`);
|
|
197
199
|
}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
if (Number.isFinite(value) && value > 0) range[key] = value;
|
|
205
|
-
}
|
|
206
|
-
return range;
|
|
200
|
+
return {
|
|
201
|
+
source_url: sourceUrl,
|
|
202
|
+
start,
|
|
203
|
+
end,
|
|
204
|
+
description: typeof raw.description === 'string' ? raw.description.trim() : '',
|
|
205
|
+
};
|
|
207
206
|
});
|
|
208
207
|
|
|
209
208
|
return {
|
|
@@ -350,7 +349,7 @@ Options:
|
|
|
350
349
|
--image <file|url> Attach a reference image or screenshot. Repeatable.
|
|
351
350
|
--video <file|url> Attach a video to the project timeline. Repeatable.
|
|
352
351
|
--audio <file|url> Attach a song, beat, or voice reference. MP3/WAV, repeatable.
|
|
353
|
-
--media-manifest <file|-> Import source_url +
|
|
352
|
+
--media-manifest <file|-> Import source_url + start + end + description clips before this run.
|
|
354
353
|
--skill <id|label|name> Use an installed skill or auto-install a matched marketplace skill.
|
|
355
354
|
--background, -b Submit and print a runId.
|
|
356
355
|
--json Output structured JSON.
|
|
@@ -910,7 +909,7 @@ async function addProjectMediaSourceRanges(baseUrl, headers, projectId, ranges,
|
|
|
910
909
|
const res = await fetch(`${baseUrl}/api/projects/${projectId}/media`, {
|
|
911
910
|
method: 'POST',
|
|
912
911
|
headers: { 'Content-Type': 'application/json', ...headers },
|
|
913
|
-
body: JSON.stringify({
|
|
912
|
+
body: JSON.stringify({ clips: ranges }),
|
|
914
913
|
});
|
|
915
914
|
if (!res.ok) { console.error('Project media add failed:', await res.text()); process.exit(1); }
|
|
916
915
|
const data = await res.json();
|
|
@@ -1686,7 +1685,7 @@ Commands:
|
|
|
1686
1685
|
credits Show current credit balance
|
|
1687
1686
|
list (ls) List all projects
|
|
1688
1687
|
project media <projectId> --json List timeline media for a project
|
|
1689
|
-
project media add <projectId> --source-url <url> --start
|
|
1688
|
+
project media add <projectId> --source-url <url> --start <n> --end <n>
|
|
1690
1689
|
Add an external source range without uploading video
|
|
1691
1690
|
create --image <file> Create project from local image
|
|
1692
1691
|
create --image-url <url> Create project from URL
|
|
@@ -1806,11 +1805,11 @@ function printHelp(topic, subtopic) {
|
|
|
1806
1805
|
console.log('Usage: makaron credits [--json]');
|
|
1807
1806
|
} else if (topic === 'project' || topic === 'projects') {
|
|
1808
1807
|
if (subtopic === 'media') console.log(`Usage: makaron project media <projectId> [--json]
|
|
1809
|
-
makaron project media add <projectId> --source-url <url> --start
|
|
1808
|
+
makaron project media add <projectId> --source-url <url> --start <n> --end <n> [--description <text>] [--json]
|
|
1810
1809
|
makaron project media add <projectId> --input <ranges.json> [--json]`);
|
|
1811
1810
|
else console.log(`Project commands:
|
|
1812
1811
|
project media <projectId> --json List timeline media for a project
|
|
1813
|
-
project media add <projectId> ... Add external source_url +
|
|
1812
|
+
project media add <projectId> ... Add external source_url + start + end media
|
|
1814
1813
|
`);
|
|
1815
1814
|
} else if (topic === 'abort') {
|
|
1816
1815
|
console.log('Usage: makaron abort <runId>');
|
|
@@ -2496,7 +2495,7 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
|
|
|
2496
2495
|
const jsonOutput = args.includes('--json');
|
|
2497
2496
|
if (args[2] === 'add') {
|
|
2498
2497
|
const projectId = args[3];
|
|
2499
|
-
if (!projectId) { console.error('Usage: makaron project media add <projectId> --source-url <url> --start
|
|
2498
|
+
if (!projectId) { console.error('Usage: makaron project media add <projectId> --source-url <url> --start <n> --end <n>'); process.exit(1); }
|
|
2500
2499
|
const readOption = (name) => {
|
|
2501
2500
|
const index = args.indexOf(name);
|
|
2502
2501
|
return index >= 0 ? args[index + 1] : undefined;
|
|
@@ -2505,28 +2504,24 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
|
|
|
2505
2504
|
let ranges;
|
|
2506
2505
|
if (inputPath) {
|
|
2507
2506
|
const input = readJsonInput(inputPath);
|
|
2508
|
-
ranges = Array.isArray(input) ? input : input.source_ranges || input.sourceRanges;
|
|
2507
|
+
ranges = Array.isArray(input) ? input : input.clips || input.source_ranges || input.sourceRanges;
|
|
2509
2508
|
} else {
|
|
2510
2509
|
const sourceUrl = readOption('--source-url');
|
|
2511
|
-
const
|
|
2512
|
-
const
|
|
2513
|
-
if (!sourceUrl || !Number.isFinite(
|
|
2514
|
-
console.error('Provide --source-url, --start
|
|
2510
|
+
const start = Number(readOption('--start') ?? readOption('--start-sec'));
|
|
2511
|
+
const end = Number(readOption('--end') ?? readOption('--end-sec'));
|
|
2512
|
+
if (!sourceUrl || !Number.isFinite(start) || !Number.isFinite(end)) {
|
|
2513
|
+
console.error('Provide --source-url, --start, and --end, or --input <manifest.json>.');
|
|
2515
2514
|
process.exit(1);
|
|
2516
2515
|
}
|
|
2517
2516
|
ranges = [{
|
|
2518
2517
|
source_url: sourceUrl,
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
...(readOption('--source-uri') ? { source_uri: readOption('--source-uri') } : {}),
|
|
2522
|
-
...(readOption('--project-id') ? { project_id: readOption('--project-id') } : {}),
|
|
2523
|
-
...(readOption('--asset-id') ? { asset_id: readOption('--asset-id') } : {}),
|
|
2524
|
-
...(readOption('--file-name') ? { file_name: readOption('--file-name') } : {}),
|
|
2518
|
+
start,
|
|
2519
|
+
end,
|
|
2525
2520
|
...(readOption('--description') ? { description: readOption('--description') } : {}),
|
|
2526
2521
|
}];
|
|
2527
2522
|
}
|
|
2528
2523
|
if (!Array.isArray(ranges) || !ranges.length) {
|
|
2529
|
-
console.error('Input must contain a non-empty
|
|
2524
|
+
console.error('Input must contain a non-empty clips array.');
|
|
2530
2525
|
process.exit(1);
|
|
2531
2526
|
}
|
|
2532
2527
|
await addProjectMediaSourceRanges(baseUrl, headers, projectId, ranges, { json: jsonOutput });
|
|
@@ -2538,7 +2533,7 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
|
|
|
2538
2533
|
} else {
|
|
2539
2534
|
console.log(`Project commands:
|
|
2540
2535
|
project media <projectId> --json List timeline media for a project
|
|
2541
|
-
project media add <projectId> ... Add external source_url +
|
|
2536
|
+
project media add <projectId> ... Add external source_url + start + end media
|
|
2542
2537
|
`);
|
|
2543
2538
|
}
|
|
2544
2539
|
} else if (command === 'abort') {
|
package/package.json
CHANGED
package/skills/makaron/SKILL.md
CHANGED
|
@@ -152,11 +152,11 @@ This is project-scoped. `responses get <runId> --pick output` only returns artif
|
|
|
152
152
|
Publish an external video interval directly into that Media List without uploading the original or a derivative MP4:
|
|
153
153
|
|
|
154
154
|
```bash
|
|
155
|
-
npx makaron-cli project media add <projectId> --source-url "https://cdn.example.com/source.mp4" --start
|
|
155
|
+
npx makaron-cli project media add <projectId> --source-url "https://cdn.example.com/source.mp4" --start 12.5 --end 19 --description "Racket frame molding"
|
|
156
156
|
npx makaron-cli project media add <projectId> --input ranges.json --json
|
|
157
157
|
```
|
|
158
158
|
|
|
159
|
-
The JSON input may be an array or `{ "
|
|
159
|
+
The JSON input may be an array or `{ "clips": [...] }`. Each clip has exactly `source_url + 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.
|
|
160
160
|
|
|
161
161
|
For one-call orchestration, use `chat --project auto --media-manifest plan.json`. Makaron validates the manifest, creates the project, imports its ranges, 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.
|
|
162
162
|
|