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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "makaron-cli",
3
- "version": "0.13.5",
3
+ "version": "0.13.6",
4
4
  "description": "Give Claude Code a creative agent. Pass complete creative requests and source media to Makaron Chat.",
5
5
  "author": {
6
6
  "name": "Versa AI",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "makaron-cli",
3
- "version": "0.13.5",
3
+ "version": "0.13.6",
4
4
  "description": "Give Codex a creative agent. Pass complete creative requests and source media to Makaron Chat.",
5
5
  "author": {
6
6
  "name": "Versa AI",
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-sec 12.5 --end-sec 19 \
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 {"source_ranges": [...]}
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": "...", "source_ranges": [...] }`.
185
- It is validated before project creation and supports up to 20 ranges for one
186
- Makaron task. Batch planning remains the upstream orchestrator's responsibility:
187
- convert each plan into one manifest and start one independent Makaron task.
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) ? { source_ranges: input } : 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.source_ranges)
167
- ? manifest.source_ranges
168
- : Array.isArray(manifest.sourceRanges)
169
- ? manifest.sourceRanges
170
- : null;
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 source_ranges array.');
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(`source_ranges[${index}] must be an object.`);
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(`source_ranges[${index}].source_url must be a valid HTTP(S) URL.`);
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(`source_ranges[${index}].source_url must use HTTP or HTTPS.`);
190
+ throw new Error(`clips[${index}].source_url must use HTTP or HTTPS.`);
189
191
  }
190
- const startSec = Number(raw.start_sec);
191
- const endSec = Number(raw.end_sec);
192
- if (!Number.isFinite(startSec) || startSec < 0) {
193
- throw new Error(`source_ranges[${index}].start_sec must be a finite number >= 0.`);
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(endSec) || endSec <= startSec) {
196
- throw new Error(`source_ranges[${index}].end_sec must be greater than start_sec.`);
197
+ if (!Number.isFinite(end) || end <= start) {
198
+ throw new Error(`clips[${index}].end must be greater than start.`);
197
199
  }
198
- const range = { source_url: sourceUrl, start_sec: startSec, end_sec: endSec };
199
- for (const key of ['source_uri', 'project_id', 'asset_id', 'file_name', 'description']) {
200
- if (typeof raw[key] === 'string' && raw[key].trim()) range[key] = raw[key].trim();
201
- }
202
- for (const key of ['width', 'height']) {
203
- const value = Number(raw[key]);
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 + start_sec + end_sec ranges before this run.
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({ source_ranges: ranges }),
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-sec <n> --end-sec <n>
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-sec <n> --end-sec <n> [--source-uri <uri>] [--description <text>] [--json]
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 + start_sec + end_sec media
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-sec <n> --end-sec <n>'); process.exit(1); }
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 startSec = Number(readOption('--start-sec'));
2512
- const endSec = Number(readOption('--end-sec'));
2513
- if (!sourceUrl || !Number.isFinite(startSec) || !Number.isFinite(endSec)) {
2514
- console.error('Provide --source-url, --start-sec, and --end-sec, or --input <ranges.json>.');
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
- start_sec: startSec,
2520
- end_sec: endSec,
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 source_ranges array.');
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 + start_sec + end_sec media
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "makaron-cli",
3
- "version": "0.13.5",
3
+ "version": "0.13.6",
4
4
  "description": "Talk to Makaron Agent from the terminal — create projects, edit images, generate videos",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -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-sec 12.5 --end-sec 19 --source-uri "dam://project/asset" --description "Racket frame molding"
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 `{ "source_ranges": [...] }`. Each item uses `source_url + start_sec + end_sec`; optional `source_uri`, `project_id`, and `asset_id` preserve durable source identity. 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.
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